The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NAME

Math::PlanePath::FlowsnakeCentres -- self-similar path of hexagon centres

SYNOPSIS

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

DESCRIPTION

This path is a variation of the flowsnake curve by William Gosper which follows the flowsnake tiling the same way but follows the centres of hexagons instead of corners and across. The result is the same overall shape, but a symmetric base figure.

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

    -5 -4 -3 -2 -1 X=0 1  2  3  4  5  6  7  8  9

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
      /        \
     3---- 2     6---
             \
        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 reverse. Eg. N=7 to N=13 is the "1" part, taking the base figure in reverse, and rotated so the end points towards the "2".

The next level can be seen at the midpoints of each such group, being N=2,11,18,23,30,37,46.

                 ---- 37
             ----       ---
       30----              ---
       |                      ---
      |                           46
      |
      |        ----18
     |    -----      ---
    23---               ---
                           ---
                           --- 11
                      -----
                 2 ---

Arms

The optional arms parameter can give up to three copies of the curve, each advancing successively. For example arms=>3 is as follows. Notice the N=3*k points are the plain curve, and N=3*k+1 and N=3*k+2 are rotated copies of it.

                            84---...    48----45                   5
                           /           /        \
                         81    66    51----54    42                4
                        /     /  \           \     \
          28----25    78    69    63----60----57    39    30       3
         /        \     \     \                    /     /  \
       31----34    22    75----72    12----15    36----33    27    2
               \     \              /        \              /
          40----37    19     4     9---- 6    18----21----24       1
         /           /     /  \           \
       43    58    16     7     1     0---- 3    77----80      <- Y=0
      /     /  \     \     \                    /        \
    46    55    61    13----10     2    11    74----71    83      -1
      \     \     \              /     /  \           \     \
       49----52    64    73     5---- 8    14    65----68    86   -2
                  /     /  \              /     /           /
          ...   67----70    76    20----17    62    53   ...      -3
            \              /     /           /     /  \
             85----82----79    23    38    59----56    50         -4
                              /     /  \              /
                            26    35    41----44----47            -5
                              \     \
                               29----32                           -6

                                      ^
          -9 -8 -7 -6 -5 -4 -3 -2 -1 X=0 1  2  3  4  5  6  7  8  9

As described in "Arms" in Math::PlanePath::Flowsnake the flowsnake essentially fills a hexagonal shape. For this Centres variation the start of each arm corresponds to a little hexagon with the N=0 one at the origin, and the 1 and 2 beside and below,

    ^ / \   / \  
     \   \ /   \ 
    | \   |     |
    |  1  |  0--->
    |     |     |
     \   / \   / 
      \ /   \ /  
       |     |   
       |  2  |   
       | /   |   
        /   / 
      v  \ /  

Like the main Flowsnake the sides of the arms mesh perfectly and three arms fill the plane.

FUNCTIONS

$path = Math::PlanePath::FlowsnakeCentres->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.

Fractional positions give an X,Y position along a straight line between the integer positions.

FORMULAS

N to X,Y

The n_to_xy() calculation follows Ed Schouten's method

    http://80386.nl/projects/flowsnake/

breaking N into base-7 digits, applying reversals from high to low according to digits 1, 2, or 6, then applying rotation and position according to the resulting digits.

Unlike Ed's code, the path here starts from N=0 at the edge of the Gosper island shape and for that reason doesn't cover the plane. An offset of N-2*7^21 and suitable X,Y offset can be applied to get the same result.

X,Y to N

The xy_to_n() calculation also follows Ed Schouten's method which is based on a nice observation that the seven cells of the base figure can be identified from their coordinates and the centres of those figures then shrunk down to unit separation, thus generating digits of N from low to high.

In triangular grid style X,Y a remainder is formed

    m = (x + 2*y) mod 7

With the base figure 0 at 0,0 the remainders are

        4---- 6
      /        \
     1---- 3     5
             \
        0---- 2

The remainders are unchanged when the shape is shifted by some multiple of the next level X=5,Y=1 or its rotated forms X=1,Y=3 and X=-4,Y=1 etc. Those vectors all have X+2*Y==0 mod 7.

From the m remainder an offset can be applied to move X,Y to the 0 position, leaving X,Y a multiple of the next level vector X=5,Y=1 etc. That vector can then be shrunk down with

    Xshrunk = (3*Y + 5*X) / 14
    Yshrunk = (5*Y - X) / 14

This gives integers as 3*Y+5*X and 5*Y-X are always multiples of 14. For example the N=35 point at X=2,Y=6 reduces to X = (3*6+5*2)/14 = 2 and Y = (5*6-2)/14 = 2, which is then the "5" part of the base figure.

The remainders can be mapped to digits and then reversals and rotations applied, from high to low, according to the edge orientation. These steps can also be combined in a single lookup table with 6 states (three rotations and forward or reverse).

For the main curve the reduction ends at 0,0. For the multi-arm form the second arm ends at -2,0 and the third at -1,-1. (The modulo and shrink procedure maps those points to themselves.) The calculation can be done without paying attention to how many arms are supposed to be in use. On reaching one of the three ends the "arm" is determined and the original X,Y rejected or accepted accordingly.

The key to this approach is that the base figure is symmetric around a central point, so the rotations or reversals in the path can be applied after breaking down the tiling. Could it work on a non-symmetric base figure like the "across" style of the main Flowsnake, or of something like the DragonCurve for that matter?

SEE ALSO

Math::PlanePath, Math::PlanePath::Flowsnake, Math::PlanePath::GosperIslands

Math::PlanePath::KochCurve, Math::PlanePath::HilbertCurve, Math::PlanePath::PeanoCurve, Math::PlanePath::ZOrderCurve

http://80386.nl/projects/flowsnake/ -- Ed Schouten's code

LICENSE

Copyright 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/>.