I want to generate a sunburst to use with a laser-cutting service, like below:
This has a couple of important features:
- It’s a single path, for the laser to use
- The rays on the sun can intersect a bounding box, including the corners
- This will produce two interlocking parts (e.g. for printmaking, these can be inked separately, and combined)
The code is below – this works with Paper.js:
var postyle = { fillColor:'grey', strokeColor: 'black'} const size = 200; const rect = [0, 0, [ size, size]]; const ratio = 0.25; const radius = size * ratio; const spokes = 48; const pi = 3.14; const center = [0, 0] var path = new paper.Path(); path.strokeColor = "#000"; path.closed = true; function ip(a) { return [ radius * Math.cos(a), radius * Math.sin(a) ]; } function intersect(x1, y1, x2, y2, mixX, minY, maxX, maxY) { var point = rectangleIntersect(maxX - x1, maxY - y1, x2 - x1, y2 - y1); return point && { x: point.x + x1, y: point.y + y1 }; } function rectangleIntersect(w, h, x, y) { var sx = x > 0 ? 1 : -1; var sy = y > 0 ? 1 : -1; x *= sx; y *= sy; if (x < w && y < h) return null; var m = x * h; var n = y * w; if (m < n) w = m / y; if (m > n) h = n / x; return [ Math.round( sx * w ), Math.round(sy * h ) ]; } function outer(a) { return rectangleIntersect( size, size, 100000 * Math.cos(a) + size/2, 100000 * Math.sin(a) + size/2, ); } function maybeCorner(p1, p2, a1) { const corners = [ [1 * size, -1 * size], [1 * size, 1 * size], [-1 * size, 1 * size], [-1 * size, -1 * size], ]; if (p1[0] != p2[0] && p1[1] != p2[1]) { const idx = Math.round(2*a1/pi) % 4; return corners[idx]; } } for (let i = 0; i < spokes; i++) { const a1 = pi / spokes * (2 * i); const a2 = pi / spokes * (2 * i + 1); const inner1 = ip(a1); const inner2 = ip(a2); const outer1 = outer(a1); const outer2 = outer(a2); const points = [ inner1, outer1, maybeCorner(outer1, outer2, a1), outer2, inner2].filter( (p) => !!p ); points.map( ([x, y]) => { path.add(new paper.Point(x + center[0], y + center[1])); }); }