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.
356 lines
11 KiB
356 lines
11 KiB
% 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, essentially, 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
|
|
|