Current File : //usr/share/texlive/texmf-dist/tex/generic/pgf/basiclayer/pgfcorepathprocessing.code.tex |
% Copyright 2018 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{pgfcorepathprocessing.code.tex}
% Split a path at the last subpath of a path
%
% #1 = a macro that stores a path
%
% Description:
%
% This command will split the path into two parts:
%
% \pgfprocessresultpathprefix
% The part of the path before the last subpath.
%
% \pgfprocessresultpathsuffix
% The last subpath on the path.
%
% #1 will always be equal to the contents of the two above macros
% concatenated. Normally, your objective will be to modify the
% \pgfprocessresultpathsuffix and then concatenate the result.
\def\pgfprocesssplitpath#1{%
\let\pgfprocessresultpathprefix\pgfutil@empty%
\let\pgfprocessresultpathsuffix\pgfutil@empty%
\let\pgf@next\pgf@process@split%
\expandafter\pgf@process@split#1\pgfsyssoftpath@movetotoken{}{}\pgf@stop%
}
\def\pgf@process@split#1\pgfsyssoftpath@movetotoken#2#3#4{%
\ifx#4\pgf@stop% ok, end reached!
\expandafter\def\expandafter\pgfprocessresultpathsuffix\expandafter{\pgfprocessresultpathsuffix#1}%
\let\pgf@next\pgfutil@gobble%
\else%
\expandafter\expandafter\expandafter\def%
\expandafter\expandafter\expandafter\pgfprocessresultpathprefix%
\expandafter\expandafter\expandafter{\expandafter\pgfprocessresultpathprefix\pgfprocessresultpathsuffix#1}%
\def\pgfprocessresultpathsuffix{\pgfsyssoftpath@movetotoken{#2}{#3}}%
\fi%
\pgf@next#4%
}
% Split a subpath at the end
%
% #1 = a macro that stores an open subpath that contains at least two
% path commands (so, not just a moveto);
%
% Description:
%
% Splits the subpath into two parts:
%
% \pgfprocessresultsubpathsuffix
% This macro contains the last two "relevant" path commands: The end
% of the path command that led to the last path command and this
% last path command. In essence, this macro contains everything you
% "need to modify" if you wish to modify the end of the path.
%
% \pgfprocessresultsubpathprefix
% Everything before the previous macro on the subpath.
\def\pgfprocesssplitsubpath#1{%
% First, we need to find the end:
\let\pgf@tempa\pgfutil@emtpy%
\let\pgf@tempb\pgfutil@emtpy%
\let\pgf@tempc\pgfutil@emtpy%
\let\pgf@tempd\pgfutil@emtpy%
\let\pgfprocessresultsubpathprefix\pgfutil@empty%
\let\pgfprocessresultsubpathsuffix\pgfutil@empty%
\let\pgf@next\pgf@split@subpath%
\expandafter\pgf@split@subpath#1\pgf@stop%
}
\newif\ifpgf@split@move
\def\pgf@split@subpath#1#2#3#4{%
\ifx#4\pgf@stop%
\expandafter\def\expandafter\pgfprocessresultsubpathsuffix\expandafter{\pgfprocessresultsubpathsuffix#1{#2}{#3}}%
\let\pgf@next\pgfutil@gobble%
\else%
\pgf@split@movetrue%
\ifx#1\pgfsyssoftpath@curvetosupportatoken%
\pgf@split@movefalse%
\else
\ifx#1\pgfsyssoftpath@curvetosupportbtoken%
\pgf@split@movefalse%
\fi%
\fi%
\ifpgf@split@move%
\expandafter\expandafter\expandafter\def%
\expandafter\expandafter\expandafter\pgfprocessresultsubpathprefix%
\expandafter\expandafter\expandafter{%
\expandafter\pgfprocessresultsubpathprefix\pgfprocessresultsubpathsuffix}%
\def\pgfprocessresultsubpathsuffix{#1{#2}{#3}}%
\else%
\expandafter\def\expandafter\pgfprocessresultsubpathsuffix\expandafter{\pgfprocessresultsubpathsuffix#1{#2}{#3}}%
\fi%
\fi%
\pgf@next#4%
}
% Extract start and end vectors of a path
%
% #1 = a macro that stores a path
%
% Description:
%
% This command will extract the first and second coordinate on the
% path as well as the last and second-last. These coordinates will be
% put in the pgfpoint-macros \pgfpointfirstonpath,
% \pgfpointsecondonpath, \pgfpointsecondlastonpath, and
% \pgfpointlastonpath. If the path is empty, these macros are set to
% \pgfpointorigin.
%
% Example:
%
% \pgfsyssoftpath@moveto{0}{0}
% \pgfsyssoftpath@lineto{10}{10}
% \pgfsyssoftpath@curveto{20}{20}{30}{30}{40}{40}
% \pgfsyssoftpath@getcurrentpath\mypath
% \pgfprocesspathextractpoints\mypath
%
% % \pgfpointfirstonpath is now \pgfpoint{0}{0}
% % \pgfpointsecondonpath is now \pgfpoint{10bp}{10bp}
% % \pgfpointsecondlastonpath is now \pgfpoint{30bp}{30bp}
% % \pgfpointlastonpath is now \pgfpoint{40bp}{40bp}
\def\pgfprocesspathextractpoints#1{%
\ifx#1\pgfutil@empty%
\let\pgfpointfirstonpath=\pgfpointorigin%
\let\pgfpointsecondonpath=\pgfpointorigin%
\let\pgfpointsecondlastonpath=\pgfpointorigin%
\let\pgfpointlastonpath=\pgfpointorigin%
\else%
\expandafter\pgf@extractprocessorfirst#1\pgf@stop%
\fi%
}
\def\pgf@extractprocessorfirst#1#2#3#4{%
\def\pgfpointfirstonpath{\pgfqpoint{#2}{#3}}%
\ifx#4\pgf@stop%
% pretty short path...
\let\pgfpointsecondonpath=\pgfpointfirstonpath%
\let\pgfpointsecondlastonpath=\pgfpointfirstonpath%
\let\pgfpointlastonpath=\pgfpointfirstonpath%
\let\next=\pgfutil@gobble%
\else
\let\next=\pgf@extractprocessorsecond%
\fi%
\next#4%
}
\def\pgf@extractprocessorsecond#1{%
\ifx#1\pgfsyssoftpath@movetotoken%
% Reset things...
\let\pgf@next=\pgf@extractprocessorfirst%
\else%
\let\pgf@next=\pgf@@extractprocessorsecond%
\fi%
\pgf@next#1%
}
\def\pgf@@extractprocessorsecond#1#2#3#4{%
\def\pgfpointsecondonpath{\pgfqpoint{#2}{#3}}%
\let\pgfpointsecondlastonpath=\pgfpointfirstonpath%
\let\pgfpointlastonpath=\pgfpointsecondonpath%
\ifx#4\pgf@stop%
% short path...
\let\next=\pgfutil@gobble%
\else
\let\next=\pgf@extractprocessorother%
\fi%
\next#4%
}
\def\pgf@extractprocessorother#1{%
\ifx#1\pgfsyssoftpath@movetotoken%
% Reset things...
\let\pgf@next=\pgf@extractprocessorfirst%
\else%
\let\pgf@next=\pgf@@extractprocessorother%
\fi%
\pgf@next#1%
}
\def\pgf@@extractprocessorother#1#2#3#4{%
\let\pgfpointsecondlastonpath=\pgfpointlastonpath%
\def\pgfpointlastonpath{\pgfqpoint{#2}{#3}}%
\ifx#4\pgf@stop%
% end!
\let\next=\pgfutil@gobble%
\fi%
\next#4%
}
% Check for closepath and rectangles
%
% #1 = a macro that stores a path
% #2 = command to be executed when a closepath or a rectangle is encountered
%
% Example:
%
% \pgfsyssoftpath@moveto{0}{0}
% \pgfsyssoftpath@lineto{10}{10}
% \pgfsyssoftpath@curveto{20}{20}{30}{30}{40}{40}
% \pgfsyssoftpath@getcurrentpath\mypath
% \pgfprocesscheckclosed{\mypath}{\pgf@drawarrowsfalse}
\def\pgfprocesscheckclosed#1#2{%
{%
\global\let\pgf@proc@todo=\relax%
\let\pgfsyssoftpath@movetotoken=\pgfutil@gobbletwo%
\let\pgfsyssoftpath@linetotoken=\pgfutil@gobbletwo%
\let\pgfsyssoftpath@curvetosupportatoken=\pgfutil@gobbletwo%
\let\pgfsyssoftpath@curvetosupportbtoken=\pgfutil@gobbletwo%
\let\pgfsyssoftpath@curvetotoken=\pgfutil@gobbletwo%
\def\pgfsyssoftpath@rectcornertoken{\gdef\pgf@proc@todo{#2}\pgfutil@gobbletwo}%
\def\pgfsyssoftpath@rectsizetoken{\gdef\pgf@proc@todo{#2}\pgfutil@gobbletwo}%
\def\pgfsyssoftpath@closepathtoken{\gdef\pgf@proc@todo{#2}\pgfutil@gobbletwo}%
#1%
}%
\pgf@proc@todo%
}
% Resolve specialround
%
% #1 = a macro that stores a path
% #2 = a macro that stores the new path
%
% Description:
%
% Resolves all specialround tokens. When such a token is encountered,
% the objective is to replace the next corner by a rounded corner.
%
\def\pgfprocessround#1#2{%
% first, check whether #1 contains \pgfsyssoftpath@specialroundtoken.
% if not, do quick assignment!
\expandafter\pgf@processroundcheck\expandafter#1\expandafter#2#1\pgfsyssoftpath@specialroundtoken\pgf@stop%
}
\def\pgf@processroundcheck#1#2#3\pgfsyssoftpath@specialroundtoken#4\pgf@stop{%
\def\pgf@test{#4}%
\ifx\pgf@test\pgfutil@empty%
% ok, nothing to be done!
\let#2=#1%
\else%
% very well...
\pgf@@processround#1#2%
\fi%
}
\def\pgf@@processround#1#2{%
\let\pgfprocess@newpath\pgfutil@empty%
\let\pgfprocess@moveto\pgfutil@empty%
\let\pgfprocess@firstto\pgfutil@empty%
\let\pgfprocess@segment\pgfutil@empty%
\pgf@xa=0pt%
\pgf@ya=0pt%
\expandafter\pgfprocess@round#1\pgf@stop{0pt}{0pt}%
\expandafter\pgfutil@g@addto@macro\expandafter\pgfprocess@newpath\expandafter{\pgfprocess@moveto}%
\expandafter\pgfutil@g@addto@macro\expandafter\pgfprocess@newpath\expandafter{\pgfprocess@segment}%
\let#2=\pgfprocess@newpath%
}
\def\pgfprocess@round#1#2#3{%
\ifx#1\pgf@stop%
\let\next=\relax%
\else%
\ifx#1\pgfsyssoftpath@specialroundtoken%
\def\pgfprocess@savex{#2}%
\def\pgfprocess@savey{#3}%
\let\next=\pgfprocess@specialround%
\ifdim#2=0pt%
\ifdim#3=0pt%
\let\next=\pgfprocess@round% skip!
\fi%
\fi%
\else%
\ifx\pgfprocess@firstto\pgfutil@empty%
\def\pgfprocess@firstto{{#2}{#3}}%
\fi%
\pgf@xa=#2%
\pgf@ya=#3%
\ifx#1\pgfsyssoftpath@movetotoken%
% ok, move old segment to newpath
\expandafter\pgfutil@g@addto@macro\expandafter\pgfprocess@newpath\expandafter{\pgfprocess@moveto}%
\expandafter\pgfutil@g@addto@macro\expandafter\pgfprocess@newpath\expandafter{\pgfprocess@segment}%
\def\pgfprocess@moveto{#1{#2}{#3}}%
\let\pgfprocess@firstto=\pgfutil@empty%
\let\pgfprocess@segment=\pgfutil@empty%
\else%
\pgfutil@g@addto@macro\pgfprocess@segment{#1{#2}{#3}}%
\fi%
\let\next=\pgfprocess@round%
\fi%
\fi%
\next%
}
\def\pgfprocess@specialround#1#2#3{%
\ifx\pgfprocess@firstto\pgfutil@empty%
\def\pgfprocess@firstto{{#2}{#3}}%
\fi%
\let\next=\pgfprocess@round% default: do nothing
\ifx#1\pgfsyssoftpath@linetotoken%
% Ok, round a lineto
\let\next=\pgfprocess@specialroundcope%
\else%
\ifx#1\pgfsyssoftpath@curvetosupportatoken%
% Ok, round a curveto.
\let\next=\pgfprocess@specialroundcurveto%
\else%
\ifx#1\pgfsyssoftpath@closepathtoken%
% Ok, round a closepath (this is tricky...)
\let\next=\pgfprocess@specialroundclose%
\fi%
\fi%
\fi%
\next#1{#2}{#3}%
}%
\def\pgfprocess@specialroundcope#1#2#3#4#5#6{%
\let\next=\pgfprocess@round% do nothing by default
\let\pgfprocess@continueafterrounding=\pgfprocess@round%
\ifx#4\pgfsyssoftpath@linetotoken%
% ok, let's get kicking...
\pgf@xc=#5%
\pgf@yc=#6%
\let\next=\pgfprocess@@specialround%
\else%
\ifx#4\pgfsyssoftpath@curvetosupportatoken%
\pgf@xc=#5%
\pgf@yc=#6%
\let\next=\pgfprocess@@specialround%
\else%
\ifx#4\pgfsyssoftpath@closepathtoken%
\pgf@xc=#5%
\pgf@yc=#6%
\let\next=\pgfprocess@@specialround%
\else
\ifx#4\pgfsyssoftpath@specialroundtoken%
\let\next=\pgfprocess@@findrightcoordinates%
\fi%
\fi%
\fi%
\fi%
\next#1{#2}{#3}#4{#5}{#6}%
}
\def\pgfprocess@@findrightcoordinates#1#2#3#4#5#6#7#8#9{%
\pgf@xc=#8%
\pgf@yc=#9%
\pgfprocess@@specialround#1{#2}{#3}#4{#5}{#6}#7{#8}{#9}%
}
\def\pgfprocess@@specialround#1#2#3{%
\pgfutil@g@addto@macro\pgfprocess@segment{#1}%
% calculate start coordinate of the curve
\pgf@xb=#2%
\pgf@yb=#3%
%
\edef\pgf@marshal%
{\noexpand\pgfpointlineatdistance{\pgfprocess@savex}%
{\noexpand\pgfqpoint{\the\pgf@xb}{\the\pgf@yb}}%
{\noexpand\pgfqpoint{\the\pgf@xa}{\the\pgf@ya}}}%
\pgf@process{\pgf@marshal}%
\pgf@xa=\pgf@x% save start point of added curve
\pgf@ya=\pgf@y%
\edef\pgfprocess@addition{{\the\pgf@x}{\the\pgf@y}}%
\expandafter\pgfutil@g@addto@macro\expandafter\pgfprocess@segment\expandafter{\pgfprocess@addition}%
%
% now add curve
%
\edef\pgf@marshal%
{\noexpand\pgfpointlineatdistance{\pgfprocess@savey}%
{\noexpand\pgfqpoint{\the\pgf@xb}{\the\pgf@yb}}%
{\noexpand\pgfqpoint{\the\pgf@xc}{\the\pgf@yc}}}%
\pgf@process{\pgf@marshal}%
\pgf@xc=\pgf@x% save end point of added curve
\pgf@yc=\pgf@y%
% calculate first support:
{%
\pgf@x=\pgf@xb%
\pgf@y=\pgf@yb%
\advance\pgf@x by-\pgf@xa%
\advance\pgf@y by-\pgf@ya%
\advance\pgf@xa by 0.5522847\pgf@x%
\advance\pgf@ya by 0.5522847\pgf@y%
\edef\pgfprocess@addition{\noexpand\pgfsyssoftpath@curvetosupportatoken{\the\pgf@xa}{\the\pgf@ya}}%
\expandafter\pgfutil@g@addto@macro\expandafter\pgfprocess@segment\expandafter{\pgfprocess@addition}%
}%
% calculate second support:
{%
\pgf@x=\pgf@xb%
\pgf@y=\pgf@yb%
\advance\pgf@x by-\pgf@xc%
\advance\pgf@y by-\pgf@yc%
\advance\pgf@xc by 0.5522847\pgf@x%
\advance\pgf@yc by 0.5522847\pgf@y%
\edef\pgfprocess@addition{\noexpand\pgfsyssoftpath@curvetosupportbtoken{\the\pgf@xc}{\the\pgf@yc}}%
\expandafter\pgfutil@g@addto@macro\expandafter\pgfprocess@segment\expandafter{\pgfprocess@addition}%
}%
% add end:
\edef\pgfprocess@addition{\noexpand\pgfsyssoftpath@curvetotoken{\the\pgf@xc}{\the\pgf@yc}}%
\expandafter\pgfutil@g@addto@macro\expandafter\pgfprocess@segment\expandafter{\pgfprocess@addition}%
%
% continue!
%
\pgf@xa=#2%
\pgf@ya=#3%
\pgfprocess@continueafterrounding%
}
\def\pgfprocess@specialroundcurveto#1#2#3#4#5#6{%
\pgfutil@g@addto@macro\pgfprocess@segment{#1{#2}{#3}#4{#5}{#6}}% supports
\pgf@xa=#5%
\pgf@ya=#6%
\pgfprocess@specialroundcope}
\def\pgfprocess@specialroundclose{%
\let\next=\pgfprocess@round%
\ifx\pgfprocess@moveto\pgfutil@empty%
\else%
\ifx\pgfprocess@firstto\pgfutil@empty%
\else%
\expandafter\pgfprocess@@specialclosetarget\pgfprocess@firstto%
\let\pgfprocess@continueafterrounding=\pgfprocess@cleanupafterclose%
\edef\next{%
\noexpand\pgfprocess@@specialround%
\expandafter\expandafter\expandafter\noexpand\expandafter\pgfprocess@@specialclosemoveto\pgfprocess@moveto%
}%
\fi%
\fi%
\next%
}
\def\pgfprocess@@specialclosetarget#1#2{%
\pgf@xc=#1%
\pgf@yc=#2%
}
\def\pgfprocess@@specialclosemoveto#1#2#3{%
\pgfsyssoftpath@linetotoken{#2}{#3}%
}
\def\pgfprocess@cleanupafterclose#1#2#3{%
\edef\pgfprocess@moveto{\noexpand\pgfsyssoftpath@movetotoken{\the\pgf@xc}{\the\pgf@yc}}%
\edef\pgf@marshal{\noexpand\pgfprocess@round\noexpand\pgfsyssoftpath@closepathtoken{\the\pgf@xc}{\the\pgf@yc}}%
\pgf@marshal%
}
% Replace start and end coordinates of a path
%
% #1 = new start coordinate
% #2 = new end coordinate
%
% Description:
%
% This command will replace the first and last coordinates on a path
% by the given coordinates.
%
% Example:
%
% \pgfsyssoftpath@moveto{0}{0}
% \pgfsyssoftpath@lineto{10}{10}
% \pgfsyssoftpath@curveto{20}{20}{30}{10}{40}{0}
% \pgfsyssoftpath@getcurrentpath\mypath
% \pgfsetlinewidth{2pt}
% \pgfusepath{stroke}
% \pgfprocesspathextractpoints{\mypath}
% \pgfprocesspathreplacestartandend{\mypath}
% {\pgfpointlineatdistance{2pt}{\pgfpointfirstonpath}{\pgfpointsecondonpath}}%
% {\pgfpointlineatdistance{2pt}{\pgfpointlastonpath}{\pgfpointsecondlastonpath}}%
% \pgfsyssoftpath@setcurrentpath\mypath
% \pgfsetlinewidth{1pt}
% \color{red}
% \pgfusepath{stroke}
\def\pgfprocesspathreplacestartandend#1#2#3{%
\ifx#1\pgfutil@empty%
\else%
{%
% We (mis)use the current path to store (in a buffered manner) the
% rest path.
\pgfsyssoftpath@getcurrentpath\pgf@replace@origpath%
\let\pgf@prepath=\pgfutil@empty%
\pgf@process{#3}%
\pgf@xa=\pgf@x%
\pgf@ya=\pgf@y%
\pgf@process{#2}%
\expandafter\pgf@replaceprocessfirst#1\pgf@stop%
\pgfsyssoftpath@getcurrentpath\pgf@restpath%
\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\gdef%
\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter#1%
\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter{%
\expandafter\expandafter\expandafter\pgf@prepath%
\expandafter\pgf@newstart\pgf@restpath}%
% Restore current path
\pgfsyssoftpath@setcurrentpath\pgf@replace@origpath%
}%
\fi%
}
\def\pgf@replaceprocessfirst#1#2#3#4{%
\def\pgf@origstart{#1{#2}{#3}}%
\edef\pgf@newstart{\noexpand#1{\the\pgf@x}{\the\pgf@y}}%
\pgfsyssoftpath@setcurrentpath\pgfutil@empty%
\ifx#4\pgf@stop%
\let\pgf@next=\pgfutil@gobble%
\else%
\let\pgf@next=\pgf@replaceprocessother%
\let\pgf@@next=\pgf@@replaceprocessother%
\fi%
\pgf@next#4%
}
\def\pgf@replaceprocessother#1{%
\ifx#1\pgfsyssoftpath@movetotoken%
\pgf@replace@handle@move%
\fi%
\pgf@@next#1%
}
\def\pgf@@replaceprocessother#1#2#3#4{%
\ifx#4\pgf@stop%
\edef\pgf@restpathaddition{{\noexpand#1{\the\pgf@xa}{\the\pgf@ya}}}%
\expandafter\pgfsyssoftpath@addtocurrentpath\pgf@restpathaddition%
\let\pgf@next=\pgfutil@gobble%
\else%
\pgfsyssoftpath@addtocurrentpath{#1{#2}{#3}}%
\fi%
\pgf@next#4%
}
\def\pgf@replace@handle@move{%
\pgfsyssoftpath@getcurrentpath\pgf@restpath%
% Arggghh! Must reset everything!
\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\gdef%
\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\pgf@prepath%
\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter{%
\expandafter\expandafter\expandafter\pgf@prepath%
\expandafter\pgf@origstart\pgf@restpath}%
% Redo first.
\let\pgf@@next=\pgf@replaceprocessfirst%
}
\endinput