Math::...Chords(3pm)

πŸ“¦
version 129 Β· 3 versions
, in debian bookworm, debian trixie, ubuntu jammy, ubuntu noble, ubuntu resolute, ubuntu stonking

✨ NAME ✨

Math::PlanePath::ArchimedeanChords β€” radial spiral chords, bestie πŸŒ€ (yep, this is the Math::...Chords(3pm) page, you found it)


πŸŽ€ SYNOPSIS πŸŽ€

use Math::PlanePath::ArchimedeanChords;
my $path = Math::PlanePath::ArchimedeanChords->new;
my ($x, $y) = $path->n_to_xy (123);

πŸ’« DESCRIPTION πŸ’«

okay so this path drops points at unit chord steps along an Archimedean spiral. the spiral creeps outwards by 1 unit every single revolution, and the points are spaced 1 apart. very demure, very orderly πŸ’…

R = theta/(2*pi)

the result is roughly this whole situation:

                        31
                  32          30         ...                3
            33                   29
                     14
      34       15          13          28    50             2
                                 12
            16        3
       35                       2             27    49          1
                   4                11
         17
       36           5        0     1          26    48     <- Y=0
                                        10
         18
       37              6                      25    47         -1
                                  9
            19        7     8          24    46
      38                                                   -2
               20                23
         39          21    22             45
                                                           -3
               40                   44
                  41    42    43

                         ^
      -3    -2    -1    X=0    1     2     3     4

the X,Y positions it returns are fractional, no cap. each revolution is about 2*pi longer than the previous one, so the whole effect is a kind of 6.28 increment looping. iconic.

because the spacing is by unit chords, adjacent unit circles centred on each N position touch but do not overlap. and the spiral spacing of 1 unit per revolution means they don't overlap radially either. we love a clean layout 🌸

the unit chords here are a little like the "TheodorusSpiral". but the "TheodorusSpiral" goes by unit steps at a fixed right-angle and approximates an Archimedean spiral (of 3.14 radial spacing). whereas this "ArchimedeanChords" is an actual Archimedean spiral (of radial spacing 1), with unit steps angling along that. different girl, different vibe ✨


🌈 FUNCTIONS 🌈

see "FUNCTIONS" in Math::PlanePath for behaviour common to all path classes.

  • $path = Math::PlanePath::ArchimedeanChords->new () β€” makes you a shiny new path object and hands it over 🎁
  • ($x,$y) = $path->n_to_xy ($n) β€” gives you the X,Y coordinates of point number $n on the path.
    • $n can be any value $n >= 0, and fractions give positions on the chord between the integer points (ie. a straight line between the points). $n==0 is the origin 0,0.
    • for $n < 0 the return is an empty list, because it's considered that there are no negative points in the spiral. sorry bestie 😭
  • $n = $path->xy_to_n ($x,$y) β€” gives you back 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 inside 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 isn't inside one, the return is undef.
ngl, the current implementation is a bit slow 🐌
  • $n = $path->n_start () β€” returns 0, the first $n on the path. every queen has a beginning πŸ‘‘
  • $str = $path->figure () β€” returns "circle".

πŸ”₯ FORMULAS πŸ”₯

N to X,Y

the current code keeps a position as a polar angle t and calculates an increment u needed to move along by a unit chord. if dist(u) is the straight-line distance between t and t+u, then squared is the hypotenuse

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)

switch from cos to sin using the half angle cos(u) = 1 - 2*sin^2(u/2) in case if u is small then the cos(u) near 1.0 might lose floating point accuracy, and also as a slight simplification,

dist^2(u) = [ u^2 + 4*t*(t+u)*sin^2(u/2) ] / (4*pi^2)

then want the u which has dist(u)=1 for a unit chord. the u*sin(u) part probably doesn't have a good closed form inverse, so the current code is a Newton/Raphson iteration on f(u) = dist^2(u)-1, seeking f(u)=0

f(u) = u^2 + 4*t*(t+u)*sin^2(u/2) - 4*pi^2

derivative f'(u) for the slope from the cos form is

f'(u) = 2*(t+u) - 2*t*[ cos(u) - (t+u)*sin(u) ]

and again switching from cos to sin in case u is small,

f'(u) = 2*[ u + t*[2*sin^2(u/2) + (t+u)*sin(u)] ]

X,Y to N

a given x,y point is at a fraction of a revolution

frac = atan2(y,x) / 2pi     # -.5 <= frac <= .5
frac += (frac < 0)          # 0 <= frac < 1

and the nearest spiral arm measured radially from x,y is then

r = int(hypot(x,y) + .5 - frac) + frac

Perl's "atan2" is the same as the C library and gives -pi <= angle <= pi, hence allowing for frac<0. it may also be "unspecified" for x=0,y=0, and give +/-pi for x=negzero, which has to be a special case so 0,0 gives r=0. the "int" rounds towards zero, so frac>.5 ends up as r=0.

so the N point just before or after that spiral position may cover the x,y, but how many N chords it takes to get around to there is 's not so easily calculated.

the current code looks in saved "n_to_xy()" positions for an N below the target, and searches up from there until past the target and thus not covering x,y. with "n_to_xy()" points saved 500 apart this means searching somewhere between 1 and 500 points. lowkey a whole journey πŸšΆβ€β™€οΈ

one possibility for calculating a lower bound for N, instead of the saved positions, and both for "xy_to_n()" and "rect_to_n_range()", would be to add up chords in circles. a circle of radius k fits pi/arcsin(1/2k) many unit chords, so

             k=floor(r)     pi
    total = sum         ------------
             k=0        arcsin(1/2k)

and this is less than the chords along the spiral. is there a good polynomial over-estimate of arcsin, to become an under-estimate total, without giving away so much? πŸ€”

Rectangle to N Range

for the "rect_to_n_range()" upper bound, the current code takes the arc length along with spiral with the usual formula

arc = 1/4pi * (theta*sqrt(1+theta^2) + asinh(theta))

written in terms of the r radius (theta = 2pi*r) as calculated from the biggest of the rectangle x,y corners,

arc = pi*r^2*sqrt(1+1/r^2) + asinh(2pi*r)/4pi

the arc length is longer than chords, so N=ceil(arc) is an upper bound for the N range. slay, math ate πŸ’…

an upper bound can also be calculated simply from the circumferences of circles 1 to r, since a spiral loop from radius k to k+1 is shorter than a circle of radius k.

             k=ceil(r)
    total = sum         2pi*k
             k=1

          = pi*r*(r+1)

this is bigger than the arc length, thus a poorer upper bound, but an easier calculation. (incidentally, for smallish r have arc length <= pi*(r^2+1) which is a tighter bound and an easy calculation, but it only holds up to somewhere around r=10^7.) 🫢


🌟 SEE ALSO 🌟

Math::PlanePath, Math::PlanePath::TheodorusSpiral, Math::PlanePath::SacksSpiral


πŸ¦‹ HOME PAGE πŸ¦‹

<http://user42.tuxfamily.org/math-planepath/index.html>


πŸ’œ LICENSE πŸ’œ

Copyright 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020 Kevin Ryde

This file is part of Math-PlanePath.

Math-PlanePath is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version.

Math-PlanePath is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with Math-PlanePath. If not, see <http://www.gnu.org/licenses/>.


and that's the whole page bestie πŸ’– this one's from perl v5.32.0, dated 2021-01-23 β€” that's the footer of Math::...Chords(3pm), mwah, go plot some spirals βœ¨πŸŒ€πŸŽ€