Please let me also get on the rounded corner hype train! I don't know what the fuzz is about but I want a piece!
Mouseover the variables to read what they do.
Triangle: Rounded whatever 👙 (variation)
Square: Rounded whatever 👙 (variation)
Pentagon: Rounded whatever 👙 (variation)
Etc...
Log in to post a comment.
const edges = 4; //min=3 max=10 step=1 Start with a regular polygon const rotateFirstPI = .25; //min=0 max=2 step=.01 Then rotate that this amount of a full rotation const width = 150; //min=10 max=200 step=1 Then strecht that result to fit in this width const height = 75; //min=10 max=200 step=1 Then strecht that result to fit in this height const cornerRadius = 10; //min=0 max=50 step=1 The radius of the first (or all) corner(s). Note that there's no protection from specifying a value that's too large const repeatCornerRadius = 1; //min=0 max=4 step=1 (No; use values specified below, Yes; use cornerRadius for every corner and ignore variables below, Partailly; repeat cornerRadius and cr2 alternating, Partailly; repeat cornerRadius and cr2 and cr3 alternating, Partailly; repeat cornerRadius and cr2 and cr3 and cr4 alternating) const cr2 = 0; //min=0 max=50 step=1 const cr3 = 0; //min=0 max=50 step=1 const cr4 = 0; //min=0 max=50 step=1 const cr5 = 0; //min=0 max=50 step=1 const cr6 = 0; //min=0 max=50 step=1 const cr7 = 0; //min=0 max=50 step=1 const cr8 = 0; //min=0 max=50 step=1 const cr9 = 0; //min=0 max=50 step=1 const cr10 = 0; //min=0 max=50 step=1 // You can find the Turtle API reference here: https://turtletoy.net/syntax Canvas.setpenopacity(.7); // Global code will be evaluated once. const turtle = new Turtle(); // The walk function will be called until it returns false. function walk(i) { const radii = ((repeat) => { const all = [cornerRadius, cr2, cr3, cr4, cr5, cr6, cr7, cr8, cr9, cr10]; switch(repeat) { case 0: return all; case 1: return [cornerRadius]; default: return Array.from({length: 10}).map((v,i)=> all[i%repeat]); } })(repeatCornerRadius); const pts = getRoundedCornerPolygon(width, height, edges, rotateFirstPI, ...radii); drawPath(turtle, pts); return false; } function drawPath(turtle, pts) { [pts].map(v => v.concat([v[0]])).pop().forEach((pt, i) => turtle[(i == 0? 'jump': 'goto')](pt)); } function getRoundedCornerPolygon(width, height, edges, rotation, ...cornerRadiuses) { const pointAngle = (pt) => Math.PI - Math.atan2(...pt); const cornerRadii = Array.from({length: edges}).map((v, i) => cornerRadiuses[i] === undefined? (i == 0? 0: cornerRadiuses[0]): cornerRadiuses[i]); const pts = getPolygon(width, height, edges, rotation); if(width == 0 || height == 0 || edges < 3) return pts; const vectorsFromPoints = pts.map( (v, i, a) => [ [sub2(a[(i - 1 + a.length)%a.length], v)].map(v => [v, pointAngle(v)]).pop(), [sub2(a[(i + 1)%a.length], v)].map(v => [v, pointAngle(v)]).pop() ] ).map(vfp => [vfp[0][0], vfp[1][0], vfp[0][1] - vfp[1][1] + (vfp[1][1] > vfp[0][1]? 2*Math.PI: 0)]); const lengths = vectorsFromPoints.map(v => len2(v[0])); const cornerSplittingVectors = vectorsFromPoints.map( (vfp, i) => [ //vector from corner to center circle scale2(add2(norm2(vfp[0]), norm2(vfp[1])), cornerRadii[i] / (Math.sin(vfp[2]))), //vector from corner to tangent of circle on way to previous point scale2(vfp[0], (cornerRadii[i] / Math.tan(vfp[2]/2)) / lengths[i]), //vector from corner to tangent of circle on way to next point scale2(vfp[1], (cornerRadii[i] / Math.tan(vfp[2]/2)) / lengths[(i+1)%lengths.length]), ] ); const cornerCircleData = cornerSplittingVectors.map((csv, i) => [add2(pts[i], csv[0])].map(circleCenter => [ circleCenter, pointAngle(sub2(add2(pts[i], csv[1]), circleCenter)), pointAngle(sub2(add2(pts[i], csv[2]), circleCenter)) ]).pop(), ).map(cd => [cd[0], cd[1] - (cd[2] < cd[1]? 2*Math.PI:0), cd[2]]); const lerp1 = (a, b, t) => a + (b-a)*t; const corners = cornerCircleData.map((ccd, j) => { return [Math.max(1, (cornerRadii[j] * 2 * (ccd[2] - ccd[1])) / Math.PI | 0)].map(steps => Array.from({length: steps + 1}) .map((v, i, a, f = lerp1(ccd[1], ccd[2], i / steps)) => [ cornerRadii[j] * Math.sin(f), cornerRadii[j] * -Math.cos(f) ]) ).pop().map(pt => add2(ccd[0], pt)) }); return corners.flatMap(v => v) } function getPolygon(width, height, edges, rotation = 0) { const pts = getRegularPolygonPoints(Math.max(width, height), edges, rotation * 2 * Math.PI); const wh = pts.reduce((a, c) => [[Math.min(a[0][0], c[0]), Math.max(a[0][1], c[0])], [Math.min(a[1][0], c[1]), Math.max(a[1][1], c[1])]], [[0,0],[0,0]]); return pts.map(pt => mul2(pt, [width / (wh[0][1] - wh[0][0]), height / (wh[1][1] - wh[1][0])])); } //////////////////////////////////////////////////////////////// // 2D Vector Math utility code - Created by several Turtletoy users //////////////////////////////////////////////////////////////// function norm2(a) { return scale2(a, 1/len2(a)); } function add2(a, b) { return [a[0]+b[0], a[1]+b[1]]; } function sub2(a, b) { return [a[0]-b[0], a[1]-b[1]]; } function mul2(a, b) { return [a[0]*b[0], a[1]*b[1]]; } function scale2(a, s) { return [a[0]*s,a[1]*s]; } function lerp2(a,b,t) { return [a[0]*(1-t) + b[0]*t, a[1]*(1-t) + b[1]*t]; } function lenSq2(a) { return a[0]**2+a[1]**2; } function len2(a) { return Math.sqrt(lenSq2(a)); } /* function rot2(a) { return [Math.cos(a), -Math.sin(a), Math.sin(a), Math.cos(a)]; } function trans2(m, a) { return [m[0]*a[0]+m[2]*a[1], m[1]*a[0]+m[3]*a[1]]; } //Matrix(2x1) x Matrix(2x2) function dist2(a,b) { return Math.hypot(...sub2(a,b)); } function dot2(a,b) { return a[0]*b[0]+a[1]*b[1]; } function cross2(a,b) { return a[0]*b[1] - a[1]*b[0]; } function multiply2(a2x2, a) { return [(a[0]*a2x2[0])+(a[1]*a2x2[1]),(a[0]*a2x2[2])+(a[1]*a2x2[3])]; } //Matrix(2x2) x Matrix(1x2) */ function getRegularPolygonPoints(r, steps = null, rotatedStart = 0) { return getRegularPolygonPointsElipse(r, r, steps, rotatedStart); } function getRegularPolygonPointsElipse(rx, ry, steps = null, rotatedStart = 0) { return Array.from({length: steps === null? Math.max(12, 2 * Math.PI * Math.max(rx, ry)): steps}) .map( (v, i, a, f = rotatedStart/2 + Math.PI * 2 * i / a.length) => [rx * Math.sin(f), ry * -Math.cos(f)] ); }