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

NAME

Math::PlanePath::TerdragonMidpoint -- dragon curve midpoints

SYNOPSIS

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

DESCRIPTION

This is an integer version of the terdragon curve by Davis and Knuth, giving the midpoint of each curve segment.

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

        ^  ^  ^  ^  ^  ^  ^  ^  ^  ^  ^  ^  ^  ^  ^  ^  ^  ^
      -12-11-10 -9 -8 -7 -6 -5 -4 -3 -2 -1 X=0 1  2  3  4  5 ...

The points are the middle of each edge of a double-size TerdragonCurve. So for example the TerdragonCurve N=3 to N=4 is X=3,Y=1 to X=2,Y=2 which is doubled out to X=6,Y=2 and X=4,Y=4 then the midpoint of those is X=5,Y=3 for N=3 here.

                            ...
                              \
      6             -----8-----      double size
                    \                TerdragonCurve
                     \               giving midpoints
      5               7
                       \
                        \
      4        -----6---- _
               \         / \
                \       /   \
      3          5     4     3
                  \   /       \
                   \_/         \
      2              _----2-----
                     \
                      \
      1                1
                        \
                         \
    Y=0 ->    +-----0-----.

              ^
             X=0 1  2  3  4  5  6

The result is integer X,Y coordinates on every second point as per "Triangular Lattice" in Math::PlanePath, but visiting only 3 of every 4 such triangular points, or 3 of 8 integer X,Y points. The pattern is alternate rows with 1 of 2 points such as Y=7, and 1 of 4 points such as Y=8. Notice the pattern is the same when turned by 60 degrees or 120 degrees.

    * * * * * * * * * * * * * * * * * * * *
     *   *   *   *   *   *   *   *   *   *
    * * * * * * * * * * * * * * * * * * * *
       *   *   *   *   *   *   *   *   *
    * * * * * * * * * * * * * * * * * * * *
     *   *   *   *   *   *   *   *   *   *
    * * * * * * * * * * * * * * * * * * * *
       *   *   *   *   *   *   *   *   *
    * * * * * * * * * * * * * * * * * * * *
     *   *   *   *   *   *   *   *   *   *
    * * * * * * * * * * * * * * * * * * * *
       *   *   *   *   *   *   *   *   *
    * * * * * * * * * * * * * * * * * * * *
     *   *   *   *   *   *   *   *   *   *
    * * * * * * * * * * * * * * * * * * * *

Arms

Multiple copies of the curve can be selected, each advancing successively. The curve covers 1/6 of the plane and 6 arms rotated by 60, 120, 180, 240 and 300 degrees together perfectly.

For example arms => 6 begins as follows. N=0,6,12,18,etc is the first arm (like the plain curve above), then N=1,7,13,19 the second rotated 60 degrees, N=2,8,14,20 the third rotated 120, etc.

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

FUNCTIONS

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

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

$n = $path->n_start()

Return 0, the first N in the path.

FORMULAS

X,Y to N

An X,Y point can be turned into N by dividing out digits of a complex base w+1 where

    w = 6th root of unity
      = 1/2 + i * sqrt(3)/2

At each step the low ternary digit is formed from X,Y and an adjustment applied to move X,Y onto a multiple of w+1 to divide out.

In the N points above it can be seen that each group of three N values, such as N=0,1,2, or N=3,4,5 etc, make a straight line. The adjustment moves an endpoint N=0 mod 3 or N=2 mod 3 to the centre N=1 mod 3. The centre N=1 mod 3 is always on a multiple of w+1.

The angles and positions for the N triple groups follows a 12-point pattern,

     \   /   /   \   /   /   \   /   /   \   /   /   \
    - \ / \ - - - \ / \ - - - \ / \ - - - \ / \ - - -
       /   \   /   /   \   /   /   \   /   /   \   /
    \ - - - \ / \ - - - \ / \ - - - \ / \ - - - \ / \
     \   /   /   \   /   /   \   /   /   \   /   /   \
    - \ / \ - - - \ / \ - - - \ / \ - - - \ / \ - - -
       /   \   /   /   \   /   /   \   /   /   \   /
    \ - - - \ / \ - - - \ / \ - - - \ / \ - - - \ / \
     \   /   /   \   /   /   \   /   /   \   /   /   \
    - \ / \ - - - \ / \ - - - \ / \ - - - \ / \ - - -
       /   \   /   /   \   /   /   \   /   /   \   /
    \ - - - \ / \ - - - \ / \ - - - \ / \ - - - \ / \
     \   /   /   \   /   /   \   /   /   \   /   /   \
    - \ / \ - - - \ / \ - - - \ / \ - - - \ / \ - - -
       /   \   /   /   \   /   /   \   /   /   \   /
    \ - - - \ / \ - - - \ / \ - - - \ / \ - - - \ / \
     \   /   /   \   /   /   \   /   /   \   /   /   \
    - \ / \ - - - \ / \ - - - \ / \ - - - \ / \ - - -
       /   \   /   /   \   /   /   \   /   /   \   /
    \ - - - \ / \ - - - \ / \ - - - \ / \ - - - \ / \
     \   /   /   \   /   /   \   /   /   \   /   /   \
    - \ / \ - - - \ / \ - - - \ / \ - - - \ / \ - - -
       /   \   /   /   \   /   /   \   /   /   \   /
    \ - - - \ / \ - - - \ / \ - - - \ / \ - - - \ / \

In the current code a 12x12 table is used, indexed by X mod 12 and Y mod 12. Is there a good aX+bY mod 12 or mod 24 for a smaller table? Maybe X+3Y like the digit? Taking C=(X-Y)/2 in triangular coordinate style can get the table down to 6x6. But however the adjustment is found the result is

    Ndigit = (X + 3Y + 1) % 3    # 0,1,2 ternary digit

    Xmid = X + Xadj(X%12,Y%12)
    Ymid = Y + Yadj(X%12,Y%12)

    new X,Y = (Xmid,Ymid) / (w+1)
            = (Xmid,Ymid) * (2-w) / 3
            = ((Xmid+Ymid)/2, (3*Ymid-Xmid)/6)

Points not reached by the curve can be detected with flag entries in the adjustment table.

The X,Y reduction stops at X=3,Y=1 which is N=1. Or at that point rotated by 60,120,180,240,300 degrees for the other arms. Of course if only some of the arms are of interest then reaching one of the others means the original X,Y was outside the arms of interest.

    arm     X,Y stop
     0        3,1
     1        0,2
     2       -3,1
     3       -3,-1
     4        0,-2
     5        3,-1

For an odd number arm each digit of N must be flipped so 0,1,2 becomes 2,1,0,

    if arm mod 2 == 1
    then  N = 3**digits - 1 - N

SEE ALSO

Math::PlanePath, Math::PlanePath::TerdragonCurve, Math::PlanePath::DragonMidpoint

HOME PAGE

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

LICENSE

Copyright 2011, 2012 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/>.