% Copyright 2008 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.

\newdimen\pgflsystemstep
\newcount\c@pgf@lsystem@iteration

\newif\ifpgf@lsystem@randomize@step
\newif\ifpgf@lsystem@randomize@angle

\pgfkeys{/pgf/lindenmayer system/.cd,%
	step/.code={\pgfmathsetlength\pgflsystemstep{#1}},%
	randomize step percent/.code={%
		\pgfmathparse{#1}%
		\let\pgflsystemrandomizesteppercent=\pgfmathresult%
		\ifdim\pgfmathresult pt=0pt\relax%
			\pgf@lsystem@randomize@stepfalse%
		\else%
			\pgf@lsystem@randomize@steptrue%
		\fi%
	},%
	left angle/.code={\pgfmathparse{#1}\let\pgflsystemleftangle=\pgfmathresult},%
	right angle/.code={\pgfmathparse{#1}\let\pgflsystemrightangle=\pgfmathresult},%
	angle/.style={/pgf/lindenmayer system/left angle=#1, /pgf/lindenmayer system/right angle=#1},%
	randomize angle percent/.code={%
		\pgfmathparse{#1}%
		\let\pgflsystemrandomizeanglepercent=\pgfmathresult%
		\ifdim\pgfmathresult pt=0pt\relax%
			\pgf@lsystem@randomize@anglefalse%
		\else%
			\pgf@lsystem@randomize@angletrue%
		\fi%
	}%
}

\pgfkeys{/pgf/lindenmayer system/.cd,
	step=5pt,%
	randomize step percent=0,%
	angle=90,%
	randomize angle percent=0%
}

\long\def\pgfdeclarelindenmayersystem#1#2{%
	\pgfutil@ifundefined{pgf@lsystem@#1}%
		{%
			\begingroup%
				\edef\pgf@lsystem@name{#1}%
				\expandafter\global\expandafter\let\csname pgf@lsystem@#1\endcsname=\pgf@lsystem@name%
				\let\symbol=\pgf@lsystem@symbol%
				\let\rule=\pgf@lsystem@rule%
				#2%
			\endgroup%
		}%
		{\pgferror{Lindenmayer system `#1' is already defined}}%
}

\def\pgf@lsystem@symbol#1#2{%
	\expandafter\gdef\csname pgf@lsystem@\pgf@lsystem@name @symbol@#1\endcsname{#2}%
}

\def\pgf@lsystem@rule#1{\expandafter\pgf@lsystem@rule@#1\pgf@stop}
\def\pgf@lsystem@rule@#1{\def\pgf@lsystem@rule@head{#1}\pgf@lsystem@rule@@}
\def\pgf@lsystem@rule@@#1->{% Now some `fooling around' to deal with unwanted spaces.
	\let\pgf@lsystem@rule@body=\pgfutil@empty%
	\pgfutil@ifnextchar x{\pgf@lsystem@rule@@@}{\pgf@lsystem@rule@@@}}
\def\pgf@lsystem@rule@@@#1{%
	\ifx#1\pgf@stop%
		\expandafter\global\expandafter\let%
			\csname pgf@lsystem@\pgf@lsystem@name @rule@\pgf@lsystem@rule@head\endcsname=\pgf@lsystem@rule@body%
	\else%
		\edef\pgf@lsystem@rule@body{\pgf@lsystem@rule@body#1}%
		\expandafter\pgf@lsystem@rule@@@%
	\fi%
}

\def\pgflindenmayersystem#1#2#3{%
	\begingroup%
		\edef\pgf@lsystem@name{#1}%
		\edef\pgf@lsystem@axiom{#2}%
		\pgfmathtruncatemacro\pgf@lsystem@order{#3}%
		%
		\let\pgf@lsystem@current@symbol=\relax%
		%
		\c@pgf@lsystem@iteration=0\relax%
		%
		\ifnum\pgf@lsystem@order=0\relax%
			\expandafter\pgf@lsystem@draw\pgf@lsystem@axiom\pgf@stop
			\let\pgf@lsystem@next=\pgf@lsystem@end%
		\else%
			\let\pgf@lsystem@next=\pgf@lsystem@run%		
		\fi%
		\expandafter\pgf@lsystem@next\pgf@lsystem@axiom\pgf@lsystem@stop%
}

\def\pgf@lsystem@run#1{%
	\ifx#1\pgf@lsystem@stop%
		\def\pgf@lsystem@token{\pgf@lsystem@stop}%
		\let\pgf@lsystem@next=\pgf@lsystem@end%
	\else%
		\ifx#1\pgf@stop%
			\advance\c@pgf@lsystem@iteration by-1\relax%
			\let\pgf@system@token=\pgfutil@empty%
			\let\pgf@lsystem@next=\pgf@lsystem@run%
		\else%
			% Does #1 appear on the RHS of a rule...?
			\expandafter\let\expandafter\pgf@lsystem@token\expandafter=%
				\csname pgf@lsystem@\pgf@lsystem@name @rule@#1\endcsname%				
			\ifx\pgf@lsystem@token\relax%
				% ...nope. So draw it straight away.
				\pgf@lsystem@draw#1\pgf@stop%
				\let\pgf@lsystem@token=\pgfutil@empty%				
			\else%
				% ...yep. So, if the order has been reached draw the LHS 
				% immediately. Otherwise add the LHS to the token stream
				% and continue.
				\advance\c@pgf@lsystem@iteration by1\relax%
				\ifnum\c@pgf@lsystem@iteration=\pgf@lsystem@order%
					\expandafter\pgf@lsystem@draw\pgf@lsystem@token \pgf@stop%
					\advance\c@pgf@lsystem@iteration by-1\relax%
					\let\pgf@lsystem@token=\pgfutil@empty%
				\else%
					\expandafter\def\expandafter\pgf@lsystem@token\expandafter{\pgf@lsystem@token \pgf@stop}%
				\fi%
			\fi%
			\let\pgf@lsystem@next=\pgf@lsystem@run%
		\fi%
	\fi%
	\expandafter\pgf@lsystem@next\pgf@lsystem@token}

\def\pgf@lsystem@end#1\pgf@lsystem@stop{\endgroup}

\def\pgf@lsystem@draw#1{%
	\ifx#1\pgf@stop%
		\let\pgf@lsystem@next=\relax%
	\else%
		\expandafter\let\expandafter\pgf@lsystem@current@symbol\expandafter=%
			\csname pgf@lsystem@\pgf@lsystem@name @symbol@#1\endcsname%
		\ifx\pgf@lsystem@current@symbol\relax% Try a default symbol.
			\expandafter\let\expandafter\pgf@lsystem@current@symbol\expandafter=%
				\csname pgf@lsystem@symbol@default@#1\endcsname%
		\fi%
		\let\pgf@lsystem@next=\pgf@lsystem@@draw%
	\fi%
	\pgf@lsystem@next}

\def\pgf@lsystem@@draw{%
	\edef\pgflsystemcurrentstep{\the\pgflsystemstep}%
	\let\pgflsystemcurrentrightangle=\pgflsystemrightangle%
	\let\pgflsystemcurrentrightangle=\pgflsystemleftangle%
	\pgf@lsystem@current@symbol%
	\pgf@lsystem@draw}

\expandafter\def\csname	pgf@lsystem@symbol@default@F\endcsname{\pgflsystemdrawforward}
\expandafter\def\csname	pgf@lsystem@symbol@default@f\endcsname{\pgflsystemmoveforward}
\expandafter\def\csname	pgf@lsystem@symbol@default@+\endcsname{\pgflsystemturnleft}
\expandafter\def\csname	pgf@lsystem@symbol@default@-\endcsname{\pgflsystemturnright}
\expandafter\def\csname	pgf@lsystem@symbol@default@[\endcsname{\pgflsystemsavestate}
\expandafter\def\csname	pgf@lsystem@symbol@default@]\endcsname{\pgflsystemrestorestate}

\def\pgflsystemradonmizestep{%
	\ifpgf@lsystem@randomize@step%
		\pgfmathrand%
		\pgf@x=\pgflsystemrandomizesteppercent pt\relax%
		\pgf@x=\pgfmathresult\pgf@x%
		\divide\pgf@x by20\relax%
		\advance\pgf@x by\pgflsystemstep\relax%
		\edef\pgflsystemcurrentstep{\the\pgf@x}%
	\else%
		\edef\pgflsystemcurrentstep{\the\pgflsystemstep}%
	\fi%
}

\def\pgflsystemdrawforward{%
	\pgflsystemradonmizestep
	\pgftransformxshift{+\pgflsystemcurrentstep}%
	\pgfpathlineto{\pgfpointorigin}}

\def\pgflsystemmoveforward{%
	\pgflsystemradonmizestep
	\pgftransformxshift{+\pgflsystemcurrentstep}%
	\pgfpathmoveto{\pgfpointorigin}}

\def\pgflsystemranomizerightangle{%
	\ifpgf@lsystem@randomize@angle%
		\pgf@x=\pgflsystemrandomizeanglepercent pt\relax%
		\divide\pgf@x by20\relax%
		\pgfmathrand%
		\pgf@x=\pgfmathresult\pgf@x%
		\advance\pgf@x by\pgflsystemrightangle pt\relax%
		\edef\pgflsystemcurrentrightangle{\pgfmath@tonumber{\pgf@x}}%
	\else%
		\let\pgflsystemcurrentrightangle=\pgflsystemrightangle%
	\fi%
}

\def\pgflsystemranomizeleftangle{%
	\ifpgf@lsystem@randomize@angle%
		\pgf@x=\pgflsystemrandomizeanglepercent pt\relax%
		\divide\pgf@x by20\relax%
		\pgfmathrand%
		\pgf@x=\pgfmathresult\pgf@x%
		\advance\pgf@x by\pgflsystemleftangle pt\relax%
		\edef\pgflsystemcurrentleftangle{\pgfmath@tonumber{\pgf@x}}%
	\else%
		\let\pgflsystemcurrentleftangle=\pgflsystemleftangle%
	\fi%
}

\def\pgflsystemturnright{%
	\pgflsystemranomizerightangle
	\pgftransformrotate{-\pgflsystemcurrentrightangle}}

\def\pgflsystemturnleft{%
	\pgflsystemranomizeleftangle
	\pgftransformrotate{\pgflsystemcurrentleftangle}}

\def\pgflsystemsavestate{\begingroup}
\def\pgflsystemrestorestate{\endgroup\pgfpathmoveto{\pgfpointorigin}}
