Drawing the dragon curve

A solution using Plain TeX macros and LaTeX's picture environment (enhanced by pict2e package).

Update adds variant with rounded corners (see end of answer).

Dragon Curve

and this time starting rightwards (animation updated):

Dragon Curve 2

Variant with rounded corners at bottom.

\documentclass[multi=picture,ignorerest=false]{standalone}

% convert -density 150 -verbose -delay 40 -dispose None DG/dragoncurve.* -delay 200 DG/dragoncurve.13.png -loop 0  dragoncurve.gif

\usepackage{pict2e}
\usepackage{color}
\usepackage{picture}

\newcount\X % integer horizontal coordinate
\newcount\Y % integer vertical coordinate

\newdimen\E % initial scale
\E 4cm

\newcount\Iter % iteration level, for displaying
\Iter = 1

\newcount\DeltaX
\newcount\DeltaY
% initial direction for first drawn Dragon curve (has two segments)
\DeltaX = -1
\DeltaY = 1

\let\LL\relax
\let\RR\relax

\def\Dragon {\L}

\def\IterateDragon {\advance\Iter 1
    % adjust initial direction, rotating 45 degrees clockwise
    \count255 = \DeltaX
    \advance\DeltaX by  \DeltaY
    \advance\DeltaY by -\count255
    % adjust scale
    \E = 0.5\E
    % apply rules
    \def\L{\noexpand\L\LL\noexpand\R}%
    \def\R{\noexpand\L\RR\noexpand\R}%
    \edef\Dragon{\Dragon}%
}

% draw one segment in given direction and with current scale
\def\DrawSegment {\advance\X\DeltaX
                  \advance\Y\DeltaY 
                  \lineto(\X,\Y)}

\def\DrawDragon {%
    \setlength{\unitlength}{\E}%
    \begin{picture}(13cm,9cm)(-9.5cm,-3cm)
    \linethickness{1.5pt}%
    \def\L {\count255 = \DeltaX
            \DeltaX = -\DeltaY
            \DeltaY = \count255
            \DrawSegment }%
    \def\R {\count255 = \DeltaX
            \DeltaX = \DeltaY
            \DeltaY = -\count255 
            \DrawSegment }%
    \let\LL\L
    \let\RR\R
    \X = 0
    \Y = 0
    \put(0,0){\textcolor{blue}{\phantom{x}\the\Iter}}
    \moveto(0,0)
    \DrawSegment
    \Dragon
    \strokepath
\end{picture}}

\begin{document}

\ttfamily

\DrawDragon

\IterateDragon
\DrawDragon

\IterateDragon
\DrawDragon

\IterateDragon
\DrawDragon

\IterateDragon
\DrawDragon

\IterateDragon
\DrawDragon

\IterateDragon
\DrawDragon

\IterateDragon
\DrawDragon

\IterateDragon
\DrawDragon

\IterateDragon
\DrawDragon

\IterateDragon
\DrawDragon

% twelfth .. slow

\IterateDragon
\DrawDragon

% thirteenth .... sloooww

\IterateDragon
\DrawDragon

\end{document}

Code variant for rounded corners:

\documentclass[multi=picture,ignorerest=false]{standalone}

% convert -density 75 -verbose -dispose none -delay 100 -- DG3/dragoncurve3.* -delay 200 DG3/dragoncurve3.12.png -loop 0  dragoncurve3.gif

\usepackage{pict2e}
\usepackage{color}
\usepackage{picture}

\newcount\X % integer horizontal coordinate
\newcount\Y % integer vertical coordinate
% for convenience another pair
\newcount\x
\newcount\y

\newdimen\E % initial scale
\E 1cm

\newcount\Iter % iteration level, for displaying
\Iter = 1

\newcount\DeltaX
\newcount\DeltaY
% initial direction for first drawn Dragon curve (has two segments)
% this version goes rightward 
\DeltaX = 1
\DeltaY = -1

% for convenience another pair
\newcount\deltax
\newcount\deltay

% (the first iterate goes down then up, thus turning left).
\def\Dragon {\L}


