.\" Automatically generated by Pod::Man 4.14 (Pod::Simple 3.40) .\" .\" Standard preamble: .\" ======================================================================== .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Vb \" Begin verbatim text .ft CW .nf .ne \\$1 .. .de Ve \" End verbatim text .ft R .fi .. .\" Set up some character translations and predefined strings. \*(-- will .\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left .\" double quote, and \*(R" will give a right double quote. \*(C+ will .\" give a nicer C++. Capital omega is used to do unbreakable dashes and .\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, .\" nothing in troff, for use with C<>. .tr \(*W- .ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' .ie n \{\ . ds -- \(*W- . ds PI pi . if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch . if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch . ds L" "" . ds R" "" . ds C` "" . ds C' "" 'br\} .el\{\ . ds -- \|\(em\| . ds PI \(*p . ds L" `` . ds R" '' . ds C` . ds C' 'br\} .\" .\" Escape single quotes in literal strings from groff's Unicode transform. .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" .\" If the F register is >0, we'll generate index entries on stderr for .\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index .\" entries marked with X<> in POD. Of course, you'll have to process the .\" output yourself in some meaningful fashion. .\" .\" Avoid warning from groff about undefined register 'F'. .de IX .. .nr rF 0 .if \n(.g .if rF .nr rF 1 .if (\n(rF:(\n(.g==0)) \{\ . if \nF \{\ . de IX . tm Index:\\$1\t\\n%\t"\\$2" .. . if !\nF==2 \{\ . nr % 0 . nr F 2 . \} . \} .\} .rr rF .\" ======================================================================== .\" .IX Title "Math::PlanePath::VogelFloret 3pm" .TH Math::PlanePath::VogelFloret 3pm "2021-01-23" "perl v5.32.0" "User Contributed Perl Documentation" .\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" way too many mistakes in technical documents. .if n .ad l .nh .SH "NAME" Math::PlanePath::VogelFloret \-\- circular pattern like a sunflower .SH "SYNOPSIS" .IX Header "SYNOPSIS" .Vb 3 \& use Math::PlanePath::VogelFloret; \& my $path = Math::PlanePath::VogelFloret\->new; \& my ($x, $y) = $path\->n_to_xy (123); \& \& # other rotations \& $path = Math::PlanePath::VogelFloret\->new \& (rotation_type => \*(Aqsqrt2\*(Aq); .Ve .SH "DESCRIPTION" .IX Header "DESCRIPTION" The is an implementation of Helmut Vogel's model for the arrangement of seeds in the head of a sunflower. Integer points are on a spiral at multiples of the golden ratio phi = (1+\fBsqrt\fR\|(5))/2, .IX Xref "Vogel, Helmut Golden Ratio" .PP .Vb 2 \& 27 19 \& 24 \& \& 14 11 \& 22 16 \& 6 29 \& \& 30 9 3 \& 8 \& 1 21 \& 17 . \& 4 \& 13 \& 25 2 5 \& 12 \& 7 26 \& 10 \& 18 \& 20 15 \& \& 23 31 \& 28 .Ve .PP The polar coordinates for a point N are .PP .Vb 4 \& R = sqrt(N) * radius_factor \& angle = N / (phi**2) in revolutions, 1==full circle \& = N * \-phi modulo 1, with since 1/phi^2 = 2\-phi \& theta = 2*pi * angle in radians .Ve .PP Going from point N to N+1 adds an angle 0.382 revolutions around (anti-clockwise, the usual spiralling direction), which means just over 1/3 of a circle. Or equivalently it's \-0.618 back (clockwise) which is phi=1.618 ignoring the integer part since that's a full circle \*(-- only the fractional part determines the position. .PP \&\f(CW\*(C`radius_factor\*(C'\fR is a scaling 0.6242 designed to put the closest points 1 apart. The closest are N=1 and N=4. See \*(L"Packing\*(R" below. .SS "Other Rotation Types" .IX Subsection "Other Rotation Types" An optional \f(CW\*(C`rotation_type\*(C'\fR parameter selects other possible floret forms. .PP .Vb 2 \& $path = Math::PlanePath::VogelFloret\->new \& (rotation_type => \*(Aqsqrt2\*(Aq); .Ve .PP The current types are as follows. The \f(CW\*(C`radius_factor\*(C'\fR for each keeps points at least 1 apart so unit circles don't overlap. .PP .Vb 5 \& rotation_type rotation_factor radius_factor \& "phi" 2\-phi = 0.3820 0.624 \& "sqrt2" sqrt(2) = 0.4142 0.680 \& "sqrt3" sqrt(3) = 0.7321 0.756 \& "sqrt5" sqrt(5) = 0.2361 0.853 .Ve .PP The \*(L"sqrt2\*(R" floret is quite similar to phi, but doesn't pack as tightly. Custom rotations can be made with \f(CW\*(C`rotation_factor\*(C'\fR and \f(CW\*(C`rotation_factor\*(C'\fR parameters, .PP .Vb 7 \& # R = sqrt(N) * radius_factor \& # angle = N * rotation_factor in revolutions \& # theta = 2*pi * angle in radians \& # \& $path = Math::PlanePath::VogelFloret\->new \& (rotation_factor => sqrt(37), \& radius_factor => 2.0); .Ve .PP Usually \f(CW\*(C`rotation_factor\*(C'\fR should be an irrational number. A rational like P/Q merely results in Q many straight lines and doesn't spread the points enough to suit R=sqrt(N). Irrationals which are very close to simple rationals behave that way too. (Of course all floating point values are implicitly rationals, but are fine within the limits of floating point accuracy.) .PP The \*(L"noble numbers\*(R" (A+B*phi)/(C+D*phi) with A*D\-B*C=1, A phi as k\->infinity, .PP .Vb 2 \& angle = F(k)*\-phi \& = \-F(k+1) + epsilon .Ve .PP The Lucas numbers similarly with L(k)*phi close to L(k+1). The \*(L"epsilon\*(R" approaches zero quickly enough in both cases that the resulting Y coordinate approaches zero. This can be calculated as follows, writing .PP .Vb 1 \& beta = \-1/phi =\-0.618 .Ve .PP Since abs(beta)<1 the powers beta^k go to zero. .PP .Vb 1 \& F(k) = (phi^k \- beta^k) / (phi \- beta) # an integer \& \& angle = F(k) * \-phi \& = \- (phi*phi^k \- phi*beta^k) / (phi \- beta) \& = \- (phi^(k+1) \- beta^(k+1) \& + beta^(k+1) \- phi*beta^k) / (phi \- beta) \& = \- F(k+1) \- (phi\-beta)*beta^k / (phi \- beta) \& = \- F(k+1) \- beta^k \& \& frac(angle) = \- beta^k = 1/(\-phi)^k .Ve .PP The arc distance away from the X axis at radius R=sqrt(F(k)) is then as follows, simplifying using phi*(\-beta)=1 and phi \- beta = \fBsqrt\fR\|(5). The Y coordinate vertical distance is a little less than the arc distance. .PP .Vb 5 \& arcdist = 2*pi * R * frac(angle) \& = 2*pi * sqrt((phi^k \- beta^k)/sqrt(5)) * 1/(\-phi)^k \& = \- (\-1)^k * 2*pi * sqrt((1/phi^2k*phi^k \- beta^3k)/sqrt(5)) \& = \- (\-1)^k * 2*pi * sqrt((1/phi^k \- 1/(\-phi)^3k)/sqrt(5)) \& \-> 0 as k \-> infinity .Ve .PP Essentially the radius increases as phi^(k/2) but the angle frac decreases as (1/phi)^k so their product goes to zero. The (\-1)^k in the formula puts the points alternately just above and just below the X axis. .PP The calculation for the Lucas numbers is very similar, with term +(beta^k) instead of \-(beta^k) and an extra factor \fBsqrt\fR\|(5). .PP .Vb 1 \& L(k) = phi^k + beta^k \& \& angle = L(k) * \-phi \& = \-phi*phi^k \- phi*beta^k \& = \-phi^(k+1) \- beta^(k+1) + beta^(k+1) \- phi*beta^k \& = \-L(k) + beta^k * (beta \- phi) \& = \-L(k) \- sqrt(5) * beta^k \& \& frac(angle) = \-sqrt(5) * beta^k = \-sqrt(5) / (\-phi)^k \& \& arcdist = 2*pi * R * frac(angle) \& = 2*pi * sqrt(L(k)) * sqrt(5)*beta^k \& = 2*pi * sqrt(phi^k + 1/(\-phi)^k) * sqrt(5)*beta^k \& = (\-1)*k * 2*pi * sqrt(5) * sqrt((\-beta)^2k * phi^k + beta^3k) \& = (\-1)*k * 2*pi * sqrt(5) * sqrt((\-beta)^k + beta^3k) .Ve .SS "Spectrum" .IX Subsection "Spectrum" The spectrum of a real number is its multiples, each rounded down to an integer. For example the spectrum of phi is .PP .Vb 2 \& floor(phi), floor(2*phi), floor(3*phi), floor(4*phi), ... \& 1, 3, 4, 6, ... .Ve .PP When plotted on the Vogel floret these integers are all in the first 1/phi = 0.618 of the circle. .PP .Vb 12 \& 61 53 \& 69 40 45 58 \& 48 32 71 \& 56 27 37 \& 35 19 24 50 \& 43 14 11 63 \& 64 22 6 16 29 \& 30 3 42 \& 51 9 1 8 21 \& 72 17 4 . 55 \& 38 \& 59 25 12 \& \& 46 33 \& \& 67 .Ve .PP This occurs because .PP .Vb 7 \& angle = N * 1/phi^2 \& = N * (1\-1/phi) \& = N * \-1/phi # modulo 1 \& = floor(int*phi) * \-1/phi # N=spectrum \& = (int*phi \- frac) * \-1/phi # 0new ()""" 4 .el .IP "\f(CW$path = Math::PlanePath::VogelFloret\->new ()\fR" 4 .IX Item "$path = Math::PlanePath::VogelFloret->new ()" .PD 0 .ie n .IP """$path = Math::PlanePath::VogelFloret\->new (key => value, ...)""" 4 .el .IP "\f(CW$path = Math::PlanePath::VogelFloret\->new (key => value, ...)\fR" 4 .IX Item "$path = Math::PlanePath::VogelFloret->new (key => value, ...)" .PD Create and return a new path object. .Sp The default is Vogel's phi floret. Optional parameters can vary the pattern, .Sp .Vb 3 \& rotation_type => string, choices above \& rotation_factor => number \& radius_factor => number .Ve .Sp The available \f(CW\*(C`rotation_type\*(C'\fR values are listed above (see \*(L"Other Rotation Types\*(R"). \f(CW\*(C`radius_factor\*(C'\fR can be given together with \&\f(CW\*(C`rotation_type\*(C'\fR to have its rotation, but scale the radius differently. .Sp If a \f(CW\*(C`rotation_factor\*(C'\fR is given then the default \f(CW\*(C`radius_factor\*(C'\fR is not specified yet. Currently it's 1.0, but perhaps something suiting at least the first few N positions would be better. .ie n .IP """($x,$y) = $path\->n_to_xy ($n)""" 4 .el .IP "\f(CW($x,$y) = $path\->n_to_xy ($n)\fR" 4 .IX Item "($x,$y) = $path->n_to_xy ($n)" Return the X,Y coordinates of point number \f(CW$n\fR on the path. .Sp \&\f(CW$n\fR can be any value \f(CW\*(C`$n >= 0\*(C'\fR and fractions give positions on the spiral in between the integer points, though the principle interest for the floret is where the integers fall. .Sp For \f(CW\*(C`$n < 0\*(C'\fR the return is an empty list, it being considered there are no negative points in the spiral. .ie n .IP """$rsquared = $path\->n_to_rsquared ($n)""" 4 .el .IP "\f(CW$rsquared = $path\->n_to_rsquared ($n)\fR" 4 .IX Item "$rsquared = $path->n_to_rsquared ($n)" Return the radial distance R^2 of point \f(CW$n\fR, or \f(CW\*(C`undef\*(C'\fR if there's no point \f(CW$n\fR. As per the formulas above this is simply .Sp .Vb 1 \& $n * $radius_factor**2 .Ve .ie n .IP """$n = $path\->xy_to_n ($x,$y)""" 4 .el .IP "\f(CW$n = $path\->xy_to_n ($x,$y)\fR" 4 .IX Item "$n = $path->xy_to_n ($x,$y)" Return an integer point number for coordinates \f(CW\*(C`$x,$y\*(C'\fR. Each integer N is considered the centre of a circle of diameter 1 and an \f(CW\*(C`$x,$y\*(C'\fR within that circle returns N. .Sp The builtin \f(CW\*(C`rotation_type\*(C'\fR choices are scaled so no two points are closer than 1 apart so the circles don't overlap, but they also don't cover the plane and if \f(CW\*(C`$x,$y\*(C'\fR is not within one of those circles then the return is \&\f(CW\*(C`undef\*(C'\fR. .Sp With \f(CW\*(C`rotation_factor\*(C'\fR and \f(CW\*(C`radius_factor\*(C'\fR parameters it's possible for unit circles to overlap. In the current code the return is the largest N covering \f(CW\*(C`$x,$y\*(C'\fR, but perhaps that will change. .ie n .IP """$str = $path\->figure ()""" 4 .el .IP "\f(CW$str = $path\->figure ()\fR" 4 .IX Item "$str = $path->figure ()" Return \*(L"circle\*(R". .SH "OEIS" .IX Header "OEIS" Entries in Sloane's Online Encyclopedia of Integer Sequences related to this path include .Sp .RS 4 (etc) .RE .PP .Vb 2 \& A000201 spectrum of phi, N in first 0.618 of circle \& A003849 Fibonacci word, values 0,1 .Ve .SH "SEE ALSO" .IX Header "SEE ALSO" Math::PlanePath, Math::PlanePath::SacksSpiral, Math::PlanePath::TheodorusSpiral .PP Math::NumSeq::FibonacciWord, Math::NumSeq::Fibbinary .SH "HOME PAGE" .IX Header "HOME PAGE" .SH "LICENSE" .IX Header "LICENSE" Copyright 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020 Kevin Ryde .PP This file is part of Math-PlanePath. .PP Math-PlanePath is free software; you can redistribute it and/or modify it under the terms of the \s-1GNU\s0 General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. .PP Math-PlanePath is distributed in the hope that it will be useful, but \&\s-1WITHOUT ANY WARRANTY\s0; without even the implied warranty of \s-1MERCHANTABILITY\s0 or \s-1FITNESS FOR A PARTICULAR PURPOSE.\s0 See the \s-1GNU\s0 General Public License for more details. .PP You should have received a copy of the \s-1GNU\s0 General Public License along with Math-PlanePath. If not, see .