Last active
December 5, 2025 10:21
-
-
Save Hermann-SW/374019946acdb2d9399f7619247ae4c3 to your computer and use it in GitHub Desktop.
Apollonian circles playground
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| "use strict" | |
| const jscad = require('@jscad/modeling') | |
| const math = require('mathjs') | |
| const { extrudeLinear } = jscad.extrusions | |
| const { hullChain } = jscad.hulls | |
| const { circle } = jscad.primitives | |
| const { vectorText } = jscad.text | |
| const { scale, translate } = jscad.transforms | |
| const th=1 | |
| const sc=0.03 | |
| const seg=360 | |
| const f=10 | |
| function C(c,notext=false) { | |
| return [ | |
| notext?[]:buildFlatText([f*(c[0]-sc*15/c[2]),f*c[1]], ""+c[2], th, f*sc/c[2]), | |
| circle({segments: seg, center: [f*c[0],f*c[1]], radius: f/Math.abs(c[2])}) | |
| ] | |
| } | |
| const issquare = (n) => { var i=isqrt(n); return n === i*i } | |
| const isqrt = (n) => { return Math.floor(Math.sqrt(n)) } | |
| function nxt(A) { | |
| var a,b,c | |
| [a,b,c]=[A[0][2],A[1][2],A[2][2]] | |
| console.assert(issquare(a*b+a*c+b*c)) | |
| return a+b+c+2*isqrt(a*b+a*c+b*c) | |
| } | |
| function cent(A,k4) { | |
| var a=r1+r2 | |
| var b=r1+r3 | |
| var c=r2+r3 | |
| var k1=A[0][2] | |
| var k2=A[1][2] | |
| var k3=A[2][2] | |
| var r1=1/k1 | |
| var r2=1/k2 | |
| var r3=1/k3 | |
| var z1 = math.complex(A[0][0],A[0][1]) | |
| var z2 = math.complex(A[1][0],A[1][1]) | |
| var z3 = math.complex(A[2][0],A[2][1]) | |
| // z4=(k1*z1+k2*z2+k3*z3+2*sqrt(k1*k2*z1*z2+k2*k3*z2*z3+k3*k1*z3*z1))/k4 | |
| var z4 = | |
| math.multiply( | |
| math.add( | |
| math.add( | |
| math.multiply(k1,z1), | |
| math.add( | |
| math.multiply(k2,z2), | |
| math.multiply(k3,z3) | |
| ) | |
| ), | |
| math.multiply(2, | |
| math.sqrt( | |
| math.add( | |
| math.add( | |
| math.multiply( | |
| k1*k2, | |
| math.multiply(z1,z2) | |
| ), | |
| math.multiply(k2*k3, | |
| math.multiply(z2,z3) | |
| ) | |
| ), | |
| math.multiply(k3*k1, | |
| math.multiply(z3,z1) | |
| ) | |
| ) | |
| ) | |
| ) | |
| ), | |
| 1/k4 | |
| ) | |
| return [z4.re, z4.im] | |
| } | |
| function r(A) { | |
| var n=nxt(A) | |
| var c=cent(A,n).concat([n]) | |
| return C(c) | |
| } | |
| function main() { | |
| var A=[[0,0,-1],[0,1/2,2],[0,-1/2,2],[2/3,0,3]] | |
| return [ | |
| C(A[0], true), buildFlatText([-5,f], "-1", th, f*sc), | |
| C(A[1]), | |
| C(A[2]), | |
| C(A[3]), | |
| r([...A.slice(1,4), ...A.slice(-0)]), | |
| // r([...A.slice(0,2), ...A.slice(-1)]), | |
| ] | |
| } | |
| const buildFlatText = (pos, message, characterLineWidth, s) => { | |
| if (message === undefined || message.length === 0) return [] | |
| const lineSegments = [] | |
| vectorText({ x: 0, y: 0, input: message }).forEach((segmentPoints) => { | |
| const corners = segmentPoints.map((point) => | |
| translate(point, circle({ radius: characterLineWidth / 2}))) | |
| lineSegments.push(hullChain(corners)) | |
| }) | |
| return translate(pos, scale([s,s,s],extrudeLinear({ height: 0.00001 }, lineSegments))) | |
| } | |
| module.exports = { main } |
Author
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Initial version.
jscad.app share link:
https://jscad.app/#https://gist.githubusercontent.com/Hermann-SW/374019946acdb2d9399f7619247ae4c3/raw/fa33731936b415cebc6a25968d7ff75f1aa36b82/apollonian_circles.jscad