% Copyright 2013 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{pgfmodulebending.code.tex} % % This file defines commands for drawing bending arrows and lines. % \usepgfmodule{nonlineartransformations} \usepgflibrary{curvilinear} % Configuration options for arrow tips: \pgfkeys{ /pgf/arrow keys/flex/.code=\pgfarrowsaddtooptions{\pgf@arrows@the@rigidity#1pt\let\pgf@arrow@flex@mode\pgf@arrow@mode@is@flex}, /pgf/arrow keys/flex/.default=1, /pgf/arrow keys/flex'/.code=\pgfarrowsaddtooptions{\pgf@arrows@the@rigidity#1pt\let\pgf@arrow@flex@mode\pgf@arrow@mode@is@flex@prime}, /pgf/arrow keys/flex'/.default=1, /pgf/arrow keys/bend/.code=\pgfarrowsaddtooptions{\let\pgf@arrow@flex@mode\pgf@arrow@mode@is@bend} } \def\pgf@arrow@mode@is@flex{1} \def\pgf@arrow@mode@is@flex@prime{2} \def\pgf@arrow@mode@is@bend{3} \newdimen\pgf@arrows@the@rigidity % % % Handle the end of a curve % % % First, the preparation. This is, essenatially, setting up the % nonlinear transformation \def\pgf@prep@curveend{ \pgftransformreset% \pgfsetcurvilinearbeziercurve{\pgfpointlastonpath}{\pgfpointsecondlastonpath}{\pgfpointthirdlastonpath}{\pgfpointfourthlastonpath} } % Second, the shortening. \def\pgf@do@shorten@curvedend{% \expandafter\expandafter\expandafter\pgf@do@shorten@curvedend@unpack\expandafter\pgfpointfourthlastonpath\pgfpointthirdlastonpath% } \def\pgf@do@shorten@curvedend@unpack\pgfqpoint#1#2\pgfqpoint#3#4{% \pgf@process{\pgfcurvilineardistancetotime{\pgf@path@shortening@distance}}% % Compute new curve: \pgfpointcurveattime{\pgf@x}{\pgfpointlastonpath}{\pgfpointsecondlastonpath}{\pgfpointthirdlastonpath}{\pgfpointfourthlastonpath}% % \pgfx/y and \pgf xa/xb already correct. Need to setup remaining vector... \pgf@xb#3% \pgf@yb#4% \pgf@xb\pgf@time@t\pgf@xb% \pgf@yb\pgf@time@t\pgf@yb% \advance\pgf@xb by\pgf@time@s\pgf@xc% \advance\pgf@yb by\pgf@time@s\pgf@yc% \edef\pgfprocessresultsubpathsuffix{% \expandafter\noexpand\pgfsubpathfourthlasttoken{#1}{#2}% \noexpand\pgfsyssoftpath@curvetosupportatoken{\the\pgf@xb}{\the\pgf@yb}% \noexpand\pgfsyssoftpath@curvetosupportbtoken{\the\pgf@xa}{\the\pgf@ya}% \noexpand\pgfsyssoftpath@curvetotoken{\the\pgf@x}{\the\pgf@y}}% \expandafter\expandafter\expandafter\def% \expandafter\expandafter\expandafter\pgfprocessresultpathsuffix% \expandafter\expandafter\expandafter{\expandafter\pgfprocessresultsubpathprefix\pgfprocessresultsubpathsuffix}% } % Third, the drawing \def\pgf@do@draw@curvedend{% \pgf@do@draw@curved\pgf@end@tip@sequence% } \def\pgf@do@draw@curved#1{% {% \pgftransformreset% \pgf@xb\pgf@arrow@tip@total@length% xb will keep track of the total length \let\pgf@arrow@handle\pgf@draw@curved% \let\pgf@arrow@handle@dot\relax% #1% }% } \def\pgf@draw@curved#1#2{% % Prepare: {% \pgfarrows@getid{#1}{#2}% % Do shift: \expandafter\expandafter\expandafter\pgf@arrow@drawer@rigid@shift\csname pgf@ar@ends@\pgf@arrow@id\endcsname% \expandafter\let\expandafter\pgf@arrow@bending@mode\csname pgf@ar@bending@mode@#1\endcsname% \ifx\pgf@arrow@bending@mode\pgfutil@empty\let\pgf@arrow@flex@mode\pgf@arrow@mode@is@flex\fi% % do swap: {% \csname pgf@ar@saves@\pgf@arrow@id\endcsname% \ifcase\pgf@arrow@flex@mode\relax% \expandafter\expandafter\expandafter\pgf@arrow@drawer@rigid\csname pgf@ar@visual@\pgf@arrow@id\endcsname% like flex \or% \expandafter\expandafter\expandafter\pgf@arrow@drawer@rigid\csname pgf@ar@visual@\pgf@arrow@id\endcsname% \or% \expandafter\expandafter\expandafter\pgf@arrow@drawer@rigid\csname pgf@ar@ends@\pgf@arrow@id\endcsname% \or% \pgf@arrow@drawer@bend% \fi% % hull points inside the above }% \expandafter}% % Transform to next tip: \expandafter\pgf@xb\the\pgf@xb% } \def\pgf@falsetext{false} \def\pgf@arrow@drawer@rigid@shift#1#2#3{% tip end, back end, line end, sep % Let xa be the actual back end of the current arrow plus the back end: \advance\pgf@xb by#2% \pgf@xa\pgf@xb% % Update the xb: \pgf@x#1% \advance\pgf@x by\pgfarrowsep% \advance\pgf@xb by-\pgf@x% } \def\pgf@arrow@drawer@bend{% \pgftransformnonlinear{\pgf@arrow@bending@mode{\pgf@x}{\pgf@y}} \pgftransformscale{-1}% \pgftransformxshift{-\pgf@xa}% % Do slant: \ifdim\pgfarrows@slant pt=0pt% \else% \pgftransformxslant{\pgfarrows@slant}% \fi% \ifpgfarrowswap% \pgftransformyscale{-1}% \fi% {% \pgf@relevantforpicturesizefalse% \pgfscope% \pgf@arrows@color@setup% \csname pgf@ar@inst@code@\pgf@arrow@id\endcsname% \endpgfscope% }% \pgf@arrows@bending@hull% } \def\pgf@arrow@drawer@rigid#1#2#3{% (rigid) start, (rigid) end, dummy % Compute the rigid positions: \pgf@x#1% start \pgf@y#2% flexibility*(end-start) + start \advance\pgf@y by-\pgf@x% \pgf@y\pgf@sys@tonumber\pgf@arrows@the@rigidity\pgf@y% \advance\pgf@y by\pgf@x% % Are they equal? \ifdim\pgf@x=\pgf@y% % Yes, do tangent: \pgf@bending@do@tangent% \else% \pgf@bending@do@flex% \fi% \pgf@xc#1% \pgf@xc-\pgf@xc% \pgftransformxshift{+\pgf@xc}% % Do slant: \ifdim\pgfarrows@slant pt=0pt% \else% \pgftransformxslant{\pgfarrows@slant}% \fi% % do swap: \ifpgfarrowswap% \pgftransformyscale{-1}% \fi% \pgfscope% \pgf@arrows@color@setup% \pgflowlevelsynccm\csname pgf@ar@cache@\pgf@arrow@id\endcsname% \endpgfscope% \pgf@arrows@rigid@hull% } \def\pgf@bending@do@tangent{% \pgf@xb\pgf@xa% \advance\pgf@xb by-\pgf@x% \pgfcurvilineardistancetotime{\pgf@xb}% \pgf@xb\pgf@x% % Compute points: \ifdim\pgf@xb=0pt% \pgf@bending@possible@degenerate% \else% \pgf@bending@do@tangent@normal% \fi% \pgf@ya-\pgf@y% \pgfsettransformentries% {\pgf@sys@tonumber\pgf@x}{\pgf@sys@tonumber\pgf@y}% {\pgf@sys@tonumber\pgf@ya}{\pgf@sys@tonumber\pgf@x}{\pgf@xc}{\pgf@yc}% }% \def\pgf@bending@do@tangent@normal{% \pgfpointcurveattime{\pgf@xb}{\pgf@curvilinear@line@a}{\pgf@curvilinear@line@b}{\pgf@curvilinear@line@c}{\pgf@curvilinear@line@d}% \pgf@xc\pgf@x% save \pgf@yc\pgf@y% save % compute normal: \advance\pgf@xb by-\pgf@xa% \advance\pgf@yb by-\pgf@ya% \pgf@process{\pgfpointnormalised{\pgf@x=\pgf@xb\pgf@y=\pgf@yb}} } \def\pgf@bending@possible@degenerate{% \ifx\pgf@curvilinear@line@a\pgf@curvilinear@line@b% degenerate! \ifx\pgf@curvilinear@line@a\pgf@curvilinear@line@c% double degenerate! \let\pgf@ref\pgf@curvilinear@line@d% \else \let\pgf@ref\pgf@curvilinear@line@c% \fi% \pgf@process{\pgf@curvilinear@line@a}% \pgf@xc\pgf@x% save \pgf@yc\pgf@y% save \pgf@process{\pgf@ref}% \advance\pgf@x by-\pgf@xc \advance\pgf@y by-\pgf@yc \pgf@process{\pgfpointnormalised{}} \pgf@x-\pgf@x \pgf@y-\pgf@y \else% \pgf@bending@do@tangent@normal% \fi% } \def\pgf@bending@do@flex{ \pgf@xb\pgf@xa% \pgf@xc\pgf@xa% \advance\pgf@xc by-\pgf@x% \advance\pgf@xb by-\pgf@y% \pgfcurvilineardistancetotime{\pgf@xc}% \pgf@xc\pgf@x% \pgfcurvilineardistancetotime{\pgf@xb}% \pgf@xb\pgf@x% % Compute points: \pgf@process{\pgfpointcurveattime{\pgf@xc}{\pgf@curvilinear@line@a}{\pgf@curvilinear@line@b}{\pgf@curvilinear@line@c}{\pgf@curvilinear@line@d}}% \pgf@xc\pgf@x\pgf@yc\pgf@y% \pgf@process{\pgfpointcurveattime{\pgf@xb}{\pgf@curvilinear@line@a}{\pgf@curvilinear@line@b}{\pgf@curvilinear@line@c}{\pgf@curvilinear@line@d}}% \pgf@xb\pgf@x\pgf@yb\pgf@y% \pgftransformarrow{\pgfqpoint{\pgf@xb}{\pgf@yb}}{\pgfqpoint{\pgf@xc}{\pgf@yc}}% } % Convex hull stuff: \def\pgf@arrows@bending@hull{% \ifpgf@relevantforpicturesize% % Do bb update: \expandafter\let\expandafter\pgf@temp\csname pgf@ar@hull@\pgf@arrow@id\endcsname% \ifx\pgf@temp\pgfutil@empty\else% \let\pgf@arrow@hull@point\pgf@arrow@bending@hull@point@first% \pgf@temp% \pgf@arrow@bending@update@bb% \fi% \fi% } \def\pgf@arrow@bending@hull@point@first#1#2{% \pgfpointtransformednonlinear{\pgfqpoint{#1}{#2}}% \pgf@xa\pgf@x\pgf@xb\pgf@x% \pgf@ya\pgf@y\pgf@yb\pgf@y% \let\pgf@arrow@hull@point\pgf@arrow@bending@hull@point@other% } \def\pgf@arrow@bending@hull@point@other#1#2{% \pgfpointtransformednonlinear{\pgfqpoint{#1}{#2}}% \ifdim\pgf@x<\pgf@xa\pgf@xa\pgf@x\else\ifdim\pgf@x>\pgf@xb\pgf@xb\pgf@x\fi\fi% \ifdim\pgf@y<\pgf@ya\pgf@ya\pgf@y\else\ifdim\pgf@y>\pgf@yb\pgf@yb\pgf@y\fi\fi% } \def\pgf@arrow@bending@update@bb{% \ifdim\pgf@picmaxx=-16000pt\relax% \global\pgf@picminx\pgf@xa% \global\pgf@picmaxx\pgf@xb% \global\pgf@picminy\pgf@ya% \global\pgf@picmaxy\pgf@yb% \else% \ifdim\pgf@xa<\pgf@picminx\global\pgf@picminx\pgf@xa\fi% \ifdim\pgf@ya<\pgf@picminy\global\pgf@picminy\pgf@ya\fi% \ifdim\pgf@xb>\pgf@picmaxx\global\pgf@picmaxx\pgf@xb\fi% \ifdim\pgf@yb>\pgf@picmaxy\global\pgf@picmaxy\pgf@yb\fi% \fi% } % % % Handle the start of a curve % % % First, the preparation. \def\pgf@prep@curvedstart{ \pgftransformreset% \pgfsetcurvilinearbeziercurve{\pgfpointfirstonpath}{\pgfpointsecondonpath}{\pgfpointthirdonpath}{\pgfpointfourthonpath}% } % Second, the shortening. \def\pgf@do@shorten@curvedstart{% \expandafter\expandafter\expandafter\pgf@do@shorten@curvedstart@unpack\expandafter\pgfpointthirdonpath\pgfpointfourthonpath% } \def\pgf@do@shorten@curvedstart@unpack\pgfqpoint#1#2\pgfqpoint#3#4{% \pgf@process{\pgfcurvilineardistancetotime{\pgf@path@shortening@distance}}% % Compute new curve: \pgfpointcurveattime{\pgf@x}{\pgfpointfirstonpath}{\pgfpointsecondonpath}{\pgfpointthirdonpath}{\pgfpointfourthonpath}% % \pgfx/y and \pgf xa/xb already correct. Need to setup remaining vector... \pgf@xb#1% \pgf@yb#2% \pgf@xb\pgf@time@t\pgf@xb% \pgf@yb\pgf@time@t\pgf@yb% \advance\pgf@xb by\pgf@time@s\pgf@xc% \advance\pgf@yb by\pgf@time@s\pgf@yc% \edef\pgfpointfirstonpath{\noexpand\pgfqpoint{\the\pgf@x}{\the\pgf@y}}% \edef\pgfpointsecondonpath{\noexpand\pgfqpoint{\the\pgf@xa}{\the\pgf@ya}}% \edef\pgfprocessresultpathsuffix{% \noexpand\pgfsyssoftpath@movetotoken{\the\pgf@x}{\the\pgf@y}% \noexpand\pgfsyssoftpath@curvetosupportatoken{\the\pgf@xa}{\the\pgf@ya}% \noexpand\pgfsyssoftpath@curvetosupportbtoken{\the\pgf@xb}{\the\pgf@yb}% \noexpand\pgfsyssoftpath@curvetotoken{#3}{#4}% } \expandafter\expandafter\expandafter\def% \expandafter\expandafter\expandafter\pgfprocessresultpathsuffix% \expandafter\expandafter\expandafter{\expandafter\pgfprocessresultpathsuffix\pgfsubpathend}% } % Third, the drawing \def\pgf@do@draw@curvedstart{% \pgf@do@draw@curved\pgf@start@tip@sequence% } \endinput