Pezones
All the lines are beautiful
Log in to post a comment.
Canvas.setpenopacity(1);
const spacing = 100; // min=1, max=200, step=1
const brustRadius = 8; // min=5, max=100, step=1
const areolaRadius = 4; // min=1, max=100, step=1
const nippleRadius = 1; // min=1, max=100, step=1
const height = 0; // min=-80, max=80, step=1
const droop = 1; // min=0, max=100, step=1
const areolaNoise = 0; // min=0, max=10, step=0.1
const areolaFreq = 8; // min=1, max=60, step=1
const nippleNoise = 0; // min=0, max=10, step=0.1
const nippleFreq = 8; // min=1, max=60, step=1
const clampedAreola = Math.min(areolaRadius, brustRadius);
const clampedNipple = Math.min(nippleRadius, clampedAreola);
const maxAreolaDisplace = brustRadius - clampedAreola;
const maxNippleDisplace = clampedAreola - clampedNipple;
function makeRng(seed) {
let s = seed >>> 0;
return function() {
s += 0x6D2B79F5;
let t = Math.imul(s ^ (s >>> 15), 1 | s);
t ^= t + Math.imul(t ^ (t >>> 7), 61 | t);
return ((t ^ (t >>> 14)) >>> 0) / 4294967296;
};
}
function buildNoiseMap(count, freq, amplitude, rng) {
if (amplitude === 0) return new Array(count).fill(0);
const anchors = [];
for (let i = 0; i < freq; i++) {
anchors.push((rng() - 0.5) * 2 * amplitude);
}
return Array.from({ length: count }, (_, i) => {
const t = (i / count) * freq;
const i0 = Math.floor(t) % freq;
const i1 = (i0 + 1) % freq;
const f = t - Math.floor(t);
const mu = (1 - Math.cos(f * Math.PI)) / 2;
return anchors[i0] * (1 - mu) + anchors[i1] * mu;
});
}
function applyNoise(points, amplitude, freq, maxOutward, rng) {
if (amplitude === 0) return points;
const cx = points.reduce((s, p) => s + p.x, 0) / points.length;
const cy = points.reduce((s, p) => s + p.y, 0) / points.length;
const noiseMap = buildNoiseMap(points.length, freq, amplitude, rng);
return points.map((p, i) => {
const dx = p.x - cx;
const dy = p.y - cy;
const len = Math.sqrt(dx * dx + dy * dy) || 1;
const offset = Math.min(noiseMap[i], maxOutward);
return {
x: p.x + (dx / len) * offset,
y: p.y + (dy / len) * offset
};
});
}
function drawPoints(t, points) {
t.penup();
t.goto(points[0].x, points[0].y);
t.pendown();
for (let i = 1; i < points.length; i++) {
t.goto(points[i].x, points[i].y);
}
}
function buildCirclePoints(cx, cy, r) {
const pts = [];
const steps = 180;
for (let i = 0; i <= steps; i++) {
const angle = -Math.PI / 2 + (i / steps) * 2 * Math.PI;
pts.push({ x: cx + r * Math.cos(angle), y: cy + r * Math.sin(angle) });
}
return pts;
}
function buildSemiPoints(cx, arcCY, r) {
const pts = [];
const steps = 90;
for (let i = 0; i <= steps; i++) {
const angle = Math.PI - (i / steps) * Math.PI;
pts.push({ x: cx + r * Math.cos(angle), y: arcCY + r * Math.sin(angle) });
}
return pts;
}
function drawCircle(cx, cy, r, amplitude, freq, maxOutward, rng) {
const t = new Turtle();
drawPoints(t, applyNoise(buildCirclePoints(cx, cy, r), amplitude, freq, maxOutward, rng));
}
function drawBreast(cx, cy) {
const arcCY = cy + height;
const leftX = cx - brustRadius;
const rightX = cx + brustRadius;
if (droop === 0) {
const t = new Turtle();
drawPoints(t, buildCirclePoints(cx, arcCY, brustRadius));
return;
}
const t = new Turtle();
const leftLine = [
{ x: leftX, y: arcCY },
{ x: leftX, y: arcCY - droop * 0.33 },
{ x: leftX, y: arcCY - droop * 0.66 },
{ x: leftX, y: arcCY - droop }
];
drawPoints(t, leftLine);
const rightLine = [
{ x: rightX, y: arcCY },
{ x: rightX, y: arcCY - droop * 0.33 },
{ x: rightX, y: arcCY - droop * 0.66 },
{ x: rightX, y: arcCY - droop }
];
drawPoints(t, rightLine);
drawPoints(t, buildSemiPoints(cx, arcCY, brustRadius));
}
const groupWidth = spacing + brustRadius * 4;
const offsetX = -groupWidth / 2 + brustRadius;
const cy = 0;
drawBreast(offsetX, cy);
drawBreast(offsetX + spacing + brustRadius * 2, cy);
const leftCX = offsetX;
const rightCX = offsetX + spacing + brustRadius * 2;
const rngAreola = makeRng(1);
const rngNipple = makeRng(2);
drawCircle(leftCX, cy + height, clampedAreola, areolaNoise, areolaFreq, maxAreolaDisplace, rngAreola);
drawCircle(rightCX, cy + height, clampedAreola, areolaNoise, areolaFreq, maxAreolaDisplace, rngAreola);
drawCircle(leftCX, cy + height, clampedNipple, nippleNoise, nippleFreq, maxNippleDisplace, rngNipple);
drawCircle(rightCX, cy + height, clampedNipple, nippleNoise, nippleFreq, maxNippleDisplace, rngNipple);