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#
}
#end
#include ShowLevel("1")
#include ShowLevel("2")
#include ShowLevel("3")
#include ShowLevel("4")
#include ShowLevel("5")
#include ShowLevel("6")
#include ShowLevel("7")
#include ShowLevel("8")
#include ShowLevel("9")
#include ShowLevel("10")
#include ShowLevel("11")
#include ShowLevel("12")
#include ShowLevel("13")
#include ShowLevel("14")
#include ShowLevel("15")
#include ShowLevel("16")