You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
369 lines
9.9 KiB
369 lines
9.9 KiB
% Copyright 2006 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
|
|
|