A spiral evolving into infinity.
Log in to post a comment.
let numPoints = 150; // min=20, max=300, step=5, Total number of points in the spiral let a = 0; // min=0, max=50, step=0.1, Starting radius let b = 0.28; // min=0, max=3, step=0.001, Controls the tightness of the spiral let s = 1.88; // min=0, max=3, step=0.001, Controls the spacing of the spiral // You can find the Turtle API reference here: https://turtletoy.net/syntax Canvas.setpenopacity(0.12); // Global code will be evaluated once. const turtle = new Turtle(); function drawRandomCubicHermiteSpline(pStart, pEnd, numPoints, aScale) { // Generates a set of random control points between pStart and pEnd function generateRandomControlPoints(pStart, pEnd, numPoints) { let points = [pStart]; let dx = pEnd.x - pStart.x; let dy = pEnd.y - pStart.y; let dTotal = Math.sqrt(dx * dx + dy * dy); let normalDirection = { x: -dy / dTotal, y: dx / dTotal }; for (let i = 1; i < numPoints - 1; i++) { let t = i / (numPoints - 1); let p = { x: pStart.x + dx * t, y: pStart.y + dy * t }; let f = Math.random() * 2 - 1; let offsetMagnitude = Math.sin(t * Math.PI * f) * (Math.random() * dTotal * aScale); p.x += offsetMagnitude * normalDirection.x; p.y += offsetMagnitude * normalDirection.y; points.push(p); } points.push(pEnd); return points; } // Calculates tangent using two points. function calculateTangent(p0, p1) { return { x: p1.x - p0.x, y: p1.y - p0.y }; } // Calculates tangents for each control point function calculateTangents(points) { let tangents = []; for (let i = 0; i < points.length; i++) { if (i == 0) { tangents.push(calculateTangent(points[i], points[i + 1])); } else if (i == points.length - 1) { tangents.push(calculateTangent(points[i - 1], points[i])); } else { let tangent = calculateTangent(points[i - 1], points[i + 1]); tangents.push({ x: tangent.x / 2, y: tangent.y / 2 }); } } return tangents; } // Computes a point on the Cubic Hermite spline function hermiteInterpolate(p0, p1, t0, t1, t) { let h00 = (2 * t ** 3) - (3 * t ** 2) + 1; let h10 = (t ** 3) - (2 * t ** 2) + t; let h01 = (-2 * t ** 3) + (3 * t ** 2); let h11 = (t ** 3) - (t ** 2); return { x: h00 * p0.x + h10 * t0.x + h01 * p1.x + h11 * t1.x, y: h00 * p0.y + h10 * t0.y + h01 * p1.y + h11 * t1.y }; } // Generate control points let controlPoints = generateRandomControlPoints(pStart, pEnd, numPoints); // Calculate tangents for control points let tangents = calculateTangents(controlPoints); // Draw the spline by interpolating between each pair of points for (let i = 0; i < controlPoints.length - 1; i++) { let p0 = controlPoints[i]; let p1 = controlPoints[i + 1]; let t0 = tangents[i]; let t1 = tangents[i + 1]; turtle.penup(); turtle.goto(p0.x, p0.y); turtle.pendown(); for (let t = 0; t <= 1; t += 0.1) { // Smaller step for a smoother curve let point = hermiteInterpolate(p0, p1, t0, t1, t); turtle.goto(point.x, point.y); } turtle.penup(); } } // generate a spiral path function generateSpiralPoints(numPoints, a, b, s = 0.1, yOffset = 0) { let points = []; for (let i = 0; i < numPoints; i++) { // Angle increases linearly with each point let theta = i * s; // Adjust the s multiplier to change spacing between points // Radius increases with theta to create the spiral let r = a + b * theta; // 'a' is the starting radius, 'b' controls how tightly the spiral winds // Convert polar coordinates (r, theta) to Cartesian coordinates (x, y) let x = r * Math.cos(theta); let y = r * Math.sin(theta) + yOffset; points.push({ x, y }); } return points; } let spiralPoints = generateSpiralPoints(numPoints, a, b, s, -12); // draw the figure below for (let j = 0; j < 16; j++) { for (let i = 0; i < j * 2 + 1; i++) { let x = -90 + j * 12; drawRandomCubicHermiteSpline({ x: x, y: 75 }, { x: x, y: 95 }, j * 2.5, 0.2); } } // The walk function will be called until it returns false. function walk(i) { if (i < spiralPoints.length - 1) { // Use the current and next point in the spiral as start and end points for the spline let pStart = spiralPoints[i]; let pEnd = spiralPoints[i + 1]; let nCurves = i * 0.4; // Call the function to draw the spline segment between these points for (let k = 0; k < nCurves; k++) { drawRandomCubicHermiteSpline(pStart, pEnd, i * 0.05, 0.1 * i / spiralPoints.length); } return true; // Continue walking } return false; // Stop walking once we've processed all points }