Current File : //usr/share/texlive/texmf-dist/tex/generic/pgf/modules/pgfmodulesnakes.code.tex |
% Copyright 2019 by Till Tantau
%
% 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.
\ProvidesFileRCS{pgfmodulesnakes.code.tex}
\pgfwarning{Snakes have been superseded by decorations. Use the module decorations instead of snakes}
\usepgfmodule{decorations}%
\endinput
\newdimen\pgfsnakeremainingdistance
\newdimen\pgfsnakecompleteddistance
% Creates a new pgf snake
%
% #1 = snake name
% #1 = initial state
% #3 = states of the snake
%
%
% This command declares a new snake for later use. The second
% parameter specifies the states of the snake, see also the
% description of pgfpathsnake.
%
% Inside the code of #3 the command \state may be used. This command
% will only be defined while #3 is executed.
%
% Example:
%
% \pgfdeclaresnake{zig zag}{one zig zag}
% {
% \state{one zig zag}[width=10pt]
% {
% \pgfpathlineto{\pgfpoint{2.5pt}{2.5pt}}
% \pgfpathlineto{\pgfpoint{7.5pt}{-2.5pt}}
% \pgfpathlineto{\pgfpoint{10pt}{0pt}}
% }
% \state{final}
% {
% \pgfpathlineto{\pgfpoint{\pgfsnakeremainingdistance}{0pt}}
% }
% }
\long\def\pgfdeclaresnake#1#2#3{%
\def\pgf@snake@name{#1}%
\pgfutil@namedef{pgf@snake@@#1@initial}{#2}%
\let\pgf@orig@state=\state%
\let\state=\pgf@snake@state
#3
\let\state=\pgf@orig@state%
}%
% Sets the additional transformation applied to every segment of a snake
%
% #1 = transformation
%
% Example:
%
% \pgfsetsnakesegmenttransformation{\pgftransformyshift{5pt}}
\def\pgfsetsnakesegmenttransformation#1{\def\pgf@snakeadditionaltransform{#1}}%
\pgfsetsnakesegmenttransformation{}%
% Declares a new state
%
% #1 = state name
% #2 = options
% #3 = path element
%
% Description:
%
% When a snake is drawn and the current state is #1, the following
% happens. First, the options are executed, which will possible change
% the state. If that does not happen, the path element is added to the
% path and the coordinate system is translated by the path element's
% width (which is specified using the width option).
%
% Example:
%
% \state{initial}[width=10pt]
% {
% \pgfpathlineto{\pgfpoint{2.5pt}{2.5pt}}
% \pgfpathlineto{\pgfpoint{7.5pt}{-2.5pt}}
% \pgfpathlineto{\pgfpoint{10pt}{0pt}}
% }
\def\pgf@snake@state#1{\pgfutil@ifnextchar[{\pgf@@snake@start#1}{\pgf@@snake@start#1[]}}%}%
\def\pgf@@snake@start#1[#2]#3{%
\pgfutil@namedef{pgf@snake@@\pgf@snake@name @#1@options}{#2}%
\pgfutil@namedef{pgf@snake@@\pgf@snake@name @#1@code}{#3}%
}%
% Use multiple snakes
%
% #1 = list of snake names/length pairs
% #2 = point to which the snake leads
%
% This operation uses the snakes in parameter #1 to get to the point
% #4. The parameter #1 should contain pairs consisting of a snake name
% and a length for which this snake should be used. When the length is
% computed, the dimensions \pgfsnakeremainingdistance and
% \pgfsnakecompleteddistance will have been set to the length of the
% total distance to #2 that has already been covered/that still needs
% to be covered.
%
% Example:
%
% \pgfpathsnakesto{{lineto}{1cm},{zig zag}{\pgfsnakeremainingdistance}}{\pgfpoint{2cm}{3cm}}
\def\pgfpathsnakesto#1#2{%
\begingroup%
% compute target vector
\pgfpointtransformed{#2}%
\advance\pgf@x by-\pgf@path@lastx%
\advance\pgf@y by-\pgf@path@lasty%
%
% MW: Calculate the angle of the snake.
%
\edef\pgf@marshal{%
\noexpand\pgfmathanglebetweenpoints{\noexpand\pgfpointorigin}{%
\noexpand\pgf@x\the\pgf@x\noexpand\pgf@y\the\pgf@y}%
}%
\pgf@marshal%
\let\pgfsnakeangle\pgfmathresult%
%
% MW: Use this instead for length (?). More accurate and only a few operations slower.
%
\pgfmathveclen@{\pgfmath@tonumber{\pgf@x}}{\pgfmath@tonumber{\pgf@y}}%
\pgfsnakeremainingdistance\pgfmathresult pt\relax%
%
% Ok, now normalize the vector...
\pgf@xa=\pgf@x%
\pgf@ya=\pgf@y%
\pgf@process{\pgfpointnormalised{}}%
% ok, now computer length (arghh...)
% In theory that's easy: divide the larger of the values x or y by
% the normalized x or y. Well...
%
% First, make xa and ya positive:
% \ifdim\pgf@xa<0pt%
% \pgf@xa=-\pgf@xa%
% \fi%
% \ifdim\pgf@ya<0pt%
% \pgf@ya=-\pgf@ya%
% \fi%
% % Now do division:
% \ifdim\pgf@xa>\pgf@ya%
% \c@pgf@counta=\pgf@x%
% \ifnum\c@pgf@counta=0\relax%
% \else%
% \divide\c@pgf@counta by 255\relax%
% \pgf@xa=16\pgf@xa\relax%
% \divide\pgf@xa by\c@pgf@counta%
% \pgf@xa=16\pgf@xa\relax%
% \fi%
% \else%
% \c@pgf@counta=\pgf@y%
% \ifnum\c@pgf@counta=0\relax%
% \else%
% \divide\c@pgf@counta by 255\relax%
% \pgf@ya=16\pgf@ya\relax%
% \divide\pgf@ya by\c@pgf@counta%
% \pgf@xa=16\pgf@ya\relax%
% \fi%
% \fi%
% % Make positive:
% \ifdim\pgf@xa<0pt%
% \pgf@xa=-\pgf@xa%
% \fi%
% % Ok, now we draw things...
\edef\pgf@list{#1}%
% \pgfsnakeremainingdistance=\pgf@xa%
\pgfsnakecompleteddistance=0pt%
\pgf@xb=\pgf@x%
\pgf@yb=\pgf@y%
\pgfutil@for\pgf@temp:=\pgf@list\do{%
\ifx\pgf@temp\pgfutil@empty%
\else%
\expandafter\pgf@snake@invoke\pgf@temp%
\fi%
}%
\endgroup%
}%
\def\pgf@snake@invoke#1#2{%
\pgfmathsetlength\pgf@xa{#2}%
{%
\edef\pgf@marshal{\noexpand\pgfpathsnakealongvector{#1}{\the\pgf@xa}{\noexpand\pgfqpoint{\the\pgf@xb}{\the\pgf@yb}}}%
\pgf@marshal%
}%
\advance\pgfsnakecompleteddistance by\pgf@xa%
\advance\pgfsnakeremainingdistance by-\pgf@xa%
}%
% Use a snake
%
% #1 = snake name
% #2 = point to which the snake leads
%
% This operation mainly computes \pgfpathsnakealongvector for a vector
% appropriately chosen. See \pgfpathsnakealongvector for details.
%
% Example:
%
% \pgfpathsnaketo{zig zag}{\pgfpoint{2cm}{3cm}}
\def\pgfpathsnaketo#1#2{\pgfpathsnakesto{{#1}{\pgfsnakeremainingdistance}}{#2}}%
% Use a snake
%
% #1 = snake name
% #2 = length of the snake
% #3 = vector along which the snake grows, should have unit length.
%
% This command draws a snake (more precisely, it adds a snake to the
% path). This works as follows:
%
% First, the coordinate system is transformed such that the vector #3
% points to the right.
%
% Next, the state `initial' of the snake is entered. Unless the
% options of this state cause it to switch to another state, the path
% element is added to the path. Then, the coordinate system is
% translated by the width of the path element as specified in the
% width option of the path element. The dimensions
% \pgfsnakeremainingdistance and \pgfsnakecompleteddistance are
% updated.
%
% The process ends when the state `final' is entered. The code of the
% final state is executed and the process stops.
%
% Example:
%
% \pgfpathsnakealongvector{zig zag}{100pt}{\pgfpolar{30}{1pt}}
\def\pgfpathsnakealongvector#1#2#3{%
\pgfutil@ifundefined{pgf@snake@@#1@initial}{\pgferror{Undefined snake ``#1''}}
{
\begingroup% keep things local
\pgftransformreset%
\pgf@pt@x=\pgf@path@lastx% evil trickery to transform to the last point
\pgf@pt@y=\pgf@path@lasty%
\pgf@process{#3}%
\pgf@xa=\pgf@x%
\pgf@ya=\pgf@y%
\pgf@xb=-\pgf@y%
\pgf@yb=\pgf@x%
\pgftransformcm
{\pgf@sys@tonumber{\pgf@xa}}{\pgf@sys@tonumber{\pgf@ya}}
{\pgf@sys@tonumber{\pgf@xb}}{\pgf@sys@tonumber{\pgf@yb}}
{\pgfpointorigin}%
% Now, setup the automaton
\expandafter\let\expandafter\pgf@snake@current@state\expandafter=\csname pgf@snake@@#1@initial\endcsname%
\def\pgf@snake@name{#1}%
\pgfsnakecompleteddistance=0pt%
\pgfmathsetlength\pgfsnakeremainingdistance{#2}%
\pgf@snake@run%
% Last step:
{%
\pgftransformxshift{\pgfsnakecompleteddistance}%
\pgf@snakeadditionaltransform%
\csname pgf@snake@@#1@final@code\endcsname%
}%
\endgroup%
}%
}%
\def\pgf@final@text{final}%
\def\pgf@snake@run{%
\let\pgf@snake@next=\pgf@snake@do@state%
\ifx\pgf@snake@current@state\pgf@final@text%
\let\pgf@snake@next=\relax%
\fi%
\pgf@snake@next%
}%
\def\pgf@snake@do@state{%
\let\pgf@snake@next=\relax%
\let\pgf@snake@next@state=\pgf@snake@current@state%
% execute options
\expandafter\expandafter\expandafter\pgf@snakes@setter
\expandafter\expandafter\expandafter{\csname pgf@snake@@\pgf@snake@name @\pgf@snake@current@state @options\endcsname}%
\ifx\pgf@snake@next\relax%
\let\pgf@snake@next=\pgf@snake@do@code%
\fi%
\pgf@snake@next%
}%
\def\pgf@snakes@setter{%
\pgfqkeys{/pgf/snakes}%
}%
\def\pgf@snake@do@code{%
% Ok, execute code:
{%
\pgftransformxshift{\pgfsnakecompleteddistance}%
\pgf@snakeadditionaltransform%
\csname pgf@snake@@\pgf@snake@name @\pgf@snake@current@state @code\endcsname%
}%
% next, do transformation and update
\pgfmathsetlength{\pgf@xa}{\pgf@snake@width}%
\advance\pgfsnakeremainingdistance by-\pgf@xa%
\advance\pgfsnakecompleteddistance by\pgf@xa%
% Next iteration:
\let\pgf@snake@current@state=\pgf@snake@next@state%
\pgf@snake@run%
}%
\pgfkeys{
/pgf/snakes/width/.code=\def\pgf@snake@width{#1}\pgf@snake@switch@if#1 to final\pgf@stop,%
/pgf/snakes/switch if less than/.code=\pgf@snake@switch@if#1\pgf@stop,%
/pgf/snakes/next state/.store in=\pgf@snake@next@state%
}%
\def\pgf@snake@switch@if#1to #2\pgf@stop{%
\ifx\pgf@snake@next\relax%
\pgfmathsetlength\pgf@x{#1}%
\ifdim\pgfsnakeremainingdistance<\pgf@x%
\def\pgf@snake@current@state{#2}%
\let\pgf@snake@next=\pgf@snake@run%
\fi%
\fi%
}%
% lineto snake
%
% This snake simply adds a straight line. This snake is mainly useful
% in conjunction with other snakes.
\pgfdeclaresnake{lineto}{final}
{%
\state{final}
{ \pgfpathlineto{\pgfqpoint{\pgfsnakeremainingdistance}{0pt}} }
}%
% moveto snake
%
% This snake simply jumps to the end. This snake, too, is mainly
% useful in conjunction with other snakes.
\pgfdeclaresnake{moveto}{final}
{%
\state{final}
{ \pgfpathmoveto{\pgfqpoint{\pgfsnakeremainingdistance}{0pt}} }
}%
\endinput