comment:
trappedPoint.Index is the base circle index: 0 (center), 1-N (in ring) trappedPoint.Delta is the level: 0 - Steps-1
See the paper: "Evolution of Math into Art via Mobius Transformations" by Anne M. Burns, Department of Mathematics, Long Island University. http://myweb.cwpost.liu.edu/aburns/
Also, see pages 88-89 in the book: "Indra's Pearls, The Vision of Felix Klein" by David Mumford, Caroline Series, David Wright. http://klein.math.okstate.edu/IndrasPearls/
global:
Complex ShowCenter[] = LC1,LC2,LC3,LC4,LC5,LC6,LC7,LC8,LC9,LC10,LC11,LC12,LC13,LC14,LC15,LC16 Complex ShowRing[] = LR1,LR2,LR3,LR4,LR5,LR6,LR7,LR8,LR9,LR10,LR11,LR12,LR13,LR14,LR15,LR16 AbsV = Sqrt(AbsU^2 - 1) u = AbsU Cis(DegreeToRadian(ArgU)) v = AbsV Cis(DegreeToRadian(ArgV)) Mobius UnitCircleGroup = Mobius(u, v, Conj(v), Conj(u))
totalGen = 1 + N + 52 Mobius m[totalGen]
' ' Given N, find radius R such that N circles with radius R can be ' placed along the inside of the unit circle, each tangent to the ' unit circle and each of its two adjacent neighbors. ' r = 1/(1+1/Sin(Math.PI/N))
step = 2Math.PI/N ang = IIf(Shift, step/2, 0) ' ' Center generator (index 0) ' m[0] = Mobius(1-2r, 0, 0, 1) ' ' Ring generators (indices 1..N) ' for (i = 1, i <= N, i += 1) { rotate = Cis(ang) m[i] = Mobius.Multiply( \ Mobius(rrotate, (1-r)rotate, 0, 1), \ UnitCircleGroup \ ) ang += step } ' ' Custom generators (keep if needed – they increase totalGen) ' m[N+1]=Mobius(0.085786442,Complex( 0.292893222, 0.292893222),0,1) m[N+2]=Mobius(0.085786442,Complex(-0.292893222,-0.292893222),0,1) m[N+3]=Mobius(0.085786442,Complex( 0.292893222,-0.292893222),0,1) m[N+4]=Mobius(0.085786442,Complex(-0.292893222, 0.292893222),0,1)
'm[N+5]=Mobius(0.022407752,Complex( 0.076504842, 0.076504842), 0, 1) 'm[N+6]=Mobius(0.022407752,Complex(-0.076504842, -0.076504842), 0, 1) 'm[N+7]=Mobius(0.022407752,Complex( 0.076504842, -0.076504842), 0, 1) 'm[N+8]=Mobius(0.022407752,Complex(-0.076504842, 0.076504842), 0, 1)
m[N+5]=Mobius(0.041421362,Complex(0.400000002,0.224264072), 0, 1) m[N+6]=Mobius(0.041421362,Complex(0.224264072,0.400000002), 0, 1)
m[N+7]=Mobius(0.041421362,Complex(-0.400000002,0.224264072), 0, 1) m[N+8]=Mobius(0.041421362,Complex(-0.224264072,0.400000002), 0, 1)
m[N+9]=Mobius(0.041421362,Complex(-0.400000002,-0.224264072), 0, 1) m[N+10]=Mobius(0.041421362,Complex(-0.224264072,-0.400000002), 0, 1)
m[N+11]=Mobius(0.041421362,Complex(0.400000002,-0.224264072), 0, 1) m[N+12]=Mobius(0.041421362,Complex(0.224264072,-0.400000002), 0, 1)
m[N+13]=Mobius(0.023649462,Complex(0.442905162,0.175342122), 0, 1) m[N+14]=Mobius(0.023649462,Complex(0.175342122,0.442905162), 0, 1)
m[N+15]=Mobius(0.023649462,Complex(-0.442905162,0.175342122), 0, 1) m[N+16]=Mobius(0.023649462,Complex(-0.175342122,0.442905162), 0, 1)
m[N+17]=Mobius(0.023649462,Complex(-0.442905162,-0.175342122), 0, 1) m[N+18]=Mobius(0.023649462,Complex(-0.175342122,-0.442905162), 0, 1)
m[N+19]=Mobius(0.023649462,Complex(0.442905162,-0.175342122), 0, 1) m[N+20]=Mobius(0.023649462,Complex(0.175342122,-0.442905162), 0, 1)
m[N+21]=Mobius(0.015132432,Complex(0.463467092,0.142459882), 0, 1) m[N+22]=Mobius(0.015132432,Complex(0.142459882,0.463467092), 0, 1)
m[N+23]=Mobius(0.015132432,Complex(-0.463467092,0.142459882), 0, 1) m[N+24]=Mobius(0.015132432,Complex(-0.142459882,0.463467092), 0, 1)
m[N+25]=Mobius(0.015132432,Complex(-0.463467092,-0.142459882), 0, 1) m[N+26]=Mobius(0.015132432,Complex(-0.142459882,-0.463467092), 0, 1)
m[N+27]=Mobius(0.015132432,Complex(0.463467092,-0.142459882), 0, 1) m[N+28]=Mobius(0.015132432,Complex(0.142459882,-0.463467092), 0, 1)
m[N+29]=Mobius(0.010466922,Complex(0.474730622,0.119471642), 0, 1) m[N+30]=Mobius(0.010466922,Complex(0.119471642,0.474730622), 0, 1)
m[N+31]=Mobius(0.010466922,Complex(-0.474730622,0.119471642), 0, 1) m[N+32]=Mobius(0.010466922,Complex(-0.119471642,0.474730622), 0, 1)
m[N+33]=Mobius(0.010466922,Complex(-0.474730622,-0.119471642), 0, 1) m[N+34]=Mobius(0.010466922,Complex(-0.119471642,-0.474730622), 0, 1)
m[N+35]=Mobius(0.010466922,Complex(0.474730622,-0.119471642), 0, 1) m[N+36]=Mobius(0.010466922,Complex(0.119471642,-0.474730622), 0, 1)
m[N+37]=Mobius(0.007653932,Complex(0.481521772,0.102671482), 0, 1) m[N+38]=Mobius(0.007653932,Complex(0.102671482,0.481521772), 0, 1)
m[N+39]=Mobius(0.007653932,Complex(-0.481521772,0.102671482), 0, 1) m[N+40]=Mobius(0.007653932,Complex(-0.102671482,0.481521772), 0, 1)
m[N+41]=Mobius(0.007653932,Complex(-0.481521772,-0.102671482), 0, 1) m[N+42]=Mobius(0.007653932,Complex(-0.102671482,-0.481521772), 0, 1)
m[N+43]=Mobius(0.007653932,Complex(0.481521772,-0.102671482), 0, 1) m[N+44]=Mobius(0.007653932,Complex(0.102671482,-0.481521772), 0, 1)
m[N+45]=Mobius(0.005833582,Complex(0.485916492,0.089920032), 0, 1) m[N+46]=Mobius(0.005833582,Complex(0.089920032,0.485916492), 0, 1)
m[N+47]=Mobius(0.005833582,Complex(-0.485916492,0.089920032), 0, 1) m[N+48]=Mobius(0.005833582,Complex(-0.089920032,0.485916492), 0, 1)
m[N+49]=Mobius(0.005833582,Complex(-0.485916492,-0.089920032), 0, 1) m[N+50]=Mobius(0.005833582,Complex(-0.089920032,-0.485916492), 0, 1)
m[N+51]=Mobius(0.005833582,Complex(0.485916492,-0.089920032), 0, 1) m[N+52]=Mobius(0.005833582,Complex(0.089920032,-0.485916492), 0, 1)
' ' ---- Compute maximum possible number of center circles ---- ' Complex MaxTotal = 0 count = 1 ' at level 0, only the center circle for (i = 0, i < Steps, i += 1) { MaxTotal += count count *= totalGen } ' ' Allocate arrays of size MaxTotal ' Complex Total = MaxTotal ' will be overwritten with actual count after generation Circle c[Total] Complex index[Total] Complex level[Total] Circle UnitCircle = CircleC(0, 1) ' ' ---- Generate only center circles ---- ' ' Initialize level 0: the single center circle c[0] = Mobius.TransformCircle(m[0], UnitCircle) index[0] = 0 level[0] = 0 count = 1 start = 0 end = 1 ' circles from previous level are at indices start..end-1
if (Steps > 1) { for (lev = 1, lev < Steps, lev += 1) { for (j = start, j < end, j += 1) { ' All circles in the array have index = 0, so no need to check. ' Apply all generators to each existing center circle. for (k = 0, k < totalGen, k += 1) { c[count] = Mobius.TransformCircle(m[k], c[j]) if (c[count].Radius >= RadiusMin) { index[count] = 0 ' inherited from parent (always 0) level[count] = lev count += 1 } } } start = end end = count ' new circles for next level start at the old end } } Total = count ' actual number used
CurveTrap.Initialize( \ Center, DegreeToRadian(Angle), Scale, AlternateAngle, 6, False, LineWidth \ ) ' ' Add the circles to the trap. ' for (i = 0, i < Total, i += 1) { lev = level[i] idx = index[i] ' always 0 now if (idx = 0) { if (ShowCenter[lev]) { CurveTrap.AddCircle2(c[i], Solid, IIf(Solid, lev, 0), idx, lev) } } else { ' This branch will never be taken because we only have idx=0 if (ShowRing[lev]) { CurveTrap.AddCircle2(c[i], Solid, IIf(Solid, lev, 0), idx, lev) } } }
trap:
trappedPoint = CurveTrap.Apply(z)
properties:
divider { caption = "General Options" } option Center { type = Complex caption = "Center" details = "Center of trap" default = 0 } option Angle { type = Float caption = "Angle" details = "Angle of rotation" default = 0 range = [-360,360] } option Scale { type = Float caption = "Scale" details = "Scale factor applied to trap" range = (0,) default = 2 } option Solid { type = Boolean caption = "Solid" details = "Check to create solid trap" default = False } option AlternateAngle { type = Boolean caption = "Alternate Angle" details = "Use alternate angle calculation" default = False } option LineWidth { type = Float caption = "Line Width" details = "Extent of trap on either side of curve (> 0)" range = (0,) default = 0.00411522633744855967078189300413 enabled = ~Solid } divider { caption = "U/V Controls" } option AbsU { type = Float caption = "Abs(U)" details = "Magnitude of U (1-2)" default = 1.1 range = [1,2] } option ArgU { type = Float caption = "Arg(U)" details = "Angle of U" default = 0 range = [-360,360] } option ArgV { type = Float caption = "Arg(V)" details = "Angle of V" default = 180 range = [-360,360] } divider { caption = "Circle Controls" } option N { type = IntegerEnum(3,12) caption = "N" details = "Number of base circles" default = 4 } option Steps { type = IntegerEnum(1,16) caption = "Steps" details = "Number of inversion steps" default = 4 ' you can increase to 7 now, but set RadiusMin > 0 to avoid memory issues } option Shift { type = Boolean caption = "Shift" details = "Check to rotate initial chain by pi/N" default = False } option RadiusMin { type = Float caption = "Radius Min" details = "Minimum acceptable circle radius" default = 0.001 ' set to a small positive value to prune tiny circles range = [0,) }
define ShowLevel(Index)
divider { caption = "Level #Index# Options" } option LR#Index# { type = Boolean caption = "Show Ring" details = "Show ring of circles at level #Index#" default = True enabled = Steps >= #Index# } option LC#Index# { type = Boolean caption = "Show Center" details = "Show center circle at level #Index#" default = True enabled = Steps >= #Index# }