Fractal Curves via Iteration

Preliminary nonsense

Off[General::spell]
Off[General::spell1]
SetOptions[Graphics, AspectRatio -> Automatic, 
        PlotRange -> All];

Some linear algebra in (R^2)

\(Rot[θ]\ is\ a\ matrix\ which\ rotates\ a\ vector\ by\ angle\ θ\ \((measured\ in\ \(radians!\))\)\)

Rot[θ_] := {{Cos[θ], -Sin[θ]}, {Sin[θ], 
          Cos[θ]}}
Orthog  :=  Rot[π/2]

Similarity[{P,Q}] is the (orientation-preserving) similarity of the plane that takes {0,0} to P and {1,0} to Q

Similarity[{P_, Q_}][V_] := 
      P  +  V . {Q - P, Orthog . (Q - P)}

Drawing Function

DrawSegs takes a list of pairs of points, and draws the segments connecting them.

DrawSegs[segmentlist_] := 
      Show[Graphics[Line  /@  segmentlist]]

The generating rule

(Modify this section first to draw other fractals!)

First we make a list of segments in the model, i.e. the result of applying the iteration to the interval [0,1] on the X axis.  In this case, we use a "roof" with angle ϕ.

ϕ = 0.6

Model  =  {    { {0, 
            0},  {1/2,  (1/2) Tan[ϕ]} },   { {1/
              2,  (1/2) Tan[ϕ]},  {1, 0} }    }

DrawSegs[Model]

Iteration

Now we create a function F which does the same to an arbitrary segment, by applying a similarity transformation to the model.  The Map command (see online help) is needed so that the Similarity function is applied to points (rather than the segments, which it doesn't know how to handle).

F[segment_] := Map[Similarity[segment] , Model, {2}]

The Iterate function takes a list of segments and applies F to each of them, returning a new list of segments.

Iterate[segmentlist_] := Flatten[F /@ segmentlist, 1]

Result

The initial segment.

Initiator  =  {    { {0, 0},  {1, 
            0} }    }
DrawSegs[Initiator]

Generation 3 (produced using the Nest command -- see online help)

DrawSegs[Nest[Iterate, Initiator, 3]]

Generation 12 is a good approximation to the actual fractal object  (this may take a little while to compute)

DrawSegs[Nest[Iterate, Initiator, 12]]

Unfortunately, the "curve" became self-intersecting!

More Examples

Using the functions above, it is easy to apply the iteration to other starting configurations:

This double segment goes "back and forth" over the unit segment, so that one iteration is drawn above it, and one below.

DoubleSeg  =  { { {0, 0}, {1, 0} },  { {1, 0},  {0, 
            0} } }
DrawSegs[DoubleSeg]
DrawSegs[Nest[Iterate, DoubleSeg, 10]]

This function creates an initiator which is a regular n-gon.

RegularNGon[n_]  :=  
      Partition[({Re[#], Im[#]}) &  /@  
          Table[E^(2  π I k/n), {k, 0, Abs[n]}], 2, 1]

Pentagon  =  RegularNGon[5];

DrawSegs[Pentagon]
DrawSegs[Nest[Iterate, Pentagon, 10]]

(It's a flower!)

If we make n negative, the orientation is reversed, and the iteration is done on the outside rather than the inside.

Pentagon2  =  RegularNGon[-5];

DrawSegs[Pentagon2]
DrawSegs[Nest[Iterate, Pentagon2, 10]]

It's a cauliflower!