diff options
Diffstat (limited to 'graphics/pgf/base/tex/generic/basiclayer/pgfcorepathprocessing.code.tex')
-rw-r--r-- | graphics/pgf/base/tex/generic/basiclayer/pgfcorepathprocessing.code.tex | 563 |
1 files changed, 563 insertions, 0 deletions
diff --git a/graphics/pgf/base/tex/generic/basiclayer/pgfcorepathprocessing.code.tex b/graphics/pgf/base/tex/generic/basiclayer/pgfcorepathprocessing.code.tex new file mode 100644 index 0000000000..e33f0653ce --- /dev/null +++ b/graphics/pgf/base/tex/generic/basiclayer/pgfcorepathprocessing.code.tex @@ -0,0 +1,563 @@ +% 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 |