NAME

Math::PlanePath::MathImageSierpinskiCurve -- Sierpinski curve

SYNOPSIS

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

DESCRIPTION

In progress.

This is an integer version of the self-similar curve by Waclaw Sierpinski tiling with right triangles. The default is a single arm of the curve in an eighth of the plane.

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

 ^
X=0 1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16

The tiling it represents is

               /
              /|\
             / | \
            /  |  \
           /  7| 8 \
          / \  |  / \
         /   \ | /   \
        /  6  \|/  9  \
       /-------|-------\
      /|\  5  /|\ 10  /|\
     / | \   / | \   / | \
    /  |  \ /  |  \ /  |  \
   /  1| 2 X 4 |11 X 13|14 \
  / \  |  / \  |  / \  |  / \ ...
 /   \ | /   \ | /   \ | /   \
/  0  \|/  3  \|/  12 \|/  15 \
--------------------------------

The points are on a square grid with integer X,Y. 4 points in each 3x3 block are used. In general a point is used if

X%3==1 or Y%3==1, but not both

which means
((X%3)+(Y%3)) % 2 == 1

Level Ranges

Counting the N=0 to N=3 as level=1, N=0 to N=15 as level 2, etc, the end of each level, back at the X axis, is

Nlevel = 4^level - 1
Xlevel = 3*2^level - 2
Ylevel = 0

For example level=2 is Nend = 2^(2*2)-1 = 15 at X=3*2^2-2 = 10.

The top of each level is half way along,

Ntop = (4^level)/2 - 1
Xtop = 3*2^(level-1) - 1
Ytop = 3*2^(level-1) - 2

For example level=3 is Ntop = 2^(2*3-1)-1 = 31 at X=3*2^(3-1)-1 = 10 and Y=3*2^(3-1)-1 = 11.

The factor of 3 arises because there's a gap between each level, increasing it by a fixed extra each time,

length(level) = 2*length(level-1) + 2
              = 2^level + (2^level + 2^(level-1) + ... + 2)
              = 2^level + (2^(level+1)-1 - 1)
              = 3*2^level - 2

Arms

The optional arms parameter can draw multiple curves, each advancing successively. For example arms => 2,

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

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

The N=0 point is at X=1,Y=0 (in all arms forms) so that the second arm is within the first quadrant.

Anywhere between 1 and 8 arms can be done this way. arms=>8 is as follows.

       ...                       ...           6
        |                          |
       58       34       33       57           5
         \     /  \     /  \     /
...-59    50-42    26 25    41-49    56-...    4
      \           /     \           /
       51       18       17       48           3
        |        |        |        |
       43       10        9       40           2
      /           \     /           \
    35    19-11     2  1     8-16    32        1
      \  /     \           /     \  /
       27        3     .  0       24       <- Y=0

       28        4        7       31          -1
      /  \     /           \     /  \
    36    20-12     5  6    15-23    39       -2
      \           /     \           /
       44       13       14       47          -3
        |        |        |        |
       52       21       22       55          -4
      /           \     /           \
...-60    53-45    29 30    46-54    63-...   -5
         /     \  /     \  /     \
       61       37       38       62          -6
        |                          |
       ...                       ...          -7

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

The middle "." is the origin X=0,Y=0. It'd be more symmetrical to make the origin the middle of the eight arms, at X=-0.5,Y=-0.5 in the above, but that would give fractional X,Y values. Apply an offset as X+0.5,Y+0.5 if desired.

Closed Curve

Sierpinki's original conception was a closed curve filling a unit square by ever greater self-similar detail,

/\_/\ /\_/\ /\_/\ /\_/\
\   / \   / \   / \   /
 | |   | |   | |   | |
/ _ \_/ _ \ / _ \_/ _ \
\/ \   / \/ \/ \   / \/
   |  |         | |
/\_/ _ \_/\ /\_/ _ \_/\
\   / \   / \   / \   /
 | |   | |   | |   | |
/ _ \ / _ \_/ _ \ / _ \
\/ \/ \/ \   / \/ \/ \/
          | |
/\_/\ /\_/ _ \_/\ /\_/\
\   / \   / \   / \   /
 | |   | |   | |   | |
/ _ \_/ _ \ / _ \_/ _ \
\/ \   / \/ \/ \   / \/
   |  |         | |
/\_/ _ \_/\ /\_/ _ \_/\
\   / \   / \   / \   /
 | |   | |   | |   | |
/ _ \ / _ \ / _ \ / _ \
\/ \/ \/ \/ \/ \/ \/ \/

The code here might be pressed into use for this by drawing a mirror image of the curve (N=0 through Nlevel above). Or using the arms=>2 form (N=0 to N=4^level, inclusive), and joining up the ends.

The curve is usually conceived as scaling down by quarters too. The integer steps used here mean it doesn't come out that way as the horizontal and vertical segments are only 1 long not 2. They can be stretched if desired by

X + floor((X-2)/3)
Y + floor((Y-2)/3)

(Perhaps there could be an option for this.)

FUNCTIONS

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

$path = Math::PlanePath::MathImageSierpinskiCurve->new ()
$path = Math::PlanePath::MathImageSierpinskiCurve->new (arms => 8)

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.

SEE ALSO

Math::PlanePath, Math::PlanePath::SierpinskiArrowhead, Math::PlanePath::KochCurve