1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390
|
% Copyright 2019 by Mark Wibrow
%
% This file may be distributed and/or modified
%
% 1. under the LaTeX Project Public License and/or
% 2. under the GNU Public License.
%
% See the file doc/generic/pgf/licenses/LICENSE for more details.
\section{Lindenmayer System Drawing Library}
\subsection{Overview}
Lindenmayer systems (also commonly known as ``L-systems''), were originally
developed by Aristid Lindenmayer as a theory of algae growth patterns and then
subsequently used to model branching patterns in plants and produce fractal
patterns. Typically, an L-system consists of a set of symbols, each of which is
associated with some graphical action (such as ``turn left'' or ``move
forward'') and a set of rules (``production'' or ``rewrite'' rules). Given a
string of symbols, the rewrite rules are applied several times and when the
resulting string is processed the action associated with each symbol is
executed.
In \pgfname, L-systems can be used to create simple 2-dimensional fractal
patterns\ldots
%
\begin{codeexample}[
preamble={\usetikzlibrary{lindenmayersystems}},
pre={\expandafter\let\csname pgf@lsystem@Koch curve\endcsname=\relax},
]
\begin{tikzpicture}
\pgfdeclarelindenmayersystem{Koch curve}{
\rule{F -> F-F++F-F}
}
\shadedraw [top color=white, bottom color=blue!50, draw=blue!50!black]
[l-system={Koch curve, step=2pt, angle=60, axiom=F++F++F, order=3}]
lindenmayer system -- cycle;
\end{tikzpicture}
\end{codeexample}
%
\noindent\ldots and ``plant like'' patterns\ldots
%
\begin{codeexample}[preamble={\usetikzlibrary{lindenmayersystems}}]
\begin{tikzpicture}
\draw [green!50!black, rotate=90]
[l-system={rule set={F -> FF-[-F+F]+[+F-F]}, axiom=F, order=4, step=2pt,
randomize step percent=25, angle=30, randomize angle percent=5}]
lindenmayer system;
\end{tikzpicture}
\end{codeexample}
%
\noindent \ldots but it is important to bear in mind that even moderately
complex L-systems can exceed the available memory of \TeX, and can be very
slow. If possible, you are advised to increase the main memory and save stack
to their maximum possible values for your particular \TeX{} distribution.
However, even by doing this you may find you still run out of memory quite
quickly.
For an excellent introduction to L-systems (containing some ``really cool''
pictures -- many of which are sadly not possible in \pgfname) see \emph{The
Algorithmic Beauty of Plants} by Przemyslaw Prusinkiewicz and Aristid
Lindenmayer (which is freely available via the internet).
\begin{pgflibrary}{lindenmayersystems}
This \pgfname-library provides basic commands for defining and using simple
L-systems. The \tikzname-library provides, furthermore, a front end for
using L-systems in \tikzname.
\end{pgflibrary}
\subsubsection{Declaring L-systems}
Before an L-system can be used, it must be declared using the following
command:
\begin{command}{\pgfdeclarelindenmayersystem\marg{name}\marg{specification}}
This command declares a Lindenmayer system called \meta{name}. The
\meta{specification} argument contains a description of the L-system's
symbols and rules. Two commands |\symbol| and |\rule| are only defined when
the \meta{specification} argument is executed.
\begin{command}{\symbol\marg{name}\marg{code}}
This defines a symbol called \meta{name} for a specific L-system,
and associates it with \meta{code}.
A symbol should consist of a single alpha-numeric character (i.e.,
|A|-|Z|, |a|-|z| or |0|-|9|). The symbols |F|, |f|, |+|, |-|, |[| and
|]| are available by default so do not need to be defined for each
L-system. However, if you are feeling adventurous, they can be
redefined for specific L-systems if required. The L-system treats the
default symbols as follows (the commands they execute are described
below):
%
\begin{itemize}
\item |F| move forward a certain distance, drawing a line. Uses
|\pgflsystemdrawforward|.
\item |f| move forward a certain distance, without drawing a line.
Uses |\pgflsystemmoveforward|.
\item |+| turn left by some angle. Uses |\pgflsystemturnleft|.
\item |-| turn right by some angle. Uses |\pgflsystemturnright|.
\item |[| save the current state (i.e., the position and
direction). Uses |\pgflsystemsavestate|.
\item |]| restore the last saved state. Uses
|\pgflsystemrestorestate|.
\end{itemize}
The symbols |[| and |]| act like a stack: |[| pushes the state of the
L-system on to the stack, and |]| pops a state off the stack.
When \meta{code} is executed, the transformation matrix is set up so
that the origin is at the current position and the positive x-axis
``points forward'', so |\pgfpathlineto{\pgfpoint{1cm}{0cm}}| draws a
line 1cm forward.
The following keys can alter the production of an L-system. However,
they do not store values in themselves.
\begin{key}{/pgf/lindenmayer system/step=\meta{length} (initially 5pt)}
How far the L-system moves forward if required. This key sets the
\TeX{} dimension |\pgflsystemstep|.
\end{key}
\begin{key}{/pgf/lindenmayer system/randomize step percent=\meta{percentage} (initially 0)}
If the step is to be randomized, this key specifies by how much.
The value is stored in the \TeX{} macro
|\pgflsystemrandomizesteppercent|.
\end{key}
\begin{key}{/pgf/lindenmayer system/left angle=\meta{angle} (initially 90)}
This key sets the angle through which the L-system turns when it
turns left. The value is stored in the \TeX{} macro
|\pgflsystemrleftangle|.
\end{key}
\begin{key}{/pgf/lindenmayer system/right angle=\meta{angle} (initially 90)}
This key sets the angle through which the L-system turns when it
turns right. The value is stored in the \TeX{} macro
|\pgflsystemrrightangle|.
\end{key}
\begin{key}{/pgf/lindenmayer system/randomize angle percent=\meta{percentage} (initially 0)}
If the angles are to be randomized, this key specifies by how much.
The value is stored in the \TeX{} macro
|\pgflsystemrandomizeanglepercent|.
\end{key}
For speed and convenience, when the code for a symbol is executed, the
following commands are available.
\begin{command}{\pgflsystemcurrentstep}
The current ``step'' of the L-system (i.e., how far the system
will move forward if required). This is initially set to the
value in the \TeX-dimensions |\pgflsystemstep|, but the actual
value may be changed if |\pgflsystemrandomizestep| is used
(see below).
\end{command}
\begin{command}{\pgflsystemcurrentleftangle}
The angle the L-system will turn when it turns left.
The value stored in this macro may be changed if
|\pgflsystemrandomizeleftangle| is used.
\end{command}
\begin{command}{\pgflsystemcurrentrightangle}
The angle the L-system will turn when it turns right.
The value stored in this macro may be changed if
|\pgflsystemrandomizerightangle| is used.
\end{command}
The following commands may be useful if you wish to define your own
symbols.
\begin{command}{\pgflsystemrandomizestep}
Randomizes the value in |\pgflsystemcurrentstep| according to the
current value of the key |randomize step percent|.
\end{command}
\begin{command}{\pgflsystemrandomizeleftangle}
Randomizes the value in |\pgflsystemcurrentleftangle| according to
the value of the |randomize angle percent| key.
\end{command}
\begin{command}{\pgflsystemrandomizerightangle}
Randomizes the value in |\pgflsystemcurrentrightangle| according
to the value of the |randomize angle| key.
\end{command}
\begin{command}{\pgflsystemdrawforward}
Move forward in the current direction, by |\pgflsystemcurrentstep|,
drawing a line in the process. This macro calls
|\pgflsystemrandomizestep|. Internally, \pgfname{} simply shifts
the transformation matrix in the positive direction of the current
(transformed) x-axis by |\pgflsystemstep| and then executes a
line-to to the (newly transformed) origin.
\end{command}
\begin{command}{\pgflsystemmoveforward}
Move forward in the current direction, by |\pgflsystemcurrentstep|,
without drawing a line. This macro calls
|\pgflsystemrandomizestep|. \pgfname{} executes a transformation as
above, but executes a move-to to the (newly transformed) origin.
\end{command}
\begin{command}{\pgflsystemturnleft}
Turn left by |\pgflsystemcurrentleftangle|. Internally, \pgfname{}
simply rotates the transformation matrix. This macro calls
|\pgflsystemrandomizeleftangle|.
\end{command}
\begin{command}{\pgflsystemturnright}
Turn right by |\pgflsystemcurrentrightangle|. Internally,
\pgfname{} simply rotates the transformation matrix. This macro
calls |\pgflsystemrandomizerightangle|.
\end{command}
\begin{command}{\pgflsystemsavestate}
Save the current position and orientation. Internally, \pgfname{}
simply starts a new \TeX-group.
\end{command}
\begin{command}{\pgflsystemrestorestate}
Restore the last saved position and orientation. Internally,
\pgfname{} closes a \TeX-group, restoring the transformation matrix
of the outer scope, and a move-to command is executed to the
(transformed) origin.
\end{command}
\end{command}
\begin{command}{\rule{\ttfamily\char`\{}\meta{head}{\ttfamily->}\meta{body}{\ttfamily\char`\}}}
Declare a rule. \meta{head} should consist of a single symbol, which
need not have been declared using |\symbol| or exist as a default
symbol (in fact, the more interesting L-systems depend on using symbols
with no corresponding code, to control the ``growth'' of the system).
\meta{body} consists of a string of symbols, which again need not
necessarily have any code associated with them.
\end{command}
As an example, the following shows an L-system that uses some of these
commands. This example illustrates the point that some symbols, in this
case |A| and |B|, do not have to have code associated with them. They
simply control the growth of the system.
%
\begin{codeexample}[
preamble={\usetikzlibrary{lindenmayersystems}},
pre={\nullfont\expandafter\let\csname pgf@lsystem@Hilbert curve\endcsname=\relax},
]
\pgfdeclarelindenmayersystem{Hilbert curve}{
\symbol{X}{\pgflsystemdrawforward}
\symbol{+}{\pgflsystemturnright} % Explicitly define + and - symbols.
\symbol{-}{\pgflsystemturnleft}
\rule{A -> +BX-AXA-XB+}
\rule{B -> -AX+BXB+XA-}
}
\tikz\draw[lindenmayer system={Hilbert curve, axiom=A, order=4, angle=90}]
lindenmayer system;
\end{codeexample}
%
\end{command}
\subsection{Using Lindenmayer Systems}
\subsubsection{Using L-Systems in PGF}
The following command is used to run an L-system in \pgfname:
%
\begin{command}{\pgflindenmayersystem\marg{name}\marg{axiom}\marg{order}}
Runs the L-system called \meta{name} using the input string \meta{axiom}
for \meta{order} iterations. In general, prior to calling this command, the
transformation matrix should be set appropriately for shifting and
rotating, and a move-to to the (transformed) origin should be executed.
This origin will be where the L-system starts. In addition, the relevant
keys should be set appropriately.
%
\begin{codeexample}[preamble={\usetikzlibrary{lindenmayersystems}}]
\begin{tikzpicture}
\draw [help lines] grid (3,2);
\pgfset{lindenmayer system/.cd, angle=60, step=2pt}
\foreach \x/\y in {0cm/1cm, 1.5cm/1.5cm, 2.5cm/0.5cm, 1cm/0cm}{
\pgftransformshift{\pgfqpoint{\x}{\y}}
\pgfpathmoveto{\pgfpointorigin}
\pgflindenmayersystem{Koch curve}{F++F++F}{2}
\pgfusepath{stroke}
}
\end{tikzpicture}
\end{codeexample}
Note that it is perfectly feasible for an L-system to define special
symbols which perform the move-to and use-path operations.
%
\end{command}
\subsubsection{Using L-Systems in Ti\emph{k}Z}
In \tikzname, an L-system is created using a path operation. However,
\tikzname{} is more flexible regarding the positioning of the L-system and also
provides keys to create L-systems ``on-line''.
\begin{pathoperation}{lindenmayer system}{ \opt{|[|\meta{keys}|]|}}
This will run an L-system according to the parameters specified in
\meta{keys} (which can also contain normal \tikz{} keys such as |draw| or
|thin|). The syntax is flexible regarding the L-system parameters and the
following all do the same thing:
%
\begin{codeexample}[code only]
\draw lindenmayer system [lindenmayer system={Hilbert curve, axiom=4, order=3}];
\end{codeexample}
\begin{codeexample}[code only]
\draw [lindenmayer system={Hilbert curve, axiom=4, order=3}] lindenmayer system;
\end{codeexample}
\begin{codeexample}[code only]
\tikzset{lindenmayer system={Hilbert curve, axiom=4, order=3}}
\draw lindenmayer system;
\end{codeexample}
%
\end{pathoperation}
\begin{pathoperation}{l-system}{ \opt{|[|\meta{keys}|]|}}
A more compact version of the |lindenmayer system| path command.
\end{pathoperation}
This library adds some additional keys for specifying L-systems. These keys
only work in \tikzname{} and all have the same path, namely, |/pgf/lindenmayer|
|system|, but the following keys are provided for convenience, so that you do
not have to keep repeating this path:
\begin{stylekey}{/pgf/lindenmayer system=\marg{keys}}
\keyalias{tikz}
This key changes the key path to |/pgf/lindenmayer systems| and executes
\meta{keys}.
\end{stylekey}
\begin{stylekey}{/pgf/l-system=\marg{keys}}
\keyalias{tikz}
A more compact version of the previous key.
\end{stylekey}
\begin{key}{/pgf/lindenmayer system/name=\marg{name}}
Sets the name for the L-system.
\end{key}
\begin{key}{/pgf/lindenmayer system/axiom=\marg{string}}
Sets the axiom (or input string) for the L-system.
\end{key}
\begin{key}{/pgf/lindenmayer system/order=\marg{integer}}
Sets the number of iterations the L-system will perform.
\end{key}
\begin{key}{/pgf/lindenmayer system/rule set=\marg{list}}
This key allows an (anonymous) L-system to be declared ``on-line''. There
is, however, a restriction that only the default symbols can be used for
drawing (empty symbols can still be used to control the growth of the
system). The rules in \meta{list} should be separated by commas.
%
\begin{codeexample}[preamble={\usetikzlibrary{lindenmayersystems}}]
\tikz[rotate=65]\draw [green!60!black] l-system
[l-system={rule set={F -> F[+F]F[-F]}, axiom=F, order=4, angle=25,step=3pt}];
\end{codeexample}
%
\end{key}
\begin{key}{/pgf/lindenmayer system/anchor=\meta{anchor}}
Be default, when this key is not used, the L-system will start from the
last specified coordinate. By using this key, the L-system will be placed
inside a special (rectangle) node which can be positioned using
\meta{anchor}.
%
\begin{codeexample}[preamble={\usetikzlibrary{lindenmayersystems}}]
\begin{tikzpicture}[l-system={step=1.75pt, order=5, angle=60}]
\pgfdeclarelindenmayersystem{Sierpinski triangle}{
\symbol{X}{\pgflsystemdrawforward}
\symbol{Y}{\pgflsystemdrawforward}
\rule{X -> Y-X-Y}
\rule{Y -> X+Y+X}
}
\draw [help lines] grid (3,2);
\draw [red] (0,0) l-system
[l-system={Sierpinski triangle, axiom=+++X, anchor=south west}];
\draw [blue] (3,2) l-system
[l-system={Sierpinski triangle, axiom=X, anchor=north east}];
\end{tikzpicture}
\end{codeexample}
%
\end{key}
|