NAME
Math::PlanePath::MathImageArchimedeanChords -- radial spiral chords
SYNOPSIS
use Math::PlanePath::MathImageArchimedeanChords;
my $path = Math::PlanePath::MathImageArchimedeanChords->new;
my ($x, $y) = $path->n_to_xy (123);
DESCRIPTION
In progresss ... xy_to_n() is a bit slow.
This path puts points at unit chord steps on an Archimedean spiral. The spiral goes outwards by a constant 1 unit each revolution and the points are placed on it spaced 1 apart. The result is roughly
32 31 30
33 29
14
34 15 13 28 50
12
35 16 3 27 49
4 2 11
17
36 5 0 1 26 48
10
37 18 25 47
6 9
19 7 8 24 46
38
20 23 45
39 21 22
40 44
41 42 43
X,Y positions returned are fractional. Each revolution is about 2*pi longer than the previous, so the effect is a kind of "6.28" step spiralling.
Because the spacing is by unit chords, unit circles centred on each N position touch but don't overlap. The spiral spacing of 1 unit per revolution means they don't overlap radially either.
The unit chords are somewhat similar to the TheordorusSpiral. It takes unit steps at right-angles to the radius and the result approaches an Archimedean spiral of 3.14 radial spacing. This ArchimedeanChords on the other hand is a 1 radial spacing, and directly followed.
FUNCTIONS
$path = Math::PlanePath::MathImageArchimedeanChords->new ()
-
Create and return a new path object.
($x,$y) = $path->n_to_xy ($n)
-
Return the x,y coordinates of point number
$n
on the path.$n
can be any value$n >= 0
and fractions give positions on the spiral in between the integer points.For
$n < 0
the return is an empty list, it being considered there are no negative points in the spiral. $n = $path->xy_to_n ($x,$y)
-
Return an integer point number for coordinates
$x,$y
. Each integer N is considered the centre of a circle of diameter 1 and an$x,$y
within that circle returns N.The unit spacing of the spiral means those circles don't overlap, but they also don't cover the plane and if
$x,$y
is not within one then the return isundef
.
FORMULAS
The current code keeps a position as a polar angle t and calculates an increment u needed to move by a unit chord. The cartesian distance between t and t+u, or rather the square of the distance, is
dist^2(u) = ((t+u)/2pi*cos(t+u) - t/2pi*cos(t))^2 # X
+ ((t+u)/2pi*sin(t+u) - t/2pi*sin(t))^2 # Y
which simplifies to
dist^2(u) = [ (t+u)^2 + t^2 - 2*t*(t+u)*cos(u) ] / (4*pi^2)
And then a half angle cos(u) = 1 - 2*sin^2(u/2) to switch to sin(u) just in case when u is small cos(u) near 1.0 might lose floating point accuracy, and also being a slight further simplification,
dist^2(u) = [ u^2 + 4*t*(t+u)*sin^2(u/2) ] / (4*pi^2)
Then the aim is dist(u) = 1 for a unit chord. The u*sin(u) probably doesn't have a good closed form inverse, so the current code is a little Newton/Raphson iteration seeking f(u)=0
f(u) = u^2 + 4*t*(t+u)*sin^2(u/2) - 4*pi^2
and derivative f'(u) for the slope (from the cos() form), and again preferring sin over cos for small u,
f'(u) = 2*(t+u) - 2*t*[ cos(u) - (t+u)*sin(u) ]
= 2*[ u + t * [2*sin^2(u/2) + (t+u)*sin(u) ] ]
SEE ALSO
Math::PlanePath, Math::PlanePath::TheodorusSpiral, Math::PlanePath::SacksSpiral