Math::PlanePath::Flowsnake -- self-similar path through hexagons
use Math::PlanePath::Flowsnake; my $path = Math::PlanePath::Flowsnake->new; my ($x, $y) = $path->n_to_xy (123);
This path is an integer version of the flowsnake curve by William Gosper,
39----40----41 8 \ \ 32----33----34 38----37 42 7 \ \ / / 31----30 35----36 43 47----48 6 / \ \ \ 28----29 17----16----15 44 46 49... 5 / \ \ \ / 27 23----22 18----19 14 45 4 \ \ \ / / 26 24 21----20 13 11----10 3 \ / \ / / 25 4---- 5---- 6 12 9 2 \ \ / 3---- 2 7---- 8 1 / 0---- 1 y=0 x=-4 -3 -2 -1 0 1 2 3 4 5 6 7 8 9 10 11
The points are spread out on every second X coordinate to make little triangles with integer coordinates, per "Triangular Lattice" in Math::PlanePath.
The basic pattern is the seven points 0 to 6,
4---- 5---- 6 \ \ 3---- 2 / 0---- 1
This repeats at 7-fold increasing scale, with sub-sections rotated according to the edge direction, and the 1, 2 and 6 sub-sections in mirror image. The next level can be seen at the multiple of 7 points N=0,7,14,21,28,35,42,49.
42 ----------- --- 35 --- ----------- --- 28 49 --- --- ---- 14 --- ----------- | 21 | | | | ---- 7 ----- 0 ---
Notice this is the same shape as the 0 to 6, but rotated atan(1/sqrt(7)) = 20.68 degrees anti-clockwise. Each level rotates further and for example after 18 levels it goes all the way around and back to the first quadrant.
The rotation doesn't mean it covers the plane. The shape fattens as it curls around counter-clockwise, but leaves a spiral gap below (which corresponds to three unfilled hexagonal areas of tiling).
The base pattern corresponds to hexagons as follows, with the "***" lines being the base figure.
. . / \ / \ / \ / \ . . . | | | | | | 4*****5*****6 /*\ / \ /*\ / * \ / \ / * \ . * . . * . | * | | *| | *| | *| . 3*****2 7... \ / \ /*\ / \ / \ / * \ / . . * . | | * | | |* | 0*****1 . \ / \ / \ / \ / . .
In the next level the parts corresponding to 1, 2 and 6 are mirrored because they correspond to a hexagon to the right of the line segment, rather than to the left.
The flowsnake can also be thought of as successively subdividing line segments with suitably scaled copies of the 0 to 7 figure (or its reversal).
The code here could be used for that by taking points N=0 to N=7^level. The Y coordinates should be multiplied by sqrt(3) to make proper equilateral triangles, then a rotation and scaling to have the endpoint come out at X=1,Y=0 or wherever desired. With this the path is confined to a finite fractal boundary.
$path = Math::PlanePath::Flowsnake->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. Points begin at 0 and if $n < 0 then the return is an empty list.
$n
$n < 0
Fractional positions give an X,Y position along a straight line between the integer positions.
The current code calculates an exact rect_to_n_range() by searching for the highest and lowest N which is in the rectangle.
rect_to_n_range()
The curve at a given level is bounded by the Gosper island shape, but the wiggly sides make it difficult to calculate, so a bounding radius sqrt(7)^level, plus a bit, is used. The portion of the curve comprising some high digits of N can be excluded if the N point is too far away from the rectangle, ie. further than that radius.
When a part of the curve is excluded this way it prunes a whole branch of the digits tree. When the lowest digit is reached then an exact test for that point being actually within the rectangle is made. The radius calculation is a bit rough, and since it doesn't even take into account the direction of the curve it's a rather large over-estimate, but it works.
The same sort of search could be applied for non-rectangular shapes, calculating a radial distance from the shape. The distance doesn't have to be exact, something bounding the shape is good enough until the lowest digit is reached and an X,Y is being considered as an actual high or low N bound.
Math::PlanePath, Math::PlanePath::Flowsnake, Math::PlanePath::GosperIslands
Math::PlanePath::KochCurve, Math::PlanePath::HilbertCurve, Math::PlanePath::PeanoCurve, Math::PlanePath::ZOrderCurve
Copyright 2010, 2011 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/>.
To install Math::PlanePath, copy and paste the appropriate command in to your terminal.
cpanm
cpanm Math::PlanePath
CPAN shell
perl -MCPAN -e shell install Math::PlanePath
For more information on module installation, please visit the detailed CPAN module installation guide.