\def\IterMode {%
    \let\LL\relax
    \let\RR\relax
    %
    \def\L{\noexpand\L\LL\noexpand\R}%
    \def\R{\noexpand\L\RR\noexpand\R}%
}

\def\DrawMode {%
    \def\L {\deltax = -\DeltaY
            \deltay = \DeltaX
            \DrawArc
           }%
    \def\R {\deltax = \DeltaY
            \deltay = -\DeltaX 
            \DrawArc 
            }%
    \let\LL\L
    \let\RR\R
}

\def\DrawArc {%
            \x\numexpr \X + 2*\DeltaX + 2*\deltax\relax
            \y\numexpr \Y + 2*\DeltaY + 2*\deltay\relax
            \curveto
               (\numexpr\X+\DeltaX\relax,\numexpr\Y+\DeltaY\relax)%
               (\numexpr\x-\deltax\relax,\numexpr\y-\deltay\relax)%
               (\x,\y)%
            \X\x
            \Y\y
            \DeltaX\deltax
            \DeltaY\deltay
           }%


\def\IterateDragon {%
    \global\advance\Iter 1
    % adjust initial direction, rotating 45 degrees clockwise
    \count255 = \DeltaX
    \global\advance\DeltaX by  \DeltaY
    \global\advance\DeltaY by -\count255
    % adjust scale
    \global\E = 0.5\E
    % apply rules and modify \Dragon globally
    \IterMode
    \xdef\Dragon{\Dragon}%
}


\def\DrawDragonPath #1{%
    \linethickness{#1}%
    \ifodd\Iter\color{red}\else\color{blue}\fi
    \moveto(0,0)
    \X\numexpr2*\DeltaX\relax
    \Y\numexpr2*\DeltaY\relax
    \lineto(\X,\Y)
    \DrawMode
    \Dragon
    \X\numexpr\X+2*\DeltaX\relax
    \Y\numexpr\Y+2*\DeltaY\relax
    \lineto(\X,\Y)
    \strokepath
}%

\def\DrawOneDragon #1{%
    \setlength{\unitlength}{\E}%
    \begin{picture}(12.35cm,8.6cm)(-2.85cm,-5.6cm)
      \DrawDragonPath {#1}%
      \put(0,0){\llap{\the\Iter\phantom{x}}}%
    \end{picture}%
}

\def\DrawTwoDragons {% draws AND iterates once to get next curve too.
    \setlength{\unitlength}{\E}%
    \begin{picture}(12.35cm,8.6cm)(-2.85cm,-5.6cm)
% je fais ça vite fait, car avec convert je n'ai pas vu comment avoir deux 
% rémanences, donc on fait deux dessins ici.
% we store initial direction: 
\count2=\DeltaX
\count4=\DeltaY
      \DrawDragonPath {1pt}%
% restore initial direction (which will be rotated 45° by \IterateDragon)
\DeltaX \count2
\DeltaY \count4
      \IterateDragon % does \IterMode, makes global changes to \Dragon etc...
% compensate (only in this picture) for scale being left the same.
\divide\DeltaX by 2
\divide\DeltaY by 2
      \DrawDragonPath {1.5pt}%
      \put(0,0){\llap{\the\Iter\phantom{x}}}%
    \end{picture}%
}

\begin{document}

\ttfamily

\DrawOneDragon {1.5pt}%1

\DrawTwoDragons %2

\DrawTwoDragons %3

\DrawTwoDragons %4

\DrawTwoDragons %5

\DrawTwoDragons %6

\DrawTwoDragons %7

\DrawTwoDragons %8

\DrawTwoDragons %9

\DrawTwoDragons %10

\DrawTwoDragons %11

\DrawOneDragon {1pt}%

\end{document}

Dragon Curve 3


As a Lindenmayer system, the dragon curve can be presented by

angle 90°
initial string FX
string rewriting rules
    X ↦ X+YF+
    Y ↦ −FX−Y.

so we have a simple TikZ solution using lindenmayersystems library:

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{lindenmayersystems}

\begin{document}

\fbox{%
\tikz[rotate=65]
\draw[green!60!black] 
  l-system
  [l-system={
    rule set={X -> X+YF+,Y->-FX-Y},
    axiom=FX, 
    angle=90,
    order=12, 
    step=5pt
    }
  ];
}

\end{document}

enter image description here

Changing to order=14 and reducing the step to 2pt gives:

enter image description here

And my computer reports pretty decent times:

real    0m48.379s
user    0m46.404s
sys     0m0.120s

However, order=15 already produces the dreadful TeX capacity exceeded! error.

A little beamer animation up to order 12:

\documentclass{beamer}
\usepackage{tikz}
\usetikzlibrary{lindenmayersystems}

\begin{document}

\begin{frame}
\centering
\tikz
\foreach \Valor in {1,2,...,12}
\draw<\Valor>[green!60!black] 
  l-system
  [l-system={
    rule set={X -> X+YF+,Y->-FX-Y},
    axiom=FX, 
    angle=90,
    order=\Valor, 
    step=3pt
    }
  ];
\end{frame}

\end{document}

enter image description here

Rounded version

The rounded version is obtained simply by adding rounded corners=<length> to the options for the \draw; a little example of order 11:

\documentclass[border=3pt]{standalone}
\usepackage{tikz}
\usetikzlibrary{lindenmayersystems}

\begin{document}

\tikz
\draw[green!60!black,rounded corners=4pt] 
  l-system
  [l-system={
    rule set={X -> X+YF+,Y->-FX-Y},
    axiom=FX, 
    angle=90,
    order=11, 
    step=10pt
    }
  ];

\end{document}

The result:

enter image description here

Twindragon

The Davis-Knuth dragon can also be easily obtained:

\documentclass[tikz,border=3pt]{standalone}
\usetikzlibrary{lindenmayersystems}

\begin{document}

\tikz\draw[line width=1pt,green!60!black,rounded corners] 
  l-system
  [l-system={
    rule set={X -> X+YF,Y->FX-Y},
    axiom=FX+FX+, 
    angle=90,
    order=12, 
    step=10pt
    }
  ];

\end{document}

enter image description here


Here is one implementation, using PSTricks.

The sequence is generated via repetitive string replacements using xstring's \StrSubstitute:

enter image description here

\documentclass{article}
\usepackage[paper=a3paper,landscape,margin=0pt]{geometry}
\usepackage{etoolbox,pstricks,xstring,multido}
\pagestyle{empty}
\begin{document}

\begin{pspicture}(-25cm,-10cm)(10cm,7cm)
  \psset{unit=5mm}
  \SpecialCoor

  \def\dragoncurve{L,1R}% Starting fold
  \multido{\i=0+1}{10}{% Add 10 more folds
    % Add fold
    \StrSubstitute{\dragoncurve}{L}{L,1P}[\dragoncurve]% L -> L1P
    \StrSubstitute{\dragoncurve}{R}{L,0R}[\dragoncurve]% R -> L0R
    \StrSubstitute{\dragoncurve}{P}{R}[\dragoncurve]% P -> R
    \xdef\dragoncurve{\dragoncurve}% Make definition global
  }

  \StrSubstitute{\dragoncurve}{L}{}[\dragoncurve]% Drop L
  \StrSubstitute{\dragoncurve}{R}{}[\dragoncurve]% Drop R
  \StrSubstitute[1]{\dragoncurve}{,}{}[\dragoncurve]% Drop first ,
  \def\nextangle{0}% Starting angle
  \pscustom[linewidth=.1pt]{
    \psline(0,0)% Initial node
    \renewcommand{\do}[1]{
      \rlineto(1;\nextangle)% Draw next line
      \xdef\nextangle{\number\numexpr\nextangle+\ifnum#1=1 (-90)\else (90)\fi}
    }%
    \expandafter\docsvlist\expandafter{\dragoncurve}% Process dragon curve
    \rlineto(1;\nextangle)% Draw final line
  }
\end{pspicture}

\end{document}

The production is only limited by TeX's memory. With the default settings, perhaps 12 folds can be made (compiling for a very long time, and having to use a very large paper size or adjustments to the unit and/or runit).

Tags:

Diagrams