diff options
-rw-r--r-- | Master/texmf-dist/doc/latex/tikz-nfold/README.md | 2 | ||||
-rw-r--r-- | Master/texmf-dist/doc/latex/tikz-nfold/tikz-nfold-doc.pdf | bin | 302816 -> 304060 bytes | |||
-rw-r--r-- | Master/texmf-dist/doc/latex/tikz-nfold/tikz-nfold-doc.tex | 38 | ||||
-rw-r--r-- | Master/texmf-dist/tex/latex/tikz-nfold/pgflibrarybezieroffset.code.tex | 170 | ||||
-rw-r--r-- | Master/texmf-dist/tex/latex/tikz-nfold/pgflibrarynfold.code.tex | 88 | ||||
-rw-r--r-- | Master/texmf-dist/tex/latex/tikz-nfold/pgflibraryoffsetpath.code.tex | 913 | ||||
-rw-r--r-- | Master/texmf-dist/tex/latex/tikz-nfold/tikzlibrarynfold.code.tex | 1303 |
7 files changed, 1048 insertions, 1466 deletions
diff --git a/Master/texmf-dist/doc/latex/tikz-nfold/README.md b/Master/texmf-dist/doc/latex/tikz-nfold/README.md index c1466687133..4c1d75c2494 100644 --- a/Master/texmf-dist/doc/latex/tikz-nfold/README.md +++ b/Master/texmf-dist/doc/latex/tikz-nfold/README.md @@ -1,5 +1,5 @@ # tikz-nfold -## Version 0.1.3 +## Version 1.0.0 This library adds higher-order paths to [TikZ](https://ctan.org/pkg/pgf) and also fixes some graphical issues with TikZ' `double` paths, used e.g. in wide arrows. It is also compatible with [tikz-cd](https://ctan.org/pkg/tikz-cd), adding support for triple and higher arrows. See the [documentation](tikz-nfold-doc.pdf) for full details. diff --git a/Master/texmf-dist/doc/latex/tikz-nfold/tikz-nfold-doc.pdf b/Master/texmf-dist/doc/latex/tikz-nfold/tikz-nfold-doc.pdf Binary files differindex 9df9c937ac2..8dad39e27f0 100644 --- a/Master/texmf-dist/doc/latex/tikz-nfold/tikz-nfold-doc.pdf +++ b/Master/texmf-dist/doc/latex/tikz-nfold/tikz-nfold-doc.pdf diff --git a/Master/texmf-dist/doc/latex/tikz-nfold/tikz-nfold-doc.tex b/Master/texmf-dist/doc/latex/tikz-nfold/tikz-nfold-doc.tex index 46132fb7f5b..094924d2e8b 100644 --- a/Master/texmf-dist/doc/latex/tikz-nfold/tikz-nfold-doc.tex +++ b/Master/texmf-dist/doc/latex/tikz-nfold/tikz-nfold-doc.tex @@ -1,4 +1,4 @@ -%% tikz-nfold.sty +%% tikz-nfold-doc.tex %% Copyright 2023 Jonathan Schulz % % This work may be distributed and/or modified under the @@ -13,8 +13,12 @@ % % The Current Maintainer of this work is Jonathan Schulz. % -% This work consists of the files pgflibrarybezieroffset.code.tex, -% tikzlibrarynfold.code.tex, tikz-nfold-doc.tex, and tikz-nfold-doc.pdf. +% This work consists of the files +% pgflibrarybezieroffset.code.tex, pgflibrarynfold.code.tex, pgflibraryoffsetpath.code.tex, tikz-nfold-doc.tex, tikzlibrarynfold.code.tex, tikz-nfold-doc.tex, and tikz-nfold-doc.pdf. +% +% +% A commented version of this file can be found on https://github.com/jonschz/tikz-nfold . +% \documentclass[12pt,a4paper]{article} @@ -27,7 +31,6 @@ \usepackage{parskip} \usepackage[margin=2.5cm]{geometry} -% recommended order: 1) hyperref 2) amsthm 3) cleveref 4) \newtheorem \usepackage[colorlinks]{hyperref} \usepackage{amsmath} \usepackage{amsthm} @@ -38,7 +41,6 @@ \theoremstyle{definition} \newtheorem{definition}{Definition}[section] -%\newcommand{\todo}[1]{{\color{red}\bfseries#1}} \newcommand{\tikzdouble}{\texttt{/tikz/double}} \newcommand{\nfold}{\texttt{nfold}} \newcommand{\tikznfold}{\texttt{/tikz/nfold}} @@ -52,7 +54,6 @@ \newcommand{\uv}{\vec{u}} \newcommand{\vv}{\vec{v}} -% to be used in pre=... to stop the proparation of warnings outside of tkzexample environments \makeatletter \def\disablewarnings{\def\pgfutil@packagewarning##1##2{}} \makeatother @@ -209,6 +210,19 @@ This package is by no means perfect, and even if it were, there would still be s \subsection{Impossible or very hard to fix} \begin{itemize} + \item Self-intersecting paths do not have the expected intersections: +\begin{tkzexample}[latex=4.5cm] +\begin{tikzpicture} + \draw[double distance=5pt, line width=1pt] + (0,2.5) -- (1,2.5) (1,3) -- (1,2) + (2,2) -- (3,2) rectangle (4,3); + \node[right] at (0,3.5) {double:}; + \draw[double distance=5pt, line width=1pt, nfold] + (0,.5) -- (1,.5) (1,1) -- (1,0) + (2,0) -- (3,0) rectangle (4,1); + \node[right] at (0,1.5) {nfold:}; +\end{tikzpicture} +\end{tkzexample} \item \nfold{} struggles with high curvatures and wide paths: Let $\kappa(t)$ be the curvature of the path in a given point, and let $\texttt{double distance} = \alpha$. If $\kappa(t) > \frac{2}{\alpha}$ (i.e. the radius of the osculating circle is smaller than half the width of the path) for some $0 \leq t \leq 1$, the output of \nfold{} will not be correct: \begin{tkzexample}[latex=4.25cm] \begin{tikzpicture} @@ -268,12 +282,14 @@ This package is by no means perfect, and even if it were, there would still be s \section{The basic layer \texttt{pgf} commands} +This package contains three \emph{pgf} libraries building upon one another: \texttt{bezieroffset}, \texttt{offsetpath}, and \nfold. All of these are contained in the \emph{TikZ} library \nfold. + \subsection{Offsetting curves} -This package provides some basic layer commands for offsetting curves and straight lines. Use +This library provides some basic layer commands for offsetting curves and straight lines. Use \begin{verbatim} \usepgflibrary{bezieroffset} \end{verbatim} -to only import the base layer library. The following commands are provided: +to only import this base layer library. The following commands are provided: \begin{itemize} \item \verb|\pgfoffsetcurve{pt1}{pt2}{pt3}{pt4}{distance}|\\% This macro draws the parallel of a Bézier curve. The first four parameters are the control points of the Bézier curve (e.g.\ in the form of \verb|\pgfpoint{}{}|), the fifth parameter is the distance by which the curve should be offset. A negative value offsets the curve in the opposite direction. This macro begins with a \verb|\pgfpointmoveto| to the offset of \texttt{pt1}. @@ -286,7 +302,7 @@ to only import the base layer library. The following commands are provided: \end{itemize} \subsection{Offsetting paths} -The following macros are part of the TikZ library \nfold{} and offset an entire soft path. +The following macros are part of the pgf library \texttt{offsetpath} and offset the whole softpath. \begin{itemize} \item \verb|\pgfoffsetpath{softpath}{distance}|\\% This macro offsets \texttt{softpath} by \texttt{distance}. The latter may be negative. @@ -295,7 +311,7 @@ The following macros are part of the TikZ library \nfold{} and offset an entire \item \verb|\pgfoffsetpathqfraction{softpath}{hwidth}{fraction}|\\% This macro is a quicker version of the previous macro does not parse the input values using the \texttt{pgfmath}-engine. \item \verb|\pgfoffsetpathindex{softpath}{width}{i}{n}|\\% - In this convenience method, \texttt{i} and \texttt{n} are integers with $1 \leq i \leq n$. It calls the previous macro with \texttt{fraction=-1.0} for \texttt{i=1} and with \texttt{fraction=1.0} for \texttt{i=n} and is thus capable of reproducing the output of \texttt{/tikz/nfold=n} (albeit in a less efficient way). + In this convenience method, \texttt{i} and \texttt{n} are integers with $1 \leq i \leq n$. It calls the previous macro with \texttt{fraction=-1.0} for \texttt{i=1} and with \texttt{fraction=1.0} for \texttt{i=n}, hence it is capable of reproducing the output of \texttt{/tikz/nfold=n} (albeit in a less efficient way). \end{itemize} In the following example we see how \verb|\pgfoffsetpath{..}{0pt}| reproduces the input path (rendered in black) and how \verb|\pgfoffsetpathfraction{..}{8pt}{0}| differs. \begin{tkzexample}[latex=4cm] @@ -329,6 +345,7 @@ Here we see how the commands can be used to customise $n$-fold paths: \section{Version history} \begin{itemize} + \item \textbf{v1.0.0}: Restructure and bug fixes \item \textbf{v0.1.3}: Bug fixes \item \textbf{v0.1.2}: Bug fixes \item \textbf{v0.1.1}: Closing paths and structural changes @@ -497,7 +514,6 @@ Note that $-\tfrac{\pi}{3} \leq \beta \leq \tfrac{\pi}{3}$ (and hence $\cos(\bet \end{equation} and all of these terms can be computed directly from dot and cross products of vectors between the original control points. To summarise, let $\vv_{ij} := \overrightarrow{A_iA_j}$, and let $\vv_0$, $\vv_1$ be the normalised tangents at $t=0$ and $t=1$, respectively (see \cref{subsec:stabilisation} how they are computed). Then \begin{equation} -% for checking \overline{A'_1A'_2} = \overline{A_1A_2} + \frac{d}{\overline{A_1A_4}^2}\cdot\left(\vv_{12} \times \vv_{14} - \vv_{12}\cdot\vv_{14} \frac{\vv_{14}\times\tv_1}{\vv_{14}\cdot\tv_1} \right) \ . \end{equation} Let furthermore $\uv_{ij} := \vv_{ij}/|\vv_{ij}|$ be the normalised vectors. Then we find diff --git a/Master/texmf-dist/tex/latex/tikz-nfold/pgflibrarybezieroffset.code.tex b/Master/texmf-dist/tex/latex/tikz-nfold/pgflibrarybezieroffset.code.tex index 275fa0fdf39..06c9912f6c2 100644 --- a/Master/texmf-dist/tex/latex/tikz-nfold/pgflibrarybezieroffset.code.tex +++ b/Master/texmf-dist/tex/latex/tikz-nfold/pgflibrarybezieroffset.code.tex @@ -1,4 +1,4 @@ -%% tikz-nfold.sty +%% pgflibrarybezieroffset.code.tex %% Copyright 2023 Jonathan Schulz % % This work may be distributed and/or modified under the @@ -13,102 +13,40 @@ % % The Current Maintainer of this work is Jonathan Schulz. % -% This work consists of the files pgflibrarybezieroffset.code.tex, -% tikzlibrarynfold.code.tex, tikz-nfold-doc.tex, and tikz-nfold-doc.pdf. +% This work consists of the files +% pgflibrarybezieroffset.code.tex, pgflibrarynfold.code.tex, pgflibraryoffsetpath.code.tex, tikz-nfold-doc.tex, tikzlibrarynfold.code.tex, tikz-nfold-doc.tex, and tikz-nfold-doc.pdf. +% +% +% A commented version of this file can be found on https://github.com/jonschz/tikz-nfold . +% -% Don't delete this code in case we need it in the future -% -% Split a Bezier curve (de Casteljau's algorithm) -% #1 = time (between 0 and 1) -% #2-#5: control points -% Outputs the first part into \pgf@splitbezier@i@i, ... , \pgf@splitbezier@i@iv, -% and the second part into \pgf@splitbezier@ii@i, ... , \pgf@splitbezier@ii@iv. -%\def\pgf@splitbezier#1#2#3#4#5{% -% % based on pgfcorepoints.code.tex, \pgfpointcurveattime -% \edef\pgf@time@s{#1}% -% \pgf@x=-\pgf@time@s pt% -% \advance\pgf@x by 1pt% -% \edef\pgf@time@t{\pgf@sys@tonumber{\pgf@x}}% -% % P^0_3 -% \pgfextract@process\pgf@splitbezier@ii@iv{#5}% -% \pgf@xc=\pgf@x% -% \pgf@yc=\pgf@y% -% % P^0_2 -% \pgf@process{#4}% -% \pgf@xb=\pgf@x% -% \pgf@yb=\pgf@y% -% % P^0_1 -% \pgf@process{#3}% -% \pgf@xa=\pgf@x% -% \pgf@ya=\pgf@y% -% % P^0_0 -% \pgfextract@process\pgf@splitbezier@i@i{#2}% -% % First iteration: -% % P^1_0 -% \pgf@x=\pgf@time@t\pgf@x\advance\pgf@x by\pgf@time@s\pgf@xa% -% \pgf@y=\pgf@time@t\pgf@y\advance\pgf@y by\pgf@time@s\pgf@ya% -% \pgfextract@process\pgf@splitbezier@i@ii{}% -% % P^1_1 -% \pgf@xa=\pgf@time@t\pgf@xa\advance\pgf@xa by\pgf@time@s\pgf@xb% -% \pgf@ya=\pgf@time@t\pgf@ya\advance\pgf@ya by\pgf@time@s\pgf@yb% -% % P^1_2 -% \pgf@xb=\pgf@time@t\pgf@xb\advance\pgf@xb by\pgf@time@s\pgf@xc% -% \pgf@yb=\pgf@time@t\pgf@yb\advance\pgf@yb by\pgf@time@s\pgf@yc% -% \edef\pgf@splitbezier@ii@iii{\noexpand\pgfqpoint{\the\pgf@xb}{\the\pgf@yb}}% -% % P^2_0 -% \pgf@x=\pgf@time@t\pgf@x\advance\pgf@x by\pgf@time@s\pgf@xa% -% \pgf@y=\pgf@time@t\pgf@y\advance\pgf@y by\pgf@time@s\pgf@ya% -% \pgfextract@process\pgf@splitbezier@i@iii{}% -% % P^2_1 -% \pgf@xa=\pgf@time@t\pgf@xa\advance\pgf@xa by\pgf@time@s\pgf@xb% -% \pgf@ya=\pgf@time@t\pgf@ya\advance\pgf@ya by\pgf@time@s\pgf@yb% -% \edef\pgf@splitbezier@ii@ii{\noexpand\pgfqpoint{\the\pgf@xa}{\the\pgf@ya}}% -% % P^3_0 -% \pgf@x=\pgf@time@t\pgf@x\advance\pgf@x by\pgf@time@s\pgf@xa% -% \pgf@y=\pgf@time@t\pgf@y\advance\pgf@y by\pgf@time@s\pgf@ya% -% \pgfextract@process\pgf@splitbezier@i@iv{}% -% \let\pgf@splitbezier@ii@i\pgf@splitbezier@i@iv -%} -% Split the Bezier curve defined by #1-#4 at t=0.5 using de Casteljau's algorithm \def\pgf@halfsplitbezier#1#2#3#4{% - % based on pgfcorepoints.code.tex, \pgfpointcurveattime - % P^0_3 \pgfextract@process\pgf@splitbezier@ii@iv{#4}% \pgf@xc=\pgf@x% \pgf@yc=\pgf@y% - % P^0_2 - \pgf@process{#3}% removing these does not yield a significant speedup + \pgf@process{#3}% \pgf@xb=\pgf@x% \pgf@yb=\pgf@y% - % P^0_1 \pgf@process{#2}% \pgf@xa=\pgf@x% \pgf@ya=\pgf@y% - % P^0_0 \pgfextract@process\pgf@splitbezier@i@i{#1}% - % First iteration: - % P^1_0 \pgf@x=.5\pgf@x\advance\pgf@x by.5\pgf@xa% \pgf@y=.5\pgf@y\advance\pgf@y by.5\pgf@ya% \edef\pgf@splitbezier@i@ii{\pgf@x\the\pgf@x\pgf@y\the\pgf@y}% - % P^1_1 \pgf@xa=.5\pgf@xa\advance\pgf@xa by.5\pgf@xb% \pgf@ya=.5\pgf@ya\advance\pgf@ya by.5\pgf@yb% - % P^1_2 \pgf@xb=.5\pgf@xb\advance\pgf@xb by.5\pgf@xc% \pgf@yb=.5\pgf@yb\advance\pgf@yb by.5\pgf@yc% \edef\pgf@splitbezier@ii@iii{\pgf@x\the\pgf@xb\pgf@y\the\pgf@yb}% - % P^2_0 \pgf@x=.5\pgf@x\advance\pgf@x by.5\pgf@xa% \pgf@y=.5\pgf@y\advance\pgf@y by.5\pgf@ya% \edef\pgf@splitbezier@i@iii{\pgf@x\the\pgf@x\pgf@y\the\pgf@y}% - % P^2_1 \pgf@xa=.5\pgf@xa\advance\pgf@xa by.5\pgf@xb% \pgf@ya=.5\pgf@ya\advance\pgf@ya by.5\pgf@yb% \edef\pgf@splitbezier@ii@ii{\pgf@x\the\pgf@xa\pgf@y\the\pgf@ya}% - % P^3_0 \pgf@x=.5\pgf@x\advance\pgf@x by.5\pgf@xa% \pgf@y=.5\pgf@y\advance\pgf@y by.5\pgf@ya% \edef\pgf@splitbezier@i@iv{\pgf@x\the\pgf@x\pgf@y\the\pgf@y}% @@ -116,7 +54,6 @@ } -% computes the cross product and puts it into \pgfmathresult \def\pgfmathcrossproduct#1#2{% \begingroup \pgf@process{#1}% @@ -159,7 +96,6 @@ \endgroup\pgf@temp } -% Calculates abs(\pgf@x) + abs(\pgf@y) in #1 \def\pgfpointtaxicabnorm#1{% \ifdim\pgf@x<0pt #1=-\pgf@x @@ -173,24 +109,18 @@ \fi } -% Computes the normalised tangents of a given Bezier curve and stores them in \pgf@tmp@tang@i and \pgf@tmp@tang@ii. -% Also computes the angles and stores them in \pgf@tmp@angle@i and \pgf@tmp@angle@ii. -% All degenerate cases are covered. For a triple degenerate curve (all points equal), the vector (1,0) is returned. \def\pgf@offset@compute@tangents#1#2#3#4{% - \pgf@process{\pgfpointdiff{#1}{#2}}% unintuitively, this is PTii - PTi + \pgf@process{\pgfpointdiff{#1}{#2}}% \pgfpointtaxicabnorm\pgf@xa \ifdim\pgf@xa<0.1pt\relax - % edge case: first point and first control point are equal \pgf@process{\pgfpointdiff{#1}{#3}}% \pgfpointtaxicabnorm\pgf@xa \ifdim\pgf@xa<0.1pt\relax - % edge case: first three points are equal \pgf@process{\pgfpointdiff{#1}{#4}}% \fi \fi \pgfextract@process\pgf@tmp@tang@i{% \pgfpointnormalised{}% - % \pgfpointnormalised stores the angle of the vector in \pgf@tmp \global\let\pgf@nfold@tmp\pgf@tmp% }% \let\pgf@tmp@angle@i\pgf@nfold@tmp% @@ -208,37 +138,25 @@ } -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% Offsetting a simple section % -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \def\pgf@offset@bezier@segment#1#2#3#4#5{% - % normalise tangents and normals; this avoids overflow issues later, and we need - % the normal vector to be of length 1 anyway \pgf@offset@compute@tangents{#1}{#2}{#3}{#4}% \pgf@offset@bezier@segment@{#1}{#2}{#3}{#4}{#5}% } -% this version assumes that the tangents have been precomputed in \pgf@tmp@tang@i and @ii \def\pgf@offset@bezier@segment@#1#2#3#4#5{% - % offset A1 - % compute the normal \pgf@tmp@tang@i \edef\pgf@tmp@normal@i{\noexpand\pgfqpoint{-\the\pgf@y}{\the\pgf@x}}% \pgfextract@process\pgf@bezier@offset@i {\pgfpointadd{\pgfpointscale{#5}{\pgf@tmp@normal@i}}{#1}}% - % offset A4 \pgf@tmp@tang@ii \edef\pgf@tmp@normal@ii{\noexpand\pgfqpoint{-\the\pgf@y}{\the\pgf@x}}% \pgfextract@process\pgf@bezier@offset@iv {\pgfpointadd{\pgfpointscale{#5}{\pgf@tmp@normal@ii}}{#4}}% - % now compute A'_2 and A'_3 \pgf@process{\pgfpointdiff{#1}{#4}}% \pgfmathveclen@{\pgf@sys@tonumber\pgf@x}{\pgf@sys@tonumber\pgf@y}% \let\pgf@tmp@secantlen\pgfmathresult \ifdim\pgf@tmp@secantlen pt<0.1pt\relax - % Edge case: Either the curve is degenerate to a point or it is not simple. - % Either way we offset A1 and A4, and preserve the vectors A1A2 and A3A4. \pgfutil@packagewarning{tikz-nfold}{first and last point are too close, expect glitches}% \pgfextract@process\pgf@bezier@offset@ii {\pgfpointadd{\pgf@bezier@offset@i}{\pgfpointdiff{#1}{#2}}}% @@ -248,22 +166,18 @@ \pgfextract@process\pgf@tmp@secant{\pgfpointnormalised{}}% \pgfmathcrossdot{}{\pgf@tmp@tang@ii}% \ifdim\pgf@tmp@dot pt<.5pt\relax% - % this can only happen in non-simple curves \pgfutil@packagewarning{tikz-nfold}{cosine of \pgf@tmp@dot\space clamped to 0.5 in non-simple segment}% \def\pgf@tmp@dot{.5}% \fi% \pgfmathdivide@{\pgf@tmp@cross}{\pgf@tmp@dot}% \let\pgf@tmp@tanbeta\pgfmathresult \pgfmathcrossdot{\pgf@tmp@secant}{\pgfpointnormalised{\pgfpointdiff{#1}{#2}}} - % There are cases where we want #5/secantlen to be quite large, so we should not clamp the value here - % \pgfmathparse{1 + #5/\pgf@tmp@secantlen*(\pgf@tmp@cross - \pgf@tmp@dot*\pgf@tmp@tanbeta)}% \pgfmath@offset@calculate@scale{\pgf@tmp@secantlen}{\pgf@tmp@cross}{\pgf@tmp@dot}{\pgf@tmp@tanbeta}{#5}% \pgfextract@process\pgf@bezier@offset@ii{% \pgfpointadd {\pgf@bezier@offset@i} {\pgfqpointscale{\pgfmathresult}{\pgfpointdiff{#1}{#2}}}% }% - % third control point \pgfmathcrossdot{\pgf@tmp@secant}{\pgf@tmp@tang@i}% \ifdim\pgf@tmp@dot pt<.5pt\relax \pgfutil@packagewarning{tikz-nfold}{cosine of \pgf@tmp@dot\space clamped to 0.5 in non-simple segment}% @@ -272,7 +186,6 @@ \pgfmathdivide@{\pgf@tmp@cross}{\pgf@tmp@dot}% \let\pgf@tmp@tanbeta\pgfmathresult \pgfmathcrossdot{\pgf@tmp@secant}{\pgfpointnormalised{\pgfpointdiff{#4}{#3}}}% - % \pgfmathparse{1 + #5/\pgf@tmp@secantlen*(\pgf@tmp@cross - \pgf@tmp@dot*\pgf@tmp@tanbeta)}% \pgfmath@offset@calculate@scale{\pgf@tmp@secantlen}{\pgf@tmp@cross}{\pgf@tmp@dot}{\pgf@tmp@tanbeta}{#5}% \pgfextract@process\pgf@bezier@offset@iii{% \pgfpointadd @@ -282,12 +195,6 @@ \fi } -% calculates 1+#5/#1*(#2-#3*#4) -% #1 = secantlen -% #2 = cross -% #3 = dot -% #4 = tanbeta -% #5 = #5 (offset) \def\pgfmath@offset@calculate@scale#1#2#3#4#5{% \begingroup \pgfmathmultiply@{#3}{#4}% @@ -301,48 +208,24 @@ \endgroup } -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% Subdividing and offsetting % -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% Maximum level of recursion. The theoretical limit to the number of subdivisions in the final curve -% is given by 2^\pgf@offset@max@recursion \newcount\pgf@offset@max@recursion \pgf@offset@max@recursion=4 -% -% Subdivides a Bezier curve into "simple" segments (according to the definition below), -% offsets the segments, and draws them. Because offsetting also involves relocating -% the starting points, these macros come in two variants: with and without a \pgfpathmoveto{} -% to the new starting point. -% -% Interface: -% #1-#4: control points of the whole Bezier curve -% #5: offset \def\pgfoffsetcurve#1#2#3#4#5{% \pgfoffsetcurvecallback{#1}{#2}{#3}{#4}{#5}{\pgf@nfold@callback@move}% } \def\pgfoffsetcurvenomove#1#2#3#4#5{% - \pgfoffsetcurvecallback{#1}{#2}{#3}{#4}{#5}{\pgf@nfold@callback@nomove}% + \pgfoffsetcurvecallback{#1}{#2}{#3}{#4}{#5}{\pgf@nfold@callback@nomove}% } -% Arguments: -% #1-#4: control points of the segment -% #5: =0 if this is the first segment of the curve, =1 otherwise -% (checking for #5=0 allows us to draw the curve without interruptions) \def\pgf@nfold@callback@move#1#2#3#4#5{% \if#50\pgfpathmoveto{#1}\fi% \pgfpathcurveto{#2}{#3}{#4}% } -% this version never does a moveto at the start. Useful for drawing a path consisting of -% multiple Bezier curves. \def\pgf@nfold@callback@nomove#1#2#3#4#5{\pgfpathcurveto{#2}{#3}{#4}} -% This macro subdivides and offsets a curve and executes a given callback on every offset simple segment. -% #1-#4: control points of the segment -% #5: =0 if this is the first segment of the curve, =1 otherwise -% #6: callback (see \pgf@nfold@callback@move) for the parameters \def\pgfoffsetcurvecallback#1#2#3#4#5#6{% \edef\pgf@offset@tmp@callback##1##2##3##4##5{% \noexpand\pgf@offset@bezier@segment{##1}{##2}{##3}{##4}{#5}% @@ -352,11 +235,6 @@ } -% This macro subdivides (but does not offset) a curve and executes a callback on every simple segment. -% #1-#4: control points -% #5: recursion limit (decreases on every recursive call) -% #6: =0 if this is the start of the curve, =1 otherwise -% #7: callback for output (see above) \newif\ifpgf@offset@subdivide \def\pgf@subdividecurve#1#2#3#4#5#6#7{% \begingroup% @@ -369,32 +247,24 @@ \endgroup% } -% This macro assumes that the curve is defined in \pgf@ctrl@i-\pgf@ctrl@iv -% and that its tangents have already been computed. \def\pgf@subdividecurve@#1#2#3{% \pgf@offset@subdividefalse% \c@pgf@counta=#1\relax \advance\c@pgf@counta by -1 - % Use the non-degenerate tangents for the simplicity check \pgfextract@process\pgf@itoiv{\pgfpointdiff{\pgf@ctrl@i}{\pgf@ctrl@iv}}% \pgfmathcrossproduct{\pgf@itoiv}{\pgf@tmp@tang@i}% \let\firstcross\pgfmathresult \pgfmathcrossproduct{\pgf@itoiv}{\pgf@tmp@tang@ii}% - % First simplicity check: Are A2 and A3 on the same side of the A1-A4 line? - % -> compute the sign of the cross products, use the sign function to avoid overflows - % just give it a pass if one of them is zero, hence 2 and 3 at the end \ifnum \ifdim \firstcross pt<0pt -1\else\ifdim \firstcross pt>0pt 1\else 2\fi\fi =\ifdim\pgfmathresult pt<0pt -1\else\ifdim\pgfmathresult pt>0pt 1\else 3\fi\fi - \relax % the \relax is important! + \relax % \pgf@offset@subdividetrue% \else% - % Second simplicity check: How large is the angle between the tangents in A1 and A4? \pgfmathdotproduct{\pgf@tmp@tang@i}{\pgf@tmp@tang@ii}% \ifdim\pgfmathresult pt<.5pt\relax% \pgf@offset@subdividetrue% \else - % Third simplicity check: Put a limit on the lengths of the i-ii and iii-iv vectors combined \pgf@itoiv \pgfmathveclen@{\pgf@sys@tonumber\pgf@x}{\pgf@sys@tonumber\pgf@y}% \pgf@xa=\pgfmathresult pt @@ -404,7 +274,6 @@ \pgf@process{\pgfpointdiff{\pgf@ctrl@iii}{\pgf@ctrl@iv}}% \pgfmathveclen@{\pgf@sys@tonumber\pgf@x}{\pgf@sys@tonumber\pgf@y}% \advance\pgf@xb by \pgfmathresult pt - % veclen(iv-i) < veclen(ii-i) + veclen(iv-iii) \ifdim\pgf@xa<\pgf@xb \pgf@offset@subdividetrue \fi @@ -412,27 +281,19 @@ \fi% \ifpgf@offset@subdivide% \ifnum\c@pgf@counta<0% - % We hit the recursion limit but the segment is not simple \pgfutil@packagewarning{tikz-nfold}{Recursion limit reached, glitches may occur. % Consider increasing \string\pgf@offset@max@recursion}% - % Try to offset the curve anyway. The result will not be precise, - % but the code is sufficiently robust to not crash #3{\pgf@ctrl@i}{\pgf@ctrl@ii}{\pgf@ctrl@iii}{\pgf@ctrl@iv}{#2}% \else - % split the non-simple segment and execute recursive calls \pgf@halfsplitbezier{\pgf@ctrl@i}{\pgf@ctrl@ii}{\pgf@ctrl@iii}{\pgf@ctrl@iv}% - % compute the tangent at the spitting point; this vector is only zero if the curve - % is degenerate to a point, in which case we can't compute the tangent anyway \pgfextract@process\pgf@middletangent{% \pgfpointnormalised{\pgfpointdiff{\pgf@splitbezier@i@iii}{\pgf@splitbezier@i@iv}}}% \begingroup% - % we need a group to avoid overwriting variables in recursive calls \let\pgf@tmp@tang@ii\pgf@middletangent% \let\pgf@ctrl@i\pgf@splitbezier@i@i% \let\pgf@ctrl@ii\pgf@splitbezier@i@ii% \let\pgf@ctrl@iii\pgf@splitbezier@i@iii% \let\pgf@ctrl@iv\pgf@splitbezier@i@iv% - % pass on the "start of the curve flag" only to the first term \pgf@subdividecurve@{\c@pgf@counta}{#2}{#3}% \endgroup% \begingroup% @@ -445,25 +306,16 @@ \endgroup% \fi% \else% - % curve is simple #3{\pgf@ctrl@i}{\pgf@ctrl@ii}{\pgf@ctrl@iii}{\pgf@ctrl@iv}{#2}% \fi% } -% -% Offsetting straight lines -% ------------------------- -% -% For convenience we also provide macros that offset straight lines. These also come in two variants -% similar to the macros for curves. -% \def\pgfoffsetline#1#2#3{% \pgfmathparse{#3}% \pgfoffsetline@{#1}{#2}{\pgfmathresult}{\pgfpointnormalised{\pgfpointdiff{#1}{#2}}}% } -% a quicker version in case we already know the tangent and #3 is a number without unit \def\pgfoffsetline@#1#2#3#4{% \pgfqpointscale{#3}{#4}% \pgf@xc=-\pgf@y diff --git a/Master/texmf-dist/tex/latex/tikz-nfold/pgflibrarynfold.code.tex b/Master/texmf-dist/tex/latex/tikz-nfold/pgflibrarynfold.code.tex new file mode 100644 index 00000000000..f593c787b42 --- /dev/null +++ b/Master/texmf-dist/tex/latex/tikz-nfold/pgflibrarynfold.code.tex @@ -0,0 +1,88 @@ +%% pgflibrarynfold.code.tex +%% Copyright 2023 Jonathan Schulz +% +% This work may be distributed and/or modified under the +% conditions of the LaTeX Project Public License, either version 1.3c +% of this license or (at your option) any later version. +% The latest version of this license is in +% http://www.latex-project.org/lppl.txt +% and version 1.3c or later is part of all distributions of LaTeX +% version 2008-05-04 or later. +% +% This work has the LPPL maintenance status 'maintained'. +% +% The Current Maintainer of this work is Jonathan Schulz. +% +% This work consists of the files +% pgflibrarybezieroffset.code.tex, pgflibrarynfold.code.tex, pgflibraryoffsetpath.code.tex, tikz-nfold-doc.tex, tikzlibrarynfold.code.tex, tikz-nfold-doc.tex, and tikz-nfold-doc.pdf. +% +% +% A commented version of this file can be found on https://github.com/jonschz/tikz-nfold . +% + + +\usepgflibrary{offsetpath} + + +\newcount\pgf@nfold@index +\def\pgf@nfold@run@loop{% + \pgf@nfold@index=\pgf@nfold@order% + \pgf@nfold@run@loop@% +} + +\def\pgf@nfold@run@loop@{% + \pgf@nfold@loop@inner% + \advance\pgf@nfold@index by -1\relax + \ifnum\pgf@nfold@index>0\relax% + \pgf@nfold@run@loop@% + \fi% +} + +\def\pgf@nfold@loop@inner{% + \pgfmathsetmacro{\pgf@nfold@shift@fraction}% + {-1+2*(\pgf@nfold@index-1)/(\pgf@nfold@order-1)}% + \pgfmathsetmacro{\pgf@nfold@shiftamount}{\pgf@nfold@hwidth*\pgf@nfold@shift@fraction} + \pgftransformreset% + \parsedpath% + \pgfsyssoftpath@flushcurrentpath% + \pgf@up@action% +} + +\def\pgf@nfold@compute@widths@from@double{ + \pgf@x=\pgflinewidth\relax% + \pgf@y=\pgf@x\relax% + \advance\pgf@x-\pgfinnerlinewidth\relax% + \advance\pgf@y+\pgfinnerlinewidth\relax% + \pgf@x=.5\pgf@x\relax% + \pgf@y=.25\pgf@y\relax% +} + +\def\pgf@nfold@render@cached@softpath{% + \pgfscope% + \pgf@nfold@compute@widths@from@double% + \pgfsetlinewidth\pgf@x% + \edef\pgf@nfold@hwidth{\the\pgf@y}% + \pgfprocessround{\pgf@nfold@cachedpath}{\pgf@nfold@cachedpath}% + \pgf@nfold@parsearrows% + \pgf@nfold@parsesoftpath{\pgf@nfold@cachedpath}{\parsedpath}% + \pgf@nfold@run@loop% + \endpgfscope% +} + + +\pgfkeys{ + /pgf/nfold/.code={% + \pgf@nfold@order=#1\relax% + \ifnum\pgf@nfold@order<1\relax% + \pgfutil@packageerror{tikz-nfold}{The key /pgf/nfold must take a value of at least 1, got \the\pgf@nfold@order}{}% + \fi% + \ifnum\pgf@nfold@order>\pgf@nfold@intersec@numcached\relax + \ifdefined\pgfintersectionofpaths\else + \pgf@nfold@intersectionsnotloadedtrue + \fi + \fi + }, + /pgf/nfold/.default=2 +} + +\endinput diff --git a/Master/texmf-dist/tex/latex/tikz-nfold/pgflibraryoffsetpath.code.tex b/Master/texmf-dist/tex/latex/tikz-nfold/pgflibraryoffsetpath.code.tex new file mode 100644 index 00000000000..645812ecb13 --- /dev/null +++ b/Master/texmf-dist/tex/latex/tikz-nfold/pgflibraryoffsetpath.code.tex @@ -0,0 +1,913 @@ +%% pgflibraryoffsetpath.code.tex +%% Copyright 2023 Jonathan Schulz +% +% This work may be distributed and/or modified under the +% conditions of the LaTeX Project Public License, either version 1.3c +% of this license or (at your option) any later version. +% The latest version of this license is in +% http://www.latex-project.org/lppl.txt +% and version 1.3c or later is part of all distributions of LaTeX +% version 2008-05-04 or later. +% +% This work has the LPPL maintenance status 'maintained'. +% +% The Current Maintainer of this work is Jonathan Schulz. +% +% This work consists of the files +% pgflibrarybezieroffset.code.tex, pgflibrarynfold.code.tex, pgflibraryoffsetpath.code.tex, tikz-nfold-doc.tex, tikzlibrarynfold.code.tex, tikz-nfold-doc.tex, and tikz-nfold-doc.pdf. +% +% +% A commented version of this file can be found on https://github.com/jonschz/tikz-nfold . +% + +\usepgflibrary{bezieroffset} + + + + + + +\gdef\pgf@nfold@cached@miterlimit{10} +\let\pgf@nfold@old@miterlimit\pgfsetmiterlimit +\def\pgfsetmiterlimit#1{% + \pgf@nfold@old@miterlimit{#1}% + \edef\pgf@nfold@cached@miterlimit{#1}% +} + +\global\let\pgf@cached@linejoin=m% +\let\pgf@nfold@old@setbeveljoin\pgfsetbeveljoin +\let\pgf@nfold@old@setmiterjoin\pgfsetmiterjoin +\let\pgf@nfold@old@setroundjoin\pgfsetroundjoin +\def\pgfsetbeveljoin{% + \pgf@nfold@old@setbeveljoin% + \let\pgf@cached@linejoin=b% +} +\def\pgfsetmiterjoin{% + \pgf@nfold@old@setmiterjoin% + \let\pgf@cached@linejoin=m% +} +\def\pgfsetroundjoin{% + \pgf@nfold@old@setroundjoin% + \let\pgf@cached@linejoin=r% +} + + + +\def\pgf@nfold@miterjoin{ + \pgfpathlineto{ + \pgfpointadd{\pgf@nfold@join@centre}{% + \pgfpointpolar{\pgf@nfold@firstang+.5*\pgf@nfold@deltaphi+90}% + {\pgf@nfold@shiftamount/cos(.5*\pgf@nfold@deltaphi)}% + }% + }% +} + +\def\pgf@nfold@beveljoin{ + \pgfmathsetlengthmacro{\bevelouterprotrusion}% + {\pgf@nfold@shortenstartjoin pt - .5*\pgflinewidth*abs(tan(.25*\pgf@nfold@deltaphi))} + \pgfmathsetmacro{\bevelshorten}{2*\insidepercentage*abs(tan(.25*\pgf@nfold@deltaphi))} + \pgfmathparse{\bevelshorten < abs(sin(.5*\pgf@nfold@deltaphi))} + \ifnum\pgfmathresult=1\relax + \pgfmathsetlengthmacro{\bevelextension}{\bevelouterprotrusion-\bevelshorten*\pgf@nfold@hwidth} + \pgfpointadd{\pgf@nfold@join@start}{\pgfpointpolar{\pgf@nfold@firstang}{\bevelextension}} + \pgfpathlineto{} + \pgfpointadd{\pgf@nfold@join@end}{\pgfpointpolar{\pgf@nfold@secondang}{-\bevelextension}} + \pgfpathlineto{} + \else + \pgf@nfold@miterjoin + \fi +} + +\def\pgf@nfold@roundjoin{ + \ifdim\insidepercentage pt<.5pt\relax + \pgfpointadd{\pgf@nfold@join@start}{\pgfpointpolar{\pgf@nfold@firstang}{\pgf@nfold@shortenstartjoin}} + \pgfpathlineto{} + \pgfmathsetmacro\pgf@tmp@firstang{\pgf@nfold@firstang+90*\turnindicator} + \pgfpatharc% + {\pgf@tmp@firstang}% + {\pgf@tmp@firstang+\pgf@nfold@deltaphi}% + {abs(\pgf@nfold@shift@fraction)*\pgf@nfold@hwidth}% + \else + \pgf@nfold@miterjoin + \fi +} + +\def\pgf@nfold@token@join#1#2#3#4#5#6#7#8{% + \def\pgf@nfold@join@centre{#1}% + \def\pgf@nfold@join@prevend{#2}% + \def\pgf@nfold@join@nextstart{#3}% + \def\pgf@nfold@firstang{#4}% + \def\pgf@nfold@secondang{#5}% + \pgfextract@process\pgf@nfold@join@start{% + \pgfpointadd{#2}{\pgfpointpolar{\pgf@nfold@firstang+90}{\pgf@nfold@shiftamount}}}% + \pgfextract@process\pgf@nfold@join@end{% + \pgfpointadd{#3}{\pgfpointpolar{\pgf@nfold@secondang+90}{\pgf@nfold@shiftamount}}}% + \pgf@process{\pgfpointdiff{\pgf@nfold@join@start}{\pgf@nfold@join@end}} + \pgfpointtaxicabnorm\pgfutil@tempdima + \ifdim\pgfutil@tempdima>0.1pt\relax + \def\pgf@nfold@deltaphi{#6}% + \def\pgf@nfold@shortenstartjoin{#7}% + \ifdim\pgf@nfold@deltaphi pt<0pt + \def\turnindicator{1} + \else + \def\turnindicator{-1} + \fi + \pgfutil@tempdima=\pgf@nfold@shift@fraction pt\relax + \pgfutil@tempdima=\turnindicator\pgfutil@tempdima + \advance\pgfutil@tempdima by-1pt\relax + \pgfutil@tempdima=-.5\pgfutil@tempdima + \edef\insidepercentage{\pgf@sys@tonumber\pgfutil@tempdima}% + #8% + \fi +} + + +\def\pgf@nfold@process@join{% + \pgf@xa=\pgf@nfold@deltaphi@start pt\relax + \ifdim\pgf@xa<0pt\relax + \pgf@xa=-\pgf@xa + \fi + \ifdim\pgf@xa>1pt\relax + \edef\pgf@nfold@jointype{\pgf@cached@linejoin} + \if\pgf@cached@linejoin m% + \pgf@xa=.5\pgf@xa + \pgfmathcos@{\pgf@sys@tonumber\pgf@xa} + \pgf@xa=\pgfmathresult pt\relax + \pgf@xa=\pgf@nfold@cached@miterlimit\pgf@xa + \ifdim\pgf@xa>1pt\relax + \def\pgf@nfold@tmp@joinmacro{\pgf@nfold@miterjoin} + \else + \def\pgf@nfold@tmp@joinmacro{\pgf@nfold@beveljoin} + \fi + \else + \if b\pgf@cached@linejoin\relax + \def\pgf@nfold@tmp@joinmacro{\pgf@nfold@beveljoin} + \else + \def\pgf@nfold@tmp@joinmacro{\pgf@nfold@roundjoin} + \fi + \fi + \edef\pgf@nfold@macrotoadd{% + \noexpand\pgf@nfold@token@join{\pgf@nfold@cur@first}{\pgf@nfold@prev@segment@end} + {\pgf@nfold@cur@movedfirst}{\pgf@nfold@prev@angle@ii}{\pgf@nfold@cur@angle@i}% + {\pgf@nfold@deltaphi@start}{\pgf@nfold@shortenstartjoin}{% + \expandafter\noexpand\pgf@nfold@tmp@joinmacro% + \expandafter\noexpand\ifpgf@nfold@closejoinsedgecase% + \pgf@nfold@token@finish@edgecase{\pgf@nfold@cur@movedlast}% + \else% + \pgf@nfold@token@finish@normal% + \fi% + }% + }% + \pgf@nfold@addmacro\pgf@parsed@cur@conn@seg% + \fi% +} + + +\def\pgf@nfold@token@finish@normal{% + \pgfpathlineto{\pgf@nfold@join@end}% +} + +\def\pgf@nfold@token@finish@edgecase#1{% + \pgf@nfold@join@end% + \ifdim\insidepercentage pt<.5pt\relax% + \pgf@process{\pgfpointadd{#1}{\pgfpointpolar{\pgf@nfold@secondang+90}{\pgf@nfold@shiftamount}}} + \fi% + \pgfpathlineto{}% +} + + + +\newif\ifpgf@nfold@continuesegment +\newif\ifpgf@nfold@closejoinsedgecase +\newif\ifpgf@nfold@angletoosharp +\newif\ifpgf@nfold@intersectionsnotloaded +\newif\ifpgf@nfold@lastconnsubpath + + +\def\pgf@nfold@process@segment{% + \if\pgf@nfold@cur@visible0 + \if\pgf@nfold@cur@type m + \if\pgf@nfold@start@arrowcode1 + \ifpgf@nfold@lastconnsubpath + \if\pgf@nfold@prev@type f + \if\pgf@nfold@next@visible1 + \edef\pgf@nfold@macrotoadd{% + \noexpand\pgf@nfold@extendtotip{s}{\pgf@nfold@cur@last}{\pgf@nfold@next@angle@i} + }% + \pgf@nfold@addmacro\pgf@parsed@cur@conn@seg% + \let\pgf@nfold@cur@type l + \let\pgf@nfold@cur@visible1 + \let\pgf@nfold@cur@angle@ii\pgf@nfold@next@angle@i + \let\pgf@nfold@cur@tang@ii\pgf@nfold@next@tang@i + \def\pgf@nfold@deltaphi@end{0} + \pgf@nfold@angletoosharpfalse + \fi + \fi% + \fi + \fi + \fi% + \else% + \let\pgf@nfold@cur@movedfirst\pgf@nfold@cur@first + \let\pgf@nfold@cur@movedlast\pgf@nfold@cur@last + \def\pgf@nfold@shortenstartjoin{0} + \def\pgf@nfold@shortenendjoin{0} + \pgf@nfold@closejoinsedgecasefalse + \if\pgf@nfold@prev@visible0 + \pgf@nfold@continuesegmentfalse + \else + \pgf@nfold@continuesegmenttrue + \let\pgf@nfold@deltaphi@start\pgf@nfold@deltaphi@end + \pgf@xb=\pgf@nfold@deltaphi@start pt\relax + \ifdim\pgf@xb<0pt\relax + \pgf@xb=-\pgf@xb + \fi + \ifpgf@nfold@angletoosharp\else + \ifdim\pgf@xb>0.5pt\relax + \pgf@yb=.5\pgf@xb + \pgfmathtan@{\pgf@sys@tonumber\pgf@yb} + \pgf@yb=\pgf@nfold@hwidth\relax + \pgf@yb=\pgfmathresult\pgf@yb + \edef\pgf@nfold@shortenstartjoin{\pgf@sys@tonumber\pgf@yb} + \pgfextract@process\pgf@nfold@cur@movedfirst{% + \pgfpointadd{\pgf@nfold@cur@first}% + {\pgfqpointscale{\pgf@nfold@shortenstartjoin}{\pgf@nfold@cur@tang@i}}}% + \if\pgf@nfold@cur@type c + \pgf@process{\pgfpointdiff{\pgf@nfold@cur@first}{\pgf@nfold@cur@supporta}} + \pgfmathveclen@{\pgf@sys@tonumber\pgf@x}{\pgf@sys@tonumber\pgf@y} + \ifdim\pgfmathresult pt>0.1pt\relax + \pgfmathveclen@{\pgfmathresult}{\pgf@sys@tonumber\pgf@yb} + \pgfextract@process\pgf@nfold@cur@supporta{\pgfpointadd% + {\pgf@nfold@cur@first}% + {\pgfqpointscale{\pgfmathresult}{\pgf@nfold@cur@tang@i}}}% + \else + \let\pgf@nfold@cur@supporta\pgf@nfold@cur@movedfirst + \fi + \fi + \fi + \fi + \fi + \if\pgf@nfold@next@visible1 + \pgfmathsubtract@{\pgf@nfold@next@angle@i}{\pgf@nfold@cur@angle@ii} + \pgf@nfold@clampangle + \edef\pgf@nfold@deltaphi@end{\pgfmathresult} + \pgf@xb=\pgf@nfold@deltaphi@end pt\relax + \ifdim\pgf@xb<0pt\relax + \pgf@xb=-\pgf@xb + \fi + \ifdim\pgf@xb>178pt\relax + \pgfutil@packagewarning{tikz-nfold}{Angle too sharp, expect visual errors} + \pgf@nfold@angletoosharptrue + \else + \pgf@nfold@angletoosharpfalse + \ifdim\pgf@xb>0.5pt\relax + \pgf@yb=.5\pgf@xb + \pgfmathtan@{\pgf@sys@tonumber\pgf@yb} + \pgf@yb=\pgf@nfold@hwidth\relax + \pgf@yb=\pgfmathresult\pgf@yb + \edef\pgf@nfold@shortenendjoin{\pgf@sys@tonumber\pgf@yb} + \pgf@yb=-\pgf@yb + \pgfextract@process\pgf@nfold@cur@movedlast{% + \pgfpointadd{\pgf@nfold@cur@last}% + {\pgfqpointscale{-\pgf@nfold@shortenendjoin}{\pgf@nfold@cur@tang@ii}}}% + \pgfextract@process\pgf@nfold@cur@movedlast{% + \pgfpointadd{\pgf@nfold@cur@last}% + {\pgfqpointpolar{\pgf@nfold@cur@angle@ii}{\pgf@yb}}}% + \if\pgf@nfold@cur@type c + \pgf@process{\pgfpointdiff{\pgf@nfold@cur@supportb}{\pgf@nfold@cur@last}} + \pgfmathveclen@{\pgf@sys@tonumber\pgf@x}{\pgf@sys@tonumber\pgf@y} + \ifdim\pgfmathresult pt>0.1pt\relax + \pgfmathveclen@{\pgfmathresult}{\pgf@sys@tonumber\pgf@yb} + \pgfextract@process\pgf@nfold@cur@supportb{\pgfpointadd% + {\pgf@nfold@cur@last}% + {\pgfqpointscale{-\pgfmathresult}{\pgf@nfold@cur@tang@ii}}}% + \else + \let\pgf@nfold@cur@supportb\pgf@nfold@cur@movedlast + \fi + \fi + \fi + \fi + \if\pgf@nfold@cur@type l + \pgf@process{\pgfpointdiff{\pgf@nfold@cur@first}{\pgf@nfold@cur@last}} + \pgfmathveclen@{\pgf@sys@tonumber\pgf@x}{\pgf@sys@tonumber\pgf@y} + \pgf@xa=\pgf@nfold@shortenstartjoin pt\relax + \advance\pgf@xa by\pgf@nfold@shortenendjoin pt\relax + \ifdim\pgf@xa>\pgfmathresult pt\relax + \pgf@nfold@closejoinsedgecasetrue + \fi + \fi + \fi% + \if\pgf@nfold@prev@visible0% + \ifpgf@nfold@closejoinsedgecase + \edef\pgf@nfold@macrotoadd{% + \noexpand\pgf@nfold@token@edgecase@movetostart{\pgf@nfold@cur@movedfirst}{\pgf@nfold@cur@angle@i}% + }% + \pgf@nfold@addmacro\pgf@parsed@cur@conn@seg% + \fi + \else + \ifpgf@nfold@angletoosharp\else + \if\pgf@nfold@cur@type z\else + \pgf@nfold@process@join + \fi + \fi + \fi + \let\pgf@nfold@prev@segment@end\pgf@nfold@cur@movedlast + \if\pgf@nfold@cur@type i + \let\pgf@nfold@connsubpath@tang@i\pgf@nfold@next@tang@i% + \let\pgf@nfold@connsubpath@angle@i\pgf@nfold@next@angle@i% + \fi + \if\pgf@nfold@cur@type l + \ifpgf@nfold@closejoinsedgecase\else + \edef\pgf@nfold@macrotoadd{% + \expandafter\noexpand\ifpgf@nfold@continuesegment% + \pgf@nfold@token@lineto@continue% + \else% + \pgf@nfold@token@lineto% + \fi{\pgf@nfold@cur@movedfirst}{\pgf@nfold@cur@movedlast}{\pgf@nfold@cur@tang@i}% + }% + \pgf@nfold@addmacro\pgf@parsed@cur@conn@seg% + \fi + \fi + \if\pgf@nfold@cur@type o + \def\pgf@nfold@macrotoadd{\pgf@nfold@token@closepath}% + \pgf@nfold@addmacro\pgf@parsed@cur@conn@seg% + \fi + \if\pgf@nfold@cur@type z + \def\pgf@nfold@macrotoadd{\pgf@nfold@token@closepath}% + \pgf@nfold@addmacro\pgf@parsed@cur@conn@seg% + \fi + \if\pgf@nfold@cur@type c + \ifpgf@nfold@continuesegment + \pgf@subdividecurve{\pgf@nfold@cur@movedfirst}{\pgf@nfold@cur@supporta}{\pgf@nfold@cur@supportb}{\pgf@nfold@cur@movedlast}{\pgf@offset@max@recursion}{0}{\pgf@nfold@addcurvesegment@callback@continue} + \else + \pgf@subdividecurve{\pgf@nfold@cur@movedfirst}{\pgf@nfold@cur@supporta}{\pgf@nfold@cur@supportb}{\pgf@nfold@cur@movedlast}{\pgf@offset@max@recursion}{0}{\pgf@nfold@addcurvesegment@callback}% + \fi + \fi + \if\pgf@nfold@cur@type i + \edef\pgf@nfold@macrotoadd{% + \noexpand\pgf@nfold@token@invisibleline{\pgf@nfold@cur@movedfirst}{\pgf@nfold@cur@movedlast}{\pgf@nfold@cur@tang@i}% + }% + \pgf@nfold@addmacro\pgf@parsed@cur@conn@seg% + \fi + \if\pgf@nfold@next@type t% + \ifnum\pgf@nfold@end@arrowcode=1 + \edef\pgf@nfold@macrotoadd{% + \noexpand\pgf@nfold@extendtotip{e}{\pgf@nfold@cur@last}{\pgf@nfold@cur@angle@ii}}% + \pgf@nfold@addmacro\pgf@parsed@cur@conn@seg% + \fi% + \fi% + \fi% +} + + +\def\pgf@nfold@addcurvesegment@callback#1#2#3#4#5{% + \if#50% + \edef\pgf@nfold@macrotoadd{% + \noexpand\pgf@nfold@token@curveto{#1}{#2}{#3}{#4}{\pgf@tmp@tang@i}{\pgf@tmp@tang@ii}% + }% + \pgf@nfold@addmacro\pgf@parsed@cur@conn@seg% + \else% + \pgf@nfold@addcurvesegment@callback@continue{#1}{#2}{#3}{#4}{#5}% + \fi% +} + +\def\pgf@nfold@addcurvesegment@callback@continue#1#2#3#4#5{% + \edef\pgf@nfold@macrotoadd{% + \noexpand\pgf@nfold@token@curveto@continue{#1}{#2}{#3}{#4}{\pgf@tmp@tang@i}{\pgf@tmp@tang@ii}% + }% + \pgf@nfold@addmacro\pgf@parsed@cur@conn@seg% +} + + + +\expandafter\def\csname pgf@nfold@intersec@cache@2@3\endcsname{\pgfqpoint{2pt}{0pt}} +\expandafter\def\csname pgf@nfold@intersec@cache@2@4\endcsname{\pgfqpoint{0.94063pt}{-0.33333pt}} +\expandafter\def\csname pgf@nfold@intersec@cache@3@4\endcsname{\pgfqpoint{0.94063pt}{0.33333pt}} +\expandafter\def\csname pgf@nfold@intersec@cache@2@5\endcsname{\pgfqpoint{0.64167pt}{-0.5pt}} +\expandafter\def\csname pgf@nfold@intersec@cache@3@5\endcsname{\pgfqpoint{2pt}{0pt}} +\expandafter\def\csname pgf@nfold@intersec@cache@4@5\endcsname{\pgfqpoint{0.64167pt}{0.5pt}} +\def\pgf@nfold@intersec@numcached{5} + +\newif\ifpgf@nfold@ontheedge +\def\pgf@nfold@extendtotip#1#2#3{ + \ifpgf@nfold@intersectionsnotloaded + \pgfutil@packageerror{tikz-nfold}{% + If `nfold' is larger than \pgf@nfold@intersec@numcached\space and you use + an `Implies' arrow tip you need to say \string\usetikzlibrary{intersections}}{} + \else + \pgf@nfold@ontheedgetrue + \ifnum\pgf@nfold@index>1\relax\ifnum\pgf@nfold@index<\pgf@nfold@order\relax% + \pgf@nfold@ontheedgefalse + \fi\fi + \ifpgf@nfold@ontheedge% + \if#1s + \pgfpathmoveto{\pgfpointadd{#2}{\pgfpointpolar{#3+90}{\pgf@nfold@shiftamount}}}% + \fi + \else + \ifcsname pgf@nfold@intersec@cache@\the\pgf@nfold@index @\the\pgf@nfold@order\endcsname + \pgfextract@process\pgf@nfold@arrowintersect + {\csname pgf@nfold@intersec@cache@\the\pgf@nfold@index @\the\pgf@nfold@order\endcsname}% + \else + \pgfintersectionofpaths{ + \pgfpathmoveto{\pgfqpoint{-1.4pt}{2.65pt}} + \pgfpathcurveto{\pgfqpoint{-0.75pt}{1.25pt}}{\pgfqpoint{1pt}{0.05pt}}{\pgfqpoint{2pt}{0pt}} + \pgfpathcurveto{\pgfqpoint{1pt}{-0.05pt}}{\pgfqpoint{-0.75pt}{-1.25pt}}{\pgfqpoint{-1.4pt}{-2.65pt}} + }{ + \pgfpathmoveto{\pgfqpoint{-3pt}{\pgf@nfold@shift@fraction pt}} + \pgfpathlineto{\pgfqpoint{3pt}{\pgf@nfold@shift@fraction pt}} + } + \ifnum\pgfintersectionsolutions>0 + \pgfextract@process\pgf@nfold@arrowintersect{\pgfpointintersectionsolution{1}}% + \immediate\write17{tikz-nfold: computed intersection cache@\the\pgf@nfold@index @\the\pgf@nfold@order: \string\pgfqpoint{\the\pgf@x}{\the\pgf@y}^^J} + \expandafter\xdef\csname pgf@nfold@intersec@cache@\the\pgf@nfold@index @\the\pgf@nfold@order\endcsname{\noexpand\pgfqpoint{\the\pgf@x}{\the\pgf@y}} + \else + \pgfutil@packagewarning{tikz-nfold}{did not find intersection} + \pgfextract@process\pgf@nfold@arrowintersect{\pgfqpoint{0pt}{\pgf@nfold@shift@fraction pt}}% + \fi + \fi% + \begingroup + \pgftransformreset + \pgftransformshift{#2} + \pgftransformrotate{#3} + \if#1s + \pgftransformxscale{-1} + \fi + \pgfutil@tempdima=\pgf@nfold@hwidth + \pgfutil@tempdima=\pgf@nfold@shift@fraction\pgfutil@tempdima + \pgfextract@process\pgf@nfold@startofextension + {\pgfpointtransformed{\pgfqpoint{0pt}{\pgfutil@tempdima}}} + \pgftransformshift{\pgfqpoint{.42\pgflinewidth}{0pt}} + \pgftransformscale{\pgf@nfold@hwidth} + \pgfextract@process\pgf@nfold@arrowintersect{\pgfpointtransformed{\pgf@nfold@arrowintersect}} + \global\let\pgf@nfold@startofextension\pgf@nfold@startofextension + \global\let\pgf@nfold@arrowintersect\pgf@nfold@arrowintersect + \endgroup + \if#1s + \pgfpathmoveto{\pgf@nfold@arrowintersect} + \pgfpathlineto{\pgf@nfold@startofextension} + \else\if#1e + \pgfpathlineto{\pgf@nfold@arrowintersect} + \else + \pgfutil@packageerror{tikz-nfold}{Invalid argument to \string\pgf@nfold@extendtotip: \meaning#1}{} + \fi\fi + \pgftransformreset + \fi% + \fi% +} + + +\def\pgf@nfold@start@arrowcode{0} +\def\pgf@nfold@end@arrowcode{0} + +\def\pgf@nfold@parsearrows{ + \ifpgfutil@tempswa% + \expandafter\pgf@nfold@parsearrowmacro\pgf@start@tip@sequence\relax + \let\pgf@nfold@start@arrowcode\pgf@nfold@detectedarrow + \expandafter\pgf@nfold@parsearrowmacro\pgf@end@tip@sequence\relax + \let\pgf@nfold@end@arrowcode\pgf@nfold@detectedarrow + \else + \def\pgf@nfold@start@arrowcode{0} + \def\pgf@nfold@end@arrowcode{0} + \fi +} + +\def\pgf@nfold@parsearrowmacro#1{% + \def\pgf@nfold@detectedarrow{0} + \ifx#1\relax + \let\pgf@next\relax + \else + \ifx#1\pgf@arrow@handle + \let\pgf@next\pgf@nfold@parse@arrow@handle + \else + \ifx#1\pgf@arrow@handle@shorthand@empty + \let\pgf@next\pgf@nfold@parse@shorthandempty + \else + \let\pgf@next\pgfutil@gobble@until@relax + \fi + \fi + \fi + \pgf@next +} + +\def\pgf@nfold@param@Implies{Implies} + +\def\pgf@nfold@parse@arrow@handle#1{% + \def\pgf@tmp{#1} + \ifx\pgf@tmp\pgf@nfold@param@Implies + \def\pgf@nfold@detectedarrow{1} + \fi + \pgfutil@gobble@until@relax +} + +\def\pgf@nfold@parse@shorthandempty#1{ + \expandafter\def\expandafter\pgf@tmp\expandafter{#1} + \expandafter\pgf@nfold@parsearrowmacro\pgf@tmp\relax + \pgfutil@gobble@until@relax +} + + + +\newcount\pgf@nfold@order +\pgf@nfold@order=1 + +\def\pgf@nfold@preparenfoldpath{% + \ifnum\pgf@nfold@order>1\relax + \ifdim\pgfinnerlinewidth>0pt\relax + \pgfsyssoftpath@getcurrentpath\pgf@nfold@cachedpath% + \pgfsyssoftpath@setcurrentpath\pgfutil@empty% + \else + \pgfutil@packageerror{tikz-nfold}{Must set \string\pgfinnerlinewidth\space to use nfold, e.g. by setting /tikz/double distance}{} + \fi + \fi +} + +\let\pgf@nfold@old@path@check@proper\pgf@path@check@proper +\def\pgf@path@check@proper{% + \pgf@nfold@old@path@check@proper% + \ifpgfutil@tempswa\else% + \pgf@nfold@preparenfoldpath% + \fi% +} + +\let\pgf@nfold@old@prepare@start@of@path\pgf@prepare@start@of@path +\def\pgf@prepare@start@of@path{% + \pgf@nfold@old@prepare@start@of@path% + \pgf@nfold@preparenfoldpath% +} + +\let\pgf@nfold@old@stroke@inner@line\pgf@stroke@inner@line +\def\pgf@stroke@inner@line{% + \ifnum\pgf@nfold@order>1\relax% + \pgf@nfold@render@cached@softpath% + \else% + \pgf@nfold@old@stroke@inner@line% + \fi% +} + + + + +\def\pgf@nfold@parsemoveto#1#2{% + \ifx\pgf@cur@conn@subpath\pgfutil@empty% + \def\pgf@nfold@parser@last@moveto{{#1}{#2}}% + \def\pgf@cur@conn@subpath{\relax}% + \else% + \def\pgf@nfold@macrotoadd{\pgf@nfold@processmoveto{#1}{#2}}% + \pgf@nfold@addmacro\pgf@cur@conn@subpath% + \pgf@nfold@lastconnsubpathfalse% + \pgf@nfold@process@conn@subpath% + \let\pgf@nfold@last@closepath@from\pgfutil@empty% + \let\pgf@cur@conn@subpath\pgfutil@empty% + \pgf@nfold@parser@setupfirst% + \def\pgf@nfold@parser@last@moveto{{#1}{#2}}% + \fi% + \pgf@nfold@parsesoftpath@finish{#1}{#2}% +} + +\def\pgf@nfold@parselineto#1#2{% + \def\pgf@nfold@macrotoadd{\pgf@nfold@processlineto{#1}{#2}}% + \pgf@nfold@addmacro\pgf@cur@conn@subpath% + \pgf@nfold@parsesoftpath@finish{#1}{#2}% +} + +\def\pgf@nfold@parseclosepath#1#2{% + \let\pgf@nfold@last@closepath@from\pgf@nfold@parser@previous@pt% + \def\pgf@nfold@macrotoadd{\pgf@nfold@processclosepath{#1}{#2}}% + \pgf@nfold@addmacro\pgf@cur@conn@subpath% + \pgf@nfold@parsesoftpath@finish{#1}{#2}% +} + +\def\pgf@nfold@parsecurveto#1#2{% + \edef\pgf@nfold@macrotoadd{\noexpand\pgf@nfold@processcurveto\pgf@nfold@parser@supporta\pgf@nfold@parser@supportb{#1}{#2}}% + \pgf@nfold@addmacro\pgf@cur@conn@subpath% + \pgf@nfold@parsesoftpath@finish{#1}{#2}% +} + +\def\pgf@nfold@parserect#1#2#3#4{% + \pgf@nfold@parsemoveto{#1}{#2}% + \pgf@xc=#1\relax + \pgf@yc=#2\relax + \pgf@xd=#3\relax + \pgf@yd=#4\relax + \advance\pgf@yc\pgf@yd% + \edef\pgf@temp{{\the\pgf@xc}{\the\pgf@yc}}% + \expandafter\pgf@nfold@parselineto\pgf@temp% + \advance\pgf@xc\pgf@xd% + \edef\pgf@temp{{\the\pgf@xc}{\the\pgf@yc}}% + \expandafter\pgf@nfold@parselineto\pgf@temp% + \advance\pgf@yc-\pgf@yd% + \edef\pgf@temp{{\the\pgf@xc}{\the\pgf@yc}}% + \expandafter\pgf@nfold@parselineto\pgf@temp% + \advance\pgf@xc-\pgf@xd% + \edef\pgf@temp{{\the\pgf@xc}{\the\pgf@yc}}% + \expandafter\pgf@nfold@parseclosepath\pgf@temp% + \pgf@nfold@parsemoveto{#1}{#2}% +} + + +\def\pgf@nfold@parsesoftpath#1#2{% + \let\pgf@cur@conn@subpath\pgfutil@empty% + \let\pgf@all@parsed@subpaths\pgfutil@empty% + \edef\pgf@nfold@parser@last@moveto{{\the\pgf@path@lastx}{\the\pgf@path@lasty}}% + \let\pgf@nfold@last@closepath@from\pgfutil@empty% + \pgf@nfold@parser@setupfirst% + \expandafter\pgf@nfold@@parsesoftpath#1\pgf@stop{}{}% + \let#2\pgf@all@parsed@subpaths% +}% + +\def\pgf@nfold@@parsesoftpath#1#2#3{% + \let\pgf@next\pgf@nfold@@parsesoftpath% + \ifx#1\pgf@stop% + \def\pgf@nfold@macrotoadd{\pgf@nfold@processlast}% + \pgf@nfold@addmacro\pgf@cur@conn@subpath% + \pgf@nfold@lastconnsubpathtrue% + \pgf@nfold@process@conn@subpath% + \let\pgf@next\relax% + \else% + \ifx#1\pgfsyssoftpath@movetotoken% + \pgf@nfold@parsemoveto{#2}{#3}% + \else% + \ifx#1\pgfsyssoftpath@linetotoken% + \pgf@nfold@parselineto{#2}{#3}% + \else% + \ifx#1\pgfsyssoftpath@curvetosupportatoken% + \def\pgf@nfold@parser@supporta{{#2}{#3}}% + \else% + \ifx#1\pgfsyssoftpath@curvetosupportbtoken% + \def\pgf@nfold@parser@supportb{{#2}{#3}}% + \else% + \ifx#1\pgfsyssoftpath@curvetotoken% + \pgf@nfold@parsecurveto{#2}{#3}% + \else% + \ifx#1\pgfsyssoftpath@closepathtoken% + \pgf@nfold@parseclosepath{#2}{#3}% + \else% + \ifx#1\pgfsyssoftpath@rectcornertoken% + \def\pgf@nfold@parser@rectcorner{{#2}{#3}}% + \else% + \ifx#1\pgfsyssoftpath@rectsizetoken% + \expandafter\pgf@nfold@parserect\pgf@nfold@parser@rectcorner{#2}{#3}% + \else% + \pgfutil@packageerror{tikz-nfold}{Unrecognised soft path token `#1'}{}% + \fi% + \fi% + \fi% + \fi% + \fi% + \fi% + \fi% + \fi% + \fi% + \pgf@next% +}% + +\def\pgf@nfold@parsesoftpath@finish#1#2{% + \def\pgf@nfold@parser@previous@pt{{#1}{#2}}% + \let\pgf@nfold@sectolast@segment\pgf@nfold@last@segment% + \let\pgf@nfold@last@segment\pgf@nfold@macrotoadd% +} + +\def\pgf@nfold@process@conn@subpath{% + \let\pgf@parsed@cur@conn@seg\pgfutil@empty% + \ifx\pgf@nfold@last@closepath@from\pgfutil@empty% + \expandafter\pgf@nfold@processmoveto\pgf@nfold@parser@last@moveto% + \else% + \expandafter\pgf@nfold@processmoveto\pgf@nfold@last@closepath@from% + \expandafter\pgf@nfold@processinvisibleline\pgf@nfold@parser@last@moveto% + \fi% + \pgf@cur@conn@subpath% + \let\pgf@nfold@macrotoadd\pgf@parsed@cur@conn@seg% + \pgf@nfold@addmacro\pgf@all@parsed@subpaths% +} + + +\def\pgf@nfold@processmoveto#1#2{% + \pgf@nfold@process@moveup% + \let\pgf@nfold@next@type=m% + \let\pgf@nfold@next@visible=0% + \edef\pgf@nfold@next@last{\pgf@x#1\pgf@y#2}% + \pgf@nfold@process@segment% +}% + +\def\pgf@nfold@process@line@common#1#2#3{% + \pgf@nfold@process@moveup% + \pgfextract@process\pgf@tmp@tang@i{\pgfpointnormalised{}\global\let\pgf@nfold@tmp\pgf@tmp} + \let\pgf@nfold@next@type=#3% + \let\pgf@nfold@next@visible=1% + \let\pgf@nfold@next@tang@i\pgf@tmp@tang@i + \let\pgf@nfold@next@tang@ii\pgf@tmp@tang@i + \let\pgf@nfold@next@angle@i\pgf@nfold@tmp + \let\pgf@nfold@next@angle@ii\pgf@nfold@tmp + \let\pgf@nfold@next@first\pgf@nfold@cur@last + \def\pgf@nfold@next@last{\pgf@x#1\pgf@y#2}% + \pgf@nfold@process@segment% +} + +\def\pgf@nfold@processlineto#1#2{% + \pgf@process{\pgfpointdiff{\pgf@nfold@next@last}{\pgf@x#1\pgf@y#2}}% + \pgfpointtaxicabnorm\pgf@xa% + \ifdim\pgf@xa>.1pt\relax% + \pgf@nfold@process@line@common{#1}{#2}{l}% + \fi% +}% + +\def\pgf@nfold@processcurveto#1#2#3#4#5#6{% + \pgf@nfold@process@moveup% + \pgf@offset@compute@tangents{\pgf@nfold@cur@last}{\pgf@x#1\pgf@y#2}{\pgf@x#3\pgf@y#4}{\pgf@x#5\pgf@y#6}% + \let\pgf@nfold@next@type=c% + \let\pgf@nfold@next@visible=1% + \let\pgf@nfold@next@tang@i=\pgf@tmp@tang@i + \let\pgf@nfold@next@tang@ii=\pgf@tmp@tang@ii + \let\pgf@nfold@next@angle@i\pgf@tmp@angle@i + \let\pgf@nfold@next@angle@ii\pgf@tmp@angle@ii + \let\pgf@nfold@next@first\pgf@nfold@cur@last + \def\pgf@nfold@next@supporta{\pgf@x#1\pgf@y#2} + \def\pgf@nfold@next@supportb{\pgf@x#3\pgf@y#4} + \def\pgf@nfold@next@last{\pgf@x#5\pgf@y#6} + \pgf@nfold@process@segment% +}% + +\def\pgf@nfold@processclosepath#1#2{% + \pgf@process{\pgfpointdiff{\pgf@nfold@next@last}{\pgf@x#1\pgf@y#2}}% + \pgfpointtaxicabnorm\pgf@xa% + \ifdim\pgf@xa<0.1pt\relax% + \pgf@nfold@process@closepath@zerolength{#1}{#2}% + \else% + \pgf@nfold@process@line@common{#1}{#2}{o}% + \fi% +}% + +\def\pgf@nfold@process@closepath@zerolength#1#2{% + \pgf@nfold@process@moveup% + \let\pgf@nfold@next@type=z% + \let\pgf@nfold@next@visible=1% + \let\pgf@nfold@next@tang@i\pgf@nfold@connsubpath@tang@i + \let\pgf@nfold@next@tang@ii\pgf@nfold@connsubpath@tang@i + \let\pgf@nfold@next@angle@i\pgf@nfold@connsubpath@angle@i + \let\pgf@nfold@next@angle@ii\pgf@nfold@connsubpath@angle@i + \let\pgf@nfold@next@first\pgf@nfold@cur@last + \def\pgf@nfold@next@last{\pgf@x#1\pgf@y#2}% + \pgf@nfold@process@segment% +} + +\def\pgf@nfold@processinvisibleline#1#2{% + \pgf@process{\pgfpointdiff{\pgf@nfold@next@last}{\pgf@x#1\pgf@y#2}}% + \pgfpointtaxicabnorm\pgf@xa% + \ifdim\pgf@xa>.1pt\relax% + \pgf@nfold@process@line@common{#1}{#2}{i}% + \else% + \begingroup% + \let\pgf@nfold@process@segment\relax% + \pgf@nfold@sectolast@segment% + \global\let\pgf@nfold@tmp\pgf@nfold@next@tang@ii% + \endgroup% + \pgfextract@process\pgf@nfold@next@first{\pgfpointdiff{\pgf@nfold@tmp}{\pgfqpoint{#1}{#2}}}% + \pgf@nfold@tmp% + \pgf@nfold@process@line@common{#1}{#2}{i}% + \fi% +}% + +\def\pgf@nfold@processlast{% + \pgf@nfold@process@moveup% + \let\pgf@nfold@next@type=t% + \let\pgf@nfold@next@visible=0% + \pgf@nfold@process@segment% +} + +\def\pgf@nfold@addmacro#1{% + \expandafter\expandafter\expandafter\gdef% + \expandafter\expandafter\expandafter#1% + \expandafter\expandafter\expandafter{% + \expandafter#1\pgf@nfold@macrotoadd}% +} + + + +\def\pgf@nfold@token@lineto#1#2#3{% + \pgfoffsetline@{#1}{#2}{\pgf@nfold@shiftamount}{#3}% +} + +\def\pgf@nfold@token@lineto@continue#1#2#3{% + \pgfoffsetlinenomove@{#1}{#2}{\pgf@nfold@shiftamount}{#3}% +} + +\def\pgf@nfold@token@invisibleline#1#2#3{% + \pgfqpointscale{\pgf@nfold@shiftamount}{#3}% + \pgf@xc=-\pgf@y% + \pgf@y=\pgf@x% + \pgf@x=\pgf@xc% + \pgfpathmoveto{\pgfpointadd{}{#2}}% +} + +\def\pgf@nfold@token@curveto#1#2#3#4#5#6{% + \def\pgf@tmp@tang@i{#5}% + \def\pgf@tmp@tang@ii{#6}% + \pgf@offset@bezier@segment@{#1}{#2}{#3}{#4}{\pgf@nfold@shiftamount}% + \pgfpathmoveto{\pgf@bezier@offset@i}% + \pgfpathcurveto{\pgf@bezier@offset@ii}{\pgf@bezier@offset@iii}{\pgf@bezier@offset@iv}% +} + +\def\pgf@nfold@token@curveto@continue#1#2#3#4#5#6{% + \def\pgf@tmp@tang@i{#5}% + \def\pgf@tmp@tang@ii{#6}% + \pgf@offset@bezier@segment@{#1}{#2}{#3}{#4}{\pgf@nfold@shiftamount}% + \pgfpathcurveto{\pgf@bezier@offset@ii}{\pgf@bezier@offset@iii}{\pgf@bezier@offset@iv}% +} + +\def\pgf@nfold@token@closepath{% + \pgfpathclose% +} + +\def\pgf@nfold@token@edgecase@movetostart#1#2{% + \pgfpathmoveto{\pgfpointadd% + {#1}{\pgfpointpolar{#2+90}{\pgf@nfold@shiftamount}}}% +} + + +\def\pgf@nfold@parser@setupfirst{% + \let\pgf@nfold@next@type=f% + \let\pgf@nfold@next@visible=0% + \edef\pgf@nfold@next@last{\pgf@x\the\pgf@path@lastx\pgf@y\the\pgf@path@lasty}% +} + +\def\pgf@nfold@clampangle{ + \ifdim\pgfmathresult pt<-180pt\relax + \pgfutil@tempdima=\pgfmathresult pt + \advance\pgfutil@tempdima by 360pt + \edef\pgfmathresult{\pgf@sys@tonumber\pgfutil@tempdima} + \else\ifdim\pgfmathresult pt>180pt\relax + \pgfutil@tempdima=\pgfmathresult pt + \advance\pgfutil@tempdima by -360pt + \edef\pgfmathresult{\pgf@sys@tonumber\pgfutil@tempdima} + \fi\fi +} + + +\def\pgf@nfold@process@moveup{% + \let\pgf@nfold@prev@type\pgf@nfold@cur@type% + \let\pgf@nfold@prev@visible\pgf@nfold@cur@visible% + \let\pgf@nfold@prev@tang@i\pgf@nfold@cur@tang@i% + \let\pgf@nfold@prev@tang@ii\pgf@nfold@cur@tang@ii% + \let\pgf@nfold@prev@angle@i\pgf@nfold@cur@angle@i% + \let\pgf@nfold@prev@angle@ii\pgf@nfold@cur@angle@ii% + \let\pgf@nfold@prev@first\pgf@nfold@cur@first% + \let\pgf@nfold@prev@supporta\pgf@nfold@cur@supporta% + \let\pgf@nfold@prev@supportb\pgf@nfold@cur@supportb% + \let\pgf@nfold@prev@last\pgf@nfold@cur@last% + \let\pgf@nfold@cur@type\pgf@nfold@next@type% + \let\pgf@nfold@cur@visible\pgf@nfold@next@visible% + \let\pgf@nfold@cur@tang@i\pgf@nfold@next@tang@i% + \let\pgf@nfold@cur@tang@ii\pgf@nfold@next@tang@ii% + \let\pgf@nfold@cur@angle@i\pgf@nfold@next@angle@i% + \let\pgf@nfold@cur@angle@ii\pgf@nfold@next@angle@ii + \let\pgf@nfold@cur@first\pgf@nfold@next@first% + \let\pgf@nfold@cur@supporta\pgf@nfold@next@supporta% + \let\pgf@nfold@cur@supportb\pgf@nfold@next@supportb% + \let\pgf@nfold@cur@last\pgf@nfold@next@last% +} + + +\def\pgfoffsetpath#1#2{% + \begingroup + \pgfmathsetlengthmacro\pgf@nfold@parsed@hwidth{#2} + \pgf@x=\pgf@nfold@parsed@hwidth\relax + \ifdim\pgf@x<0pt\relax + \pgf@x=-\pgf@x + \def\pgf@nfold@shift@fraction{-1} + \else + \def\pgf@nfold@shift@fraction{1} + \fi + \edef\pgf@nfold@parsed@hwidth{\the\pgf@x} + \pgfoffsetpathqfraction{#1}{\pgf@nfold@parsed@hwidth}{\pgf@nfold@shift@fraction} + \endgroup +} + +\def\pgfoffsetpathfraction#1#2#3{% + \begingroup + \pgfmathsetlengthmacro\pgf@nfold@parsed@hwidth{#2} + \pgfmathsetmacro\pgf@nfold@shift@fraction{#3} + \pgfoffsetpathqfraction{#1}{\pgf@nfold@parsed@hwidth}{\pgf@nfold@shift@fraction} + \endgroup +} + +\def\pgfoffsetpathindex#1#2#3#4{% + \begingroup + \pgfmathsetmacro\pgf@nfold@shift@fraction{-1+2*(#3-1)/(#4-1)} + \pgfoffsetpathqfraction{#1}{#2}{\pgf@nfold@shift@fraction} + \endgroup +} + +\def\pgfoffsetpathqfraction#1#2#3{% + \begingroup + \pgf@x=#2\relax + \edef\pgf@nfold@hwidth{\the\pgf@x} + \edef\pgf@nfold@shift@fraction{#3} + \pgf@x=\pgf@nfold@shift@fraction\pgf@x\relax + \edef\pgf@nfold@shiftamount{\pgf@sys@tonumber\pgf@x} + \pgfprocessround{#1}{\pgf@nfold@cachedpath}% + \pgf@nfold@parsesoftpath{\pgf@nfold@cachedpath}{\parsedpath}% + \pgftransformreset% + \parsedpath% + \endgroup +} + +\endinput diff --git a/Master/texmf-dist/tex/latex/tikz-nfold/tikzlibrarynfold.code.tex b/Master/texmf-dist/tex/latex/tikz-nfold/tikzlibrarynfold.code.tex index 342191b0ad7..799fa6b4d97 100644 --- a/Master/texmf-dist/tex/latex/tikz-nfold/tikzlibrarynfold.code.tex +++ b/Master/texmf-dist/tex/latex/tikz-nfold/tikzlibrarynfold.code.tex @@ -1,4 +1,4 @@ -%% tikz-nfold.sty +%% tikzlibrarynfold.code.tex %% Copyright 2023 Jonathan Schulz % % This work may be distributed and/or modified under the @@ -13,1312 +13,30 @@ % % The Current Maintainer of this work is Jonathan Schulz. % -% This work consists of the files pgflibrarybezieroffset.code.tex, -% tikzlibrarynfold.code.tex, tikz-nfold-doc.tex, and tikz-nfold-doc.pdf. - -\usetikzlibrary{arrows.meta} -\usepgflibrary{bezieroffset} - - -% -% General idea -% ============ -% -% In order to offset a path, we must first analyse and slightly modify it. For example, -% the start and end points of segments need to be relocated slightly in order to make room -% for the joins, and most curves must be subdivided for the offsetting algorithm. To avoid -% redundant computations in n-fold paths, we pre-compute as much data as possible and store -% all this information in a "parsed path" macro. The structure of the parsed path resembles -% the structure of a pgf softpath, but it consists of different tokens. -% - - - -% -% Intercepting join settings -% -------------------------- -% -% The current settings of the line joins are not stored in any TeX registers; instead, direct system -% calls are made to apply the settings. Therefore, we need to modify the pgf macros in order -% to cache the current settings. -% - -% According to the pgf documentation, miter limit=10 is the default value, -% but I couldn't find and verify this setting in the pgf code -\gdef\pgf@nfold@cached@miterlimit{10} -\let\pgf@nfold@old@miterlimit\pgfsetmiterlimit -\def\pgfsetmiterlimit#1{% - \pgf@nfold@old@miterlimit{#1}% - \edef\pgf@nfold@cached@miterlimit{#1}% -} - -% default line join is "miter" -\global\let\pgf@cached@linejoin=m% % b = bevel, m=miter, r=round -\let\pgf@nfold@old@setbeveljoin\pgfsetbeveljoin -\let\pgf@nfold@old@setmiterjoin\pgfsetmiterjoin -\let\pgf@nfold@old@setroundjoin\pgfsetroundjoin -\def\pgfsetbeveljoin{% - \pgf@nfold@old@setbeveljoin% - % do NOT change this globally! Needs to be changed back at the end of groups for scoping reasons - \let\pgf@cached@linejoin=b% -} -\def\pgfsetmiterjoin{% - \pgf@nfold@old@setmiterjoin% - \let\pgf@cached@linejoin=m% -} -\def\pgfsetroundjoin{% - \pgf@nfold@old@setroundjoin% - \let\pgf@cached@linejoin=r% -} - - -% -% Joining offset lines -% -------------------- -% -% One of the more difficult aspects is joining the segments of an offset path. Without this step, -% the path would be interrupted or self-intersect whenever there is a non-zero angle between -% two segments. This code reproduces the existing line joins "bevel", "miter" and "round". -% - -\def\pgf@nfold@miterjoin{ - % The tip of the miter join is computed starting from the original (unshifted) centre of the join; - % we then move orthorgonal to the average of the old and new angle - \pgfpathlineto{ - \pgfpointadd{\pgf@nfold@join@centre}{% - \pgfpointpolar{\pgf@nfold@firstang+.5*\pgf@nfold@deltaphi+90}% do not change - {\pgf@nfold@shiftamount/cos(.5*\pgf@nfold@deltaphi)}% - }% - }% -} - -\def\pgf@nfold@beveljoin{ - % The bevel join for one component line consists of three parts: - % 1) an extension of the ingoing line, - % 2) a middle line, angled at the average of the incoming and outgoing line, - % 3) an extension of the outgoing line. - % Different components of the ingoing and outgoing lines have a constant distance from each other. - % For a good-looking output, the mittle parts of the component lines thus should also have a constant distance, - % which is a non-trivial condition. To generate such an output the outer lines get a bevel-like join - % and the inner lines get a miter-like join; the threshold depends on deltaphi. - % We first compute by how much the outermost line must be continued from the beginning of the join. - % The protrusion amount must be lowered by a little bit for a rather complicated reason: The offset would be - % dead on if the outermost offset line were centered on the _edge_ of the wide line, but we want to draw - % the outside line _fully inside_ the wide line. The factor of tan(deltaphi/4) can be derived, but is not obvious. - \pgfmathsetlengthmacro{\bevelouterprotrusion}% - {\pgf@nfold@shortenstartjoin pt - .5*\pgflinewidth*abs(tan(.25*\pgf@nfold@deltaphi))} - % The following applies to middle lines only: We compute by how much they need to be shortened so the distance - % between the lines in the join is correct. - \pgfmathsetmacro{\bevelshorten}{2*\insidepercentage*abs(tan(.25*\pgf@nfold@deltaphi))} - % This threshold decides if the inside line has a bevel or a miter join - \pgfmathparse{\bevelshorten < abs(sin(.5*\pgf@nfold@deltaphi))} - \ifnum\pgfmathresult=1\relax - \pgfmathsetlengthmacro{\bevelextension}{\bevelouterprotrusion-\bevelshorten*\pgf@nfold@hwidth} - \pgfpointadd{\pgf@nfold@join@start}{\pgfpointpolar{\pgf@nfold@firstang}{\bevelextension}} - \pgfpathlineto{} - \pgfpointadd{\pgf@nfold@join@end}{\pgfpointpolar{\pgf@nfold@secondang}{-\bevelextension}} - \pgfpathlineto{} - \else - \pgf@nfold@miterjoin - \fi -} - -\def\pgf@nfold@roundjoin{ - % The outer half of the lines get arcs, the others get miters - \ifdim\insidepercentage pt<.5pt\relax - \pgfpointadd{\pgf@nfold@join@start}{\pgfpointpolar{\pgf@nfold@firstang}{\pgf@nfold@shortenstartjoin}} - \pgfpathlineto{} - % TODO needs unit tests for all cases left, right, across the 360 gap etc. - \pgfmathsetmacro\pgf@tmp@firstang{\pgf@nfold@firstang+90*\turnindicator} - \pgfpatharc% - {\pgf@tmp@firstang}% - {\pgf@tmp@firstang+\pgf@nfold@deltaphi}% - {abs(\pgf@nfold@shift@fraction)*\pgf@nfold@hwidth}% - \else - \pgf@nfold@miterjoin - \fi -} - -% The handler that will be added to the parsed path -% #1: The centre of the join -% #2: The end point of the first segment -% #3: The starting point of the second segment -% #4: The angle of the first segment -% #5: The angle of the second segment -% #6: deltaphi in the range [-180, 180] -% #7: the distance between #1 and #2 -% #8: the join + finish macro -\def\pgf@nfold@token@join#1#2#3#4#5#6#7#8{% - \def\pgf@nfold@join@centre{#1}% - \def\pgf@nfold@join@prevend{#2}% - \def\pgf@nfold@join@nextstart{#3}% - \def\pgf@nfold@firstang{#4}% - \def\pgf@nfold@secondang{#5}% - % Offset the start and end of this join - \pgfextract@process\pgf@nfold@join@start{% - \pgfpointadd{#2}{\pgfpointpolar{\pgf@nfold@firstang+90}{\pgf@nfold@shiftamount}}}% - \pgfextract@process\pgf@nfold@join@end{% - \pgfpointadd{#3}{\pgfpointpolar{\pgf@nfold@secondang+90}{\pgf@nfold@shiftamount}}}% - \pgf@process{\pgfpointdiff{\pgf@nfold@join@start}{\pgf@nfold@join@end}} - % Check if the start of this segment is very close to the end of the previous segment. - % In that case we don't need a join at all - \pgfpointtaxicabnorm\pgfutil@tempdima - \ifdim\pgfutil@tempdima>0.1pt\relax - \def\pgf@nfold@deltaphi{#6}% - \def\pgf@nfold@shortenstartjoin{#7}% - % First step: Check if left or right turn (-1=left, 1=right) - \ifdim\pgf@nfold@deltaphi pt<0pt - \def\turnindicator{1} - \else - \def\turnindicator{-1} - \fi - % \insidepercentage: between 0.0 and 1.0; - % 0=no distance to cover in the join, 1=maximum distance to cover - \pgfutil@tempdima=\pgf@nfold@shift@fraction pt\relax - \pgfutil@tempdima=\turnindicator\pgfutil@tempdima - \advance\pgfutil@tempdima by-1pt\relax - \pgfutil@tempdima=-.5\pgfutil@tempdima - % \insidepercentage = .5 * (1 - \turnindicator*\pgf@nfold@shift@fraction) - \edef\insidepercentage{\pgf@sys@tonumber\pgfutil@tempdima}% - #8% - \fi -} - - -% -% Parser: Join handler -% -\def\pgf@nfold@parser@handlejoin{% - % \pgf@xa := abs(deltaphi@start) - \pgf@xa=\pgf@nfold@deltaphi@start pt\relax - \ifdim\pgf@xa<0pt\relax - \pgf@xa=-\pgf@xa - \fi - % Skip the entire join if abs(deltaphi) is too small - \ifdim\pgf@xa>1pt\relax - \edef\pgf@nfold@jointype{\pgf@cached@linejoin} - \if\pgf@cached@linejoin m% \ifx is not needed because both are only one character - % miter join - % First we implement the miter limit: If the angle is too sharp, the miter join is replaced - % by a bevel join. This is controlled by /tikz/miter limit=..., initially 10. - \pgf@xa=.5\pgf@xa - \pgfmathcos@{\pgf@sys@tonumber\pgf@xa} - \pgf@xa=\pgfmathresult pt\relax - \pgf@xa=\pgf@nfold@cached@miterlimit\pgf@xa - % Switch to bevel if miterlimit*cos(.5*abs(deltaphi)) <= 1 - \ifdim\pgf@xa>1pt\relax - \def\pgf@nfold@tmp@joinmacro{\pgf@nfold@miterjoin} - \else - \def\pgf@nfold@tmp@joinmacro{\pgf@nfold@beveljoin} - \fi - \else - \if b\pgf@cached@linejoin\relax - \def\pgf@nfold@tmp@joinmacro{\pgf@nfold@beveljoin} - \else - \def\pgf@nfold@tmp@joinmacro{\pgf@nfold@roundjoin} - \fi - \fi - % The last parameter is a macro to be called when this segment of the join is non-trivial. - % It consists of - % - the macro to actually draw the join, - % - either finish@normal or finish@edgecase. - \edef\pgf@nfold@macrotoadd{% - \noexpand\pgf@nfold@token@join{\pgf@nfold@cur@first}{\pgf@nfold@prev@segment@end} - {\pgf@nfold@cur@movedfirst}{\pgf@nfold@prev@angle@ii}{\pgf@nfold@cur@angle@i}% - {\pgf@nfold@deltaphi@start}{\pgf@nfold@shortenstartjoin}{% - \expandafter\noexpand\pgf@nfold@tmp@joinmacro% - \expandafter\noexpand\ifpgf@nfold@closejoinsedgecase% - \pgf@nfold@token@finish@edgecase{\pgf@nfold@cur@movedlast}% - \else% - \pgf@nfold@token@finish@normal% - \fi% - }% - }% - \pgf@nfold@addmacro\pgf@parsed@cur@conn@seg% - \fi% end if abs(deltaphi) > 1 -} - - -% All non-trivial joins connect to the end of the join, which is the starting point of the next segment. -% Note that this entire macro is skipped by if the start and end of the join coincide, so we never create a zero length segment here. -% -% There is one edge case here: If two subsequent joins are so close that \pgf@nfold@cur@movedlast -% and \pgf@nfold@cur@movedfirst exchange places *and* we are on the outside of the first join -% (implying that we are on the inside of the second join), the first join must not connect all the way to -% to \pgf@nfold@cur@movedfirst, because that would overshoot the second join. Instead we connect to -% \pgf@nfold@cur@movedlast (which is *closer* to the first join than \pgf@nfold@cur@movedfirst in this edge case). -% To accomodate for the vertical offset we connect to \pgf@nfold@join@end which is the vertical -% offset of \pgf@nfold@cur@movedlast by definition. -\def\pgf@nfold@token@finish@normal{% - \pgfpathlineto{\pgf@nfold@join@end}% -} - -% parameter #1: @movedlast of the next segment -\def\pgf@nfold@token@finish@edgecase#1{% - \pgf@nfold@join@end% - \ifdim\insidepercentage pt<.5pt\relax% - \pgf@process{\pgfpointadd{#1}{\pgfpointpolar{\pgf@nfold@secondang+90}{\pgf@nfold@shiftamount}}} - \fi% - \pgfpathlineto{}% -} - - -% -% Main rendering pipeline -% ----------------------- -% - -% This stores whether the current segment should begin with a moveto to its offset -\newif\ifpgf@nfold@continuesegment -% This stores whether we are in some edge case of very close joins, see below for details -\newif\ifpgf@nfold@closejoinsedgecase -% This stores whether we are in an error case where we need to avoid dividing by zero -\newif\ifpgf@nfold@angletoosharp -% This stores whether we need the intersections library for an arrow tip but it is not loaded -\newif\ifpgf@nfold@intersectionsnotloaded -% This stores whether the currently processed connected sub-path is the final one on this path -\newif\ifpgf@nfold@lastconnsubpath - - -\def\pgf@nfold@parser@handlesegment{% - \if\pgf@nfold@cur@visible0 - % first, last and moveto are invisible - \if\pgf@nfold@cur@type m - % We don't need to do anything for a moveto; if a visible segment follows, it will move to - % its starting location by itself. However, we might need to draw the arrow tip extension - % at the start (if present). - % Draw a tip extension only if all of the following conditions are met: - % 1. There is an Implies tip at the start of this path - % 2. We are currently on the last connected sub-path of this path - % 3. The next segment is visible - % 4. This moveto is the first segment on this path - \if\pgf@nfold@start@arrowcode1 - \ifpgf@nfold@lastconnsubpath - \if\pgf@nfold@prev@type f - \if\pgf@nfold@next@visible1 - \edef\pgf@nfold@macrotoadd{% - \noexpand\pgf@nfold@extendtotip{s}{\pgf@nfold@cur@last}{\pgf@nfold@next@angle@i} - }% - \pgf@nfold@addmacro\pgf@parsed@cur@conn@seg% - % hack: We make the next segment believe that this segment was a lineto - % so the path does not get interrupted - \let\pgf@nfold@cur@type l - \let\pgf@nfold@cur@visible1 - \let\pgf@nfold@cur@angle@ii\pgf@nfold@next@angle@i - \let\pgf@nfold@cur@tang@ii\pgf@nfold@next@tang@i - \def\pgf@nfold@deltaphi@end{0} - \pgf@nfold@angletoosharpfalse - \fi - \fi% - \fi - \fi - \fi% - \else% - \let\pgf@nfold@cur@movedfirst\pgf@nfold@cur@first - \let\pgf@nfold@cur@movedlast\pgf@nfold@cur@last - %%% Step 1: Make room for joins if necessary - % In order to make room for the join, it may be necessary to shorten the current segment - % at the start and/or the end. In here we store by how much the segment needs to be shortened. - \def\pgf@nfold@shortenstartjoin{0} - \def\pgf@nfold@shortenendjoin{0} - \pgf@nfold@closejoinsedgecasefalse - % Step 1.1: Make room for the join at the start if needed - \if\pgf@nfold@prev@visible0 - \pgf@nfold@continuesegmentfalse - \else - \pgf@nfold@continuesegmenttrue - % deltaphi@start can be recycled from deltaphi@end; - % \ifpgf@nfold@angletoosharp is also still set - \let\pgf@nfold@deltaphi@start\pgf@nfold@deltaphi@end - % set \pgf@xb := abs(deltaphi@start) - \pgf@xb=\pgf@nfold@deltaphi@start pt\relax - \ifdim\pgf@xb<0pt\relax - \pgf@xb=-\pgf@xb - \fi - \ifpgf@nfold@angletoosharp\else - \ifdim\pgf@xb>0.5pt\relax - % make room for the start join if the angle is nonzero; - % shortenstartjoin := hwidth*tan(.5*abs(deltaphi@start)) - \pgf@yb=.5\pgf@xb - \pgfmathtan@{\pgf@sys@tonumber\pgf@yb} - \pgf@yb=\pgf@nfold@hwidth\relax - \pgf@yb=\pgfmathresult\pgf@yb - \edef\pgf@nfold@shortenstartjoin{\pgf@sys@tonumber\pgf@yb} - \pgfextract@process\pgf@nfold@cur@movedfirst{% - \pgfpointadd{\pgf@nfold@cur@first}% - {\pgfqpointscale{\pgf@nfold@shortenstartjoin}{\pgf@nfold@cur@tang@i}}}% - % If the current segment is a curve, we need to relocate @supporta point as well, - % as otherwise the @first point could overtake it - \if\pgf@nfold@cur@type c - \pgf@process{\pgfpointdiff{\pgf@nfold@cur@first}{\pgf@nfold@cur@supporta}} - \pgfmathveclen@{\pgf@sys@tonumber\pgf@x}{\pgf@sys@tonumber\pgf@y} - \ifdim\pgfmathresult pt>0.1pt\relax - % regular curves (supporta != first): - % Increase dist(first, supporta) to sqrt(a^2 + b^2) where a=dist(first, supporta) and b=shortenstart. This way, the order of first and supporta is guaranteed to be preserved, and the change to supporta is as small as reasonably possible. - \pgfmathveclen@{\pgfmathresult}{\pgf@sys@tonumber\pgf@yb} - \pgfextract@process\pgf@nfold@cur@supporta{\pgfpointadd% - {\pgf@nfold@cur@first}% - {\pgfqpointscale{\pgfmathresult}{\pgf@nfold@cur@tang@i}}}% - \else - % special treatment for singular curves (supporta = first) to avoid rounding error glitches. - % In this special case, a slight corner at the end of the join is unavoidable unless we - % also relocate @supportb, which may have unintended side effects - \let\pgf@nfold@cur@supporta\pgf@nfold@cur@movedfirst - \fi - \fi - \fi - \fi - \fi - % Step 1.2: Make room for the join at the end if needed - \if\pgf@nfold@next@visible1 - % Compute the angle difference at the end (between -180 and +180 degrees) - % using \pgfmathsubtract@ is more readable and no less efficient than computing this manually - \pgfmathsubtract@{\pgf@nfold@next@angle@i}{\pgf@nfold@cur@angle@ii} - \pgf@nfold@clampangle - % Edge case handling: If the next segment is a closepath and has length zero, deltaphi is set - % to zero to prevent glitches (a zero length segment has no well-defined angle anyway) - \edef\pgf@nfold@deltaphi@end{\pgfmathresult} - \pgf@xb=\pgf@nfold@deltaphi@end pt\relax - \ifdim\pgf@xb<0pt\relax - \pgf@xb=-\pgf@xb - \fi - \ifdim\pgf@xb>178pt\relax - \pgfutil@packagewarning{tikz-nfold}{Angle too sharp, expect visual errors} - \pgf@nfold@angletoosharptrue - \else - \pgf@nfold@angletoosharpfalse - \ifdim\pgf@xb>0.5pt\relax - % make room for the start join if the angle is nonzero - % shortenendjoin := hwidth*tan(.5*abs(deltaphi@end)) - \pgf@yb=.5\pgf@xb - \pgfmathtan@{\pgf@sys@tonumber\pgf@yb} - \pgf@yb=\pgf@nfold@hwidth\relax - \pgf@yb=\pgfmathresult\pgf@yb - \edef\pgf@nfold@shortenendjoin{\pgf@sys@tonumber\pgf@yb} - \pgf@yb=-\pgf@yb - \pgfextract@process\pgf@nfold@cur@movedlast{% - % the use of the minus sign is fine here because \pgf@nfold@shortenendjoin >= 0.0 - \pgfpointadd{\pgf@nfold@cur@last}% - {\pgfqpointscale{-\pgf@nfold@shortenendjoin}{\pgf@nfold@cur@tang@ii}}}% - \pgfextract@process\pgf@nfold@cur@movedlast{% - \pgfpointadd{\pgf@nfold@cur@last}% - {\pgfqpointpolar{\pgf@nfold@cur@angle@ii}{\pgf@yb}}}% - \if\pgf@nfold@cur@type c - % Same procedure as above: relocate supportb if we have a curve - \pgf@process{\pgfpointdiff{\pgf@nfold@cur@supportb}{\pgf@nfold@cur@last}} - \pgfmathveclen@{\pgf@sys@tonumber\pgf@x}{\pgf@sys@tonumber\pgf@y} - \ifdim\pgfmathresult pt>0.1pt\relax - \pgfmathveclen@{\pgfmathresult}{\pgf@sys@tonumber\pgf@yb} - \pgfextract@process\pgf@nfold@cur@supportb{\pgfpointadd% - {\pgf@nfold@cur@last}% - % can use qpointscale and a minus because \pgfmathresult is guaranteed to be positive - {\pgfqpointscale{-\pgfmathresult}{\pgf@nfold@cur@tang@ii}}}% - \else - \let\pgf@nfold@cur@supportb\pgf@nfold@cur@movedlast - \fi - \fi - \fi - \fi - % Step 1.3: Detect an edge case - % This edge case appears whenever the current segment is such a short line that we would - % have to reduce its length to less than zero to make room for the joins. In such cases, - % the line is not drawn at all, and slight modifications must be made to the joins to ensure - % a correct output (i.e. one join is immediately followed by the next without a segment in between). - % - % This edge case can appear for curves as well, but they are much harder to deal with. - \if\pgf@nfold@cur@type l - % No need to check for \pgf@nfold@inputsegmentclosepath as it should not be followed by any further segments - % Now: Check if the total amount of shortening is larger than the length of the segment - \pgf@process{\pgfpointdiff{\pgf@nfold@cur@first}{\pgf@nfold@cur@last}} - \pgfmathveclen@{\pgf@sys@tonumber\pgf@x}{\pgf@sys@tonumber\pgf@y} - \pgf@xa=\pgf@nfold@shortenstartjoin pt\relax - \advance\pgf@xa by\pgf@nfold@shortenendjoin pt\relax - \ifdim\pgf@xa>\pgfmathresult pt\relax - \pgf@nfold@closejoinsedgecasetrue - \fi - \fi - \fi% end if next segment visible - % - % Step 2.1: Draw the join at the start if applicable - % - \if\pgf@nfold@prev@visible0% - \ifpgf@nfold@closejoinsedgecase - % If the previous segment is a moveto and the current segment is a "close joins" edge case, - % nothing needs to be drawn here (the relevant draw call will be made at the join of the subsequent - % segment). We must therefore make sure that we move to the correct end point of this segment. - % Counterintuitively, this is given by the offset of \pgf@nfold@cur@movedFIRST since the start and end - % are reversed in the edge case. - \edef\pgf@nfold@macrotoadd{% - \noexpand\pgf@nfold@token@edgecase@movetostart{\pgf@nfold@cur@movedfirst}{\pgf@nfold@cur@angle@i}% - }% - \pgf@nfold@addmacro\pgf@parsed@cur@conn@seg% - \fi - \else - % If we draw the join when the start angle is close to 180 degrees, we get a division by zero - \ifpgf@nfold@angletoosharp\else - \if\pgf@nfold@cur@type z\else - \pgf@nfold@parser@handlejoin - \fi - \fi - \fi - % Step 2.2: Store information that may be needed later - % Step 2.2.1: Store where the current (non-offset) end point was relocated - % in order to make space for the end join. This may be used if the next - % segment begins with a join - \let\pgf@nfold@prev@segment@end\pgf@nfold@cur@movedlast - % Step 2.2.2: Store the tangent of the first proper segment of closed path. - % This is needed in case the \pgfpathclose-segment has length zero, - % since in that case its tangent cannot be computed. - \if\pgf@nfold@cur@type i - \let\pgf@nfold@connsubpath@tang@i\pgf@nfold@next@tang@i% - \let\pgf@nfold@connsubpath@angle@i\pgf@nfold@next@angle@i% - \fi - % - % Step 3: Draw the new segment. - % - % The value of \ifpgf@nfold@continuesegment decides whether we start with a moveto. - \if\pgf@nfold@cur@type l - % In the edge case, one join is followed immediately by the next. The line segment - % thus has a negative length and will be skipped. - \ifpgf@nfold@closejoinsedgecase\else - \edef\pgf@nfold@macrotoadd{% - \expandafter\noexpand\ifpgf@nfold@continuesegment% - \pgf@nfold@token@lineto@continue% - \else% - \pgf@nfold@token@lineto% - \fi{\pgf@nfold@cur@movedfirst}{\pgf@nfold@cur@movedlast}{\pgf@nfold@cur@tang@i}% - }% - \pgf@nfold@addmacro\pgf@parsed@cur@conn@seg% - \fi - \fi - \if\pgf@nfold@cur@type o - \def\pgf@nfold@macrotoadd{\pgf@nfold@token@closepath}% - \pgf@nfold@addmacro\pgf@parsed@cur@conn@seg% - \fi - \if\pgf@nfold@cur@type z - % zero and non-zero closepath's differ in the join handling, but are identical in rendering - \def\pgf@nfold@macrotoadd{\pgf@nfold@token@closepath}% - \pgf@nfold@addmacro\pgf@parsed@cur@conn@seg% - \fi - \if\pgf@nfold@cur@type c - \ifpgf@nfold@continuesegment - \pgf@subdividecurve{\pgf@nfold@cur@movedfirst}{\pgf@nfold@cur@supporta}{\pgf@nfold@cur@supportb}{\pgf@nfold@cur@movedlast}{\pgf@offset@max@recursion}{0}{\pgf@nfold@addcurvesegment@callback@continue} - \else - \pgf@subdividecurve{\pgf@nfold@cur@movedfirst}{\pgf@nfold@cur@supporta}{\pgf@nfold@cur@supportb}{\pgf@nfold@cur@movedlast}{\pgf@offset@max@recursion}{0}{\pgf@nfold@addcurvesegment@callback}% - \fi - \fi - \if\pgf@nfold@cur@type i - \edef\pgf@nfold@macrotoadd{% - \noexpand\pgf@nfold@token@invisibleline{\pgf@nfold@cur@movedfirst}{\pgf@nfold@cur@movedlast}{\pgf@nfold@cur@tang@i}% - }% - \pgf@nfold@addmacro\pgf@parsed@cur@conn@seg% - \fi - % Step 4: Extend into the arrow tip at the end (if present) - \if\pgf@nfold@next@type t% - \ifnum\pgf@nfold@end@arrowcode=1 - \edef\pgf@nfold@macrotoadd{% - \noexpand\pgf@nfold@extendtotip{e}{\pgf@nfold@cur@last}{\pgf@nfold@cur@angle@ii}}% - \pgf@nfold@addmacro\pgf@parsed@cur@conn@seg% - \fi% - \fi% - \fi% end if current visible -} - - -\def\pgf@nfold@addcurvesegment@callback#1#2#3#4#5{% - \if#50% - \edef\pgf@nfold@macrotoadd{% - % The subdivision algorithm has already computed the tangents - \noexpand\pgf@nfold@token@curveto{#1}{#2}{#3}{#4}{\pgf@tmp@tang@i}{\pgf@tmp@tang@ii}% - }% - \pgf@nfold@addmacro\pgf@parsed@cur@conn@seg% - \else% - \pgf@nfold@addcurvesegment@callback@continue{#1}{#2}{#3}{#4}{#5}% - \fi% -} - -\def\pgf@nfold@addcurvesegment@callback@continue#1#2#3#4#5{% - % The subdivision algorithm has already computed the tangents - \edef\pgf@nfold@macrotoadd{% - \noexpand\pgf@nfold@token@curveto@continue{#1}{#2}{#3}{#4}{\pgf@tmp@tang@i}{\pgf@tmp@tang@ii}% - }% - \pgf@nfold@addmacro\pgf@parsed@cur@conn@seg% -} - - -% Rendering arrow tips -% -------------------- - -% Precomputed intersections -% -% For arrows of order n > 2 with an Implies tip, the constituent parts of the n-fold arrow -% end somewhere in the middle of the tip. The exact end point must be computed using -% the intersections library. To speed up compilation times, the intersection points are precomputed -% up to n = 5. If your document contains arrows of order 6 or larger, consider adding those -% as well; the values are output in the log file. -\expandafter\def\csname pgf@nfold@intersec@cache@2@3\endcsname{\pgfqpoint{2pt}{0pt}} -\expandafter\def\csname pgf@nfold@intersec@cache@2@4\endcsname{\pgfqpoint{0.94063pt}{-0.33333pt}} -\expandafter\def\csname pgf@nfold@intersec@cache@3@4\endcsname{\pgfqpoint{0.94063pt}{0.33333pt}} -\expandafter\def\csname pgf@nfold@intersec@cache@2@5\endcsname{\pgfqpoint{0.64167pt}{-0.5pt}} -\expandafter\def\csname pgf@nfold@intersec@cache@3@5\endcsname{\pgfqpoint{2pt}{0pt}} -\expandafter\def\csname pgf@nfold@intersec@cache@4@5\endcsname{\pgfqpoint{0.64167pt}{0.5pt}} -% intersections are precomputed up to this order -\def\pgf@nfold@intersec@numcached{5} - -% This macro extends the arrow body to the tips -% #1: s=start, e=end -% #2: start/end point of the path -% #3: angle -\newif\ifpgf@nfold@ontheedge -\def\pgf@nfold@extendtotip#1#2#3{ - \ifpgf@nfold@intersectionsnotloaded - \pgfutil@packageerror{tikz-nfold}{% - If `nfold' is larger than \pgf@nfold@intersec@numcached\space and you use - an `Implies' arrow tip you need to say \string\usetikzlibrary{intersections}}{} - \else - \pgf@nfold@ontheedgetrue - % Do not extend the arrow for index=1 and index=order, it already ends in the right place - \ifnum\pgf@nfold@index>1\relax\ifnum\pgf@nfold@index<\pgf@nfold@order\relax% - \pgf@nfold@ontheedgefalse - \fi\fi - \ifpgf@nfold@ontheedge% - % the extension at the start needs a moveto to the correct starting point - \if#1s - \pgfpathmoveto{\pgfpointadd{#2}{\pgfpointpolar{#3+90}{\pgf@nfold@shiftamount}}}% - \fi - \else - % Step 1: Find the intersection of the arrow's path with the head - \ifcsname pgf@nfold@intersec@cache@\the\pgf@nfold@index @\the\pgf@nfold@order\endcsname - \pgfextract@process\pgf@nfold@arrowintersect - {\csname pgf@nfold@intersec@cache@\the\pgf@nfold@index @\the\pgf@nfold@order\endcsname}% - \else - % the intersection has not been precomputed, thus compute on the fly here - \pgfintersectionofpaths{ - % specify the tip - \pgfpathmoveto{\pgfqpoint{-1.4pt}{2.65pt}} - \pgfpathcurveto{\pgfqpoint{-0.75pt}{1.25pt}}{\pgfqpoint{1pt}{0.05pt}}{\pgfqpoint{2pt}{0pt}} - \pgfpathcurveto{\pgfqpoint{1pt}{-0.05pt}}{\pgfqpoint{-0.75pt}{-1.25pt}}{\pgfqpoint{-1.4pt}{-2.65pt}} - }{ - % extend the body to intersect the tip - \pgfpathmoveto{\pgfqpoint{-3pt}{\pgf@nfold@shift@fraction pt}} - \pgfpathlineto{\pgfqpoint{3pt}{\pgf@nfold@shift@fraction pt}} - } - \ifnum\pgfintersectionsolutions>0 - \pgfextract@process\pgf@nfold@arrowintersect{\pgfpointintersectionsolution{1}}% - \immediate\write17{tikz-nfold: computed intersection cache@\the\pgf@nfold@index @\the\pgf@nfold@order: \string\pgfqpoint{\the\pgf@x}{\the\pgf@y}^^J} - % add the new intersection to the cache - \expandafter\xdef\csname pgf@nfold@intersec@cache@\the\pgf@nfold@index @\the\pgf@nfold@order\endcsname{\noexpand\pgfqpoint{\the\pgf@x}{\the\pgf@y}} - \else - % this is a failsafe and should never be reached - \pgfutil@packagewarning{tikz-nfold}{did not find intersection} - \pgfextract@process\pgf@nfold@arrowintersect{\pgfqpoint{0pt}{\pgf@nfold@shift@fraction pt}}% - \fi - \fi% if precomputed - % Step 2: Extend the arrow body to the intersection point. - % If the tip is at the beginning of the path, we have to move to the intersection - % and then draw a line to the "regular" starting point. The subsequent segment then - % should omit its moveto. - % If the tip is at the end, we are already in the right position and only need to extend - % the current path to the intersection point. - \begingroup - \pgftransformreset - \pgftransformshift{#2} - \pgftransformrotate{#3} - \if#1s - \pgftransformxscale{-1} - \fi - % we don't want to undo the shift by .42\pgflinewidth after the scaling - \pgfutil@tempdima=\pgf@nfold@hwidth - \pgfutil@tempdima=\pgf@nfold@shift@fraction\pgfutil@tempdima - \pgfextract@process\pgf@nfold@startofextension - {\pgfpointtransformed{\pgfqpoint{0pt}{\pgfutil@tempdima}}} - % 0.5 - 0.06 = 0.42 - \pgftransformshift{\pgfqpoint{.42\pgflinewidth}{0pt}} - \pgftransformscale{\pgf@nfold@hwidth} - \pgfextract@process\pgf@nfold@arrowintersect{\pgfpointtransformed{\pgf@nfold@arrowintersect}} - \global\let\pgf@nfold@startofextension\pgf@nfold@startofextension - \global\let\pgf@nfold@arrowintersect\pgf@nfold@arrowintersect - \endgroup - \if#1s - \pgfpathmoveto{\pgf@nfold@arrowintersect} - % This is precisely the start of the body, shifted vertically - \pgfpathlineto{\pgf@nfold@startofextension} - \else\if#1e - \pgfpathlineto{\pgf@nfold@arrowintersect} - \else - \pgfutil@packageerror{tikz-nfold}{Invalid argument to \string\pgf@nfold@extendtotip: \meaning#1}{} - \fi\fi - \pgftransformreset - \fi% if 1 < i < nArrows - \fi% if intersections is needed and not loaded -} - -% Parsing the arrow tips -% ---------------------- -% -% We need to detect if the user has set Implies[] arrows at the start and/or end tip. -% To do so, we parse \pgf@start@tip@sequence. If the user specifies Implies[] manually, -% we find that -% pgf@start@tip@sequence=\pgf@arrow@handle{Implies}{...} -% However, in other cases (like tikz-cd) we may find -% \pgf@arrow@handle@shorthand@empty {\csname pgf@ar@means@tikzcd implies cap\endcsname } -% In such cases we must expand the first parameter once and then match as above. - -% Set global defaults -\def\pgf@nfold@start@arrowcode{0} -\def\pgf@nfold@end@arrowcode{0} - -\def\pgf@nfold@parsearrows{ - \ifpgfutil@tempswa% this is set in \pgfusepath and stores whether we draw arrow tips at all - \expandafter\pgf@nfold@parsearrowmacro\pgf@start@tip@sequence\relax - \let\pgf@nfold@start@arrowcode\pgf@nfold@detectedarrow - \expandafter\pgf@nfold@parsearrowmacro\pgf@end@tip@sequence\relax - \let\pgf@nfold@end@arrowcode\pgf@nfold@detectedarrow - \else - \def\pgf@nfold@start@arrowcode{0} - \def\pgf@nfold@end@arrowcode{0} - \fi -} - -\def\pgf@nfold@parsearrowmacro#1{% - \def\pgf@nfold@detectedarrow{0} - \ifx#1\relax - \let\pgf@next\relax - \else - \ifx#1\pgf@arrow@handle - % found \pgf@arrow@handle{...}, now parse the first parameter - \let\pgf@next\pgf@nfold@parse@arrow@handle - \else - \ifx#1\pgf@arrow@handle@shorthand@empty - \let\pgf@next\pgf@nfold@parse@shorthandempty - \else - % found nothing - \let\pgf@next\pgfutil@gobble@until@relax - \fi - \fi - \fi - \pgf@next -} - -\def\pgf@nfold@param@Implies{Implies} - -\def\pgf@nfold@parse@arrow@handle#1{% - \def\pgf@tmp{#1} - \ifx\pgf@tmp\pgf@nfold@param@Implies - \def\pgf@nfold@detectedarrow{1} - \fi - \pgfutil@gobble@until@relax -} - -\def\pgf@nfold@parse@shorthandempty#1{ - % Expand #1 once (\pgf@arrow@handle@shorthand@empty is just an identity operator) - \expandafter\def\expandafter\pgf@tmp\expandafter{#1} - \expandafter\pgf@nfold@parsearrowmacro\pgf@tmp\relax - % still need to gobble the rest of the orginal arrow definition - \pgfutil@gobble@until@relax -} - - -% -% Hooking into pgf's rendering pipeline -% ------------------------------------- -% -% The new code has to be injected into \pgfusepath (pgfcorepathusage.code.tex). For rendering the new paths, -% \pgf@stroke@inner@line is a natural choice as this is where /tikz/double is rendered. However, we also -% need to disable rendering the ordinary path, which is not as easy. In the future I will make a pull request -% to TikZ to simplify such injections. -% -% The call to draw the path comes right before \pgf@stroke@inner@line. The macro before \pgf@stroke@inner@line -% is either \pgf@path@check@proper or \pgf@prepare@start@of@path (depending on the result of the proper check). -% We therefore must inject code into both of them to see if nfold is enabled. If it is, we call the old macro, -% cache and delete the current softpath (so the call to \pgfsyssoftpath@invokecurrentpath has no effect), then we -% restore and offset the cached softpath in \pgf@stroke@inner@line. -% -% The macros \pgf@path@check@proper and \pgf@prepare@start@of@path are also used in \pgf@up@draw@arrows@only, -% so we must make sure that the latter is unaffected by the modifications. Luckily, this turns out not to be -% a problem - the only macros that are called after the modified ones are \pgf@add@arrow@at@start and -% \pgf@add@arrow@at@end, which do not change their behaviour even if we modify the paths. -% - -\newcount\pgf@nfold@order -\pgf@nfold@order=1 - -\def\pgf@nfold@preparenfoldpath{% - \ifnum\pgf@nfold@order>1\relax - \ifdim\pgfinnerlinewidth>0pt\relax - % Hack the rendering pipeline: There is a \pgfsyssoftpath@invokecurrentpath call following - % which we do not want if nfold is active. We therefore clear the current path here - % and then perform the nfold drawing in our modification of \pgf@stroke@inner@line - \pgfsyssoftpath@getcurrentpath\pgf@nfold@cachedpath% - \pgfsyssoftpath@setcurrentpath\pgfutil@empty% - \else - \pgfutil@packageerror{tikz-nfold}{Must set \string\pgfinnerlinewidth\space to use nfold, e.g. by setting /tikz/double distance}{} - \fi - \fi -} - -\let\pgf@nfold@old@path@check@proper\pgf@path@check@proper -\def\pgf@path@check@proper{% - \pgf@nfold@old@path@check@proper% - \ifpgfutil@tempswa\else% - % if \pgfutil@tempswa is false, this is the last macro we can overwrite before the draw call. - % Otherwise, we inject into \pgf@prepare@start@of@path% - \pgf@nfold@preparenfoldpath% - \fi% -} - -\let\pgf@nfold@old@prepare@start@of@path\pgf@prepare@start@of@path -\def\pgf@prepare@start@of@path{% - \pgf@nfold@old@prepare@start@of@path% - \pgf@nfold@preparenfoldpath% -} - -\let\pgf@nfold@old@stroke@inner@line\pgf@stroke@inner@line -\def\pgf@stroke@inner@line{% - \ifnum\pgf@nfold@order>1\relax% - \pgf@nfold@render@cached@softpath% - \else% - % Old behaviour - \pgf@nfold@old@stroke@inner@line% - \fi% -} - - -% -% Parsing the soft path -% --------------------- -% -% A significant part of the code below is based on pgfmoduledecorations.code.tex (c) 2019 Mark Wibrow and Till Tantau. -% Quite similar to decorations we parse the current soft path and put it into a form that makes it easier -% to iterate over. -% +% This work consists of the files +% pgflibrarybezieroffset.code.tex, pgflibrarynfold.code.tex, pgflibraryoffsetpath.code.tex, tikz-nfold-doc.tex, tikzlibrarynfold.code.tex, tikz-nfold-doc.tex, and tikz-nfold-doc.pdf. % - - % -% In order to correctly implement \pgfpathclose we already need to know about -% the \pgfpathclose (and the penultimate point) at the beginning of this -% connected sub-path as these data affect the first/last join. -% We therefore parse one connected sub-path of the softpath and store it in a modified -% form in \pgf@cur@conn@subpath. When reaching the end of the connected sub-path we call -% the proper parser to turn \pgf@cur@conn@subpath into a parsed path. We do this for -% all connected sub-paths and concatenate all the parsed paths. +% A commented version of this file can be found on https://github.com/jonschz/tikz-nfold . % -\def\pgf@nfold@parsesoftpath#1#2{% - \let\pgf@cur@conn@subpath\pgfutil@empty% - \let\pgf@all@parsed@subpaths\pgfutil@empty% - \edef\pgf@nfold@parser@last@moveto{{\the\pgf@path@lastx}{\the\pgf@path@lasty}}% - \let\pgf@nfold@last@closepath@from\pgfutil@empty% - \pgf@nfold@parse@setupfirst% - \expandafter\pgf@nfold@@parsesoftpath#1\pgf@stop{}{}% - \let#2\pgf@all@parsed@subpaths% -}% - -\def\pgf@nfold@@parsesoftpath#1#2#3{% - \let\pgf@next\pgf@nfold@@parsesoftpath% - \ifx#1\pgf@stop% - \def\pgf@nfold@macrotoadd{\pgf@nfold@parselast}% - \pgf@nfold@addmacro\pgf@cur@conn@subpath% - \pgf@nfold@lastconnsubpathtrue% - \pgf@nfold@process@conn@subpath% - \let\pgf@next\relax% - \else% - \ifx#1\pgfsyssoftpath@movetotoken% - \ifx\pgf@cur@conn@subpath\pgfutil@empty% - % This case happens for the very first segment or for double movetos. - % We need special treatment here, as otherwise the arrow tip extension - % does not work correctly. The \pgf@nfold@parsemoveto will be called - % in \pgf@nfold@process@conn@subpath. - \def\pgf@nfold@parser@last@moveto{{#2}{#3}}% - % Make sure \pgf@cur@conn@subpath is no longer empty so double movetos are not - % treated the same as single movetos. This is also relevant to arrow tip extensions - \def\pgf@cur@conn@subpath{\relax}% - \else% - \def\pgf@nfold@macrotoadd{\pgf@nfold@parsemoveto{#2}{#3}}% - \pgf@nfold@addmacro\pgf@cur@conn@subpath% - \pgf@nfold@lastconnsubpathfalse% - % A moveto marks the beginning/end of one connected sub-path - \pgf@nfold@process@conn@subpath% - \let\pgf@nfold@last@closepath@from\pgfutil@empty% - \let\pgf@cur@conn@subpath\pgfutil@empty% - % set up "first" again which may be needed for the arrow tip extension - \pgf@nfold@parse@setupfirst% - \def\pgf@nfold@parser@last@moveto{{#2}{#3}}% - \fi - \else% - \ifx#1\pgfsyssoftpath@linetotoken% - \def\pgf@nfold@macrotoadd{\pgf@nfold@parselineto{#2}{#3}}% - \pgf@nfold@addmacro\pgf@cur@conn@subpath% - \else% - \ifx#1\pgfsyssoftpath@curvetosupportatoken% - \def\pgf@nfold@parse@supporta{{#2}{#3}}% - \else% - \ifx#1\pgfsyssoftpath@curvetosupportbtoken% - \def\pgf@nfold@parse@supportb{{#2}{#3}}% - \else% - \ifx#1\pgfsyssoftpath@curvetotoken% - \edef\pgf@nfold@macrotoadd{\noexpand\pgf@nfold@parsecurveto\pgf@nfold@parse@supporta\pgf@nfold@parse@supportb{#2}{#3}}% - \pgf@nfold@addmacro\pgf@cur@conn@subpath% - \else% - \ifx#1\pgfsyssoftpath@closepathtoken% - \let\pgf@nfold@last@closepath@from\pgf@nfold@parser@previous@pt% - \def\pgf@nfold@macrotoadd{\pgf@nfold@parseclosepath{#2}{#3}}% - \pgf@nfold@addmacro\pgf@cur@conn@subpath% - \else% - \ifx#1\pgfsyssoftpath@rectcornertoken% - \def\pgf@nfold@parse@rectcorner{{#2}{#3}}% - \else% - \ifx#1\pgfsyssoftpath@rectsizetoken% - \edef\pgf@nfold@macrotoadd{\noexpand\pgf@nfold@parserect\pgf@nfold@parse@rectcorner{#2}{#3}}% - \pgf@nfold@addmacro\pgf@cur@conn@subpath% - \else% - \pgfutil@packageerror{tikz-nfold}{Unrecognised soft path token `#1'}{}% - \fi% - \fi% - \fi% - \fi% - \fi% - \fi% - \fi% - \fi% - \fi% - \def\pgf@nfold@parser@previous@pt{{#2}{#3}}% - % store the last two segments, as they might be needed for zero-length \pgfpathclose-segments - \let\pgf@nfold@sectolast@segment\pgf@nfold@last@segment% - \let\pgf@nfold@last@segment\pgf@nfold@macrotoadd% - \pgf@next}% - -\def\pgf@nfold@process@conn@subpath{% - \let\pgf@parsed@cur@conn@seg\pgfutil@empty% - \ifx\pgf@nfold@last@closepath@from\pgfutil@empty% - \expandafter\pgf@nfold@parsemoveto\pgf@nfold@parser@last@moveto% - \else% - % This connected sub-path ends on a closepath. In order to get - % the join right, we prepend the current sub-path with an invisible line - % identical to the line of the \pgfpathclose. - \expandafter\pgf@nfold@parsemoveto\pgf@nfold@last@closepath@from% - \expandafter\pgf@nfold@parseinvisibleline\pgf@nfold@parser@last@moveto% - \fi% - \pgf@cur@conn@subpath% - \let\pgf@nfold@macrotoadd\pgf@parsed@cur@conn@seg% - \pgf@nfold@addmacro\pgf@all@parsed@subpaths% -} - -% -% Values for \pgf@nfold@next@type: -% f=first, m=moveto, c=curveto, l=lineto, r=rect, o=closepath, z=zero length closepath, t=last, i=invisibleline -% - -\def\pgf@nfold@parsemoveto#1#2{% - \pgf@nfold@parser@moveup% - \let\pgf@nfold@next@type=m% - \let\pgf@nfold@next@visible=0% - \edef\pgf@nfold@next@last{\pgf@x#1\pgf@y#2}% - \pgf@nfold@parser@handlesegment% -}% - - -% Common code for parselineto and parseclosepath -\def\pgf@nfold@parse@line@common#1#2#3{% - \pgf@nfold@parser@moveup% - \pgfextract@process\pgf@tmp@tang@i{\pgfpointnormalised{}\global\let\pgf@nfold@tmp\pgf@tmp} - \let\pgf@nfold@next@type=#3% - \let\pgf@nfold@next@visible=1% - \let\pgf@nfold@next@tang@i\pgf@tmp@tang@i - \let\pgf@nfold@next@tang@ii\pgf@tmp@tang@i - \let\pgf@nfold@next@angle@i\pgf@nfold@tmp - \let\pgf@nfold@next@angle@ii\pgf@nfold@tmp - \let\pgf@nfold@next@first\pgf@nfold@cur@last - \def\pgf@nfold@next@last{\pgf@x#1\pgf@y#2}% - \pgf@nfold@parser@handlesegment% -} - -\def\pgf@nfold@parselineto#1#2{% - % the current end is still stored in next@last because parser@moveup has not been called yet - \pgf@process{\pgfpointdiff{\pgf@nfold@next@last}{\pgf@x#1\pgf@y#2}}% - \pgfpointtaxicabnorm\pgf@xa% - % remove degenerate line segments (reduces glitches) - \ifdim\pgf@xa>.1pt\relax% - \pgf@nfold@parse@line@common{#1}{#2}{l}% - \fi% -}% - -\def\pgf@nfold@parsecurveto#1#2#3#4#5#6{% - \pgf@nfold@parser@moveup% - \pgf@offset@compute@tangents{\pgf@nfold@cur@last}{\pgf@x#1\pgf@y#2}{\pgf@x#3\pgf@y#4}{\pgf@x#5\pgf@y#6}% - \let\pgf@nfold@next@type=c% - \let\pgf@nfold@next@visible=1% - % the following only need to be set if visible=1 - \let\pgf@nfold@next@tang@i=\pgf@tmp@tang@i - \let\pgf@nfold@next@tang@ii=\pgf@tmp@tang@ii - \let\pgf@nfold@next@angle@i\pgf@tmp@angle@i - \let\pgf@nfold@next@angle@ii\pgf@tmp@angle@ii - \let\pgf@nfold@next@first\pgf@nfold@cur@last - \def\pgf@nfold@next@supporta{\pgf@x#1\pgf@y#2} - \def\pgf@nfold@next@supportb{\pgf@x#3\pgf@y#4} - \def\pgf@nfold@next@last{\pgf@x#5\pgf@y#6} - \pgf@nfold@parser@handlesegment% -}% - -\def\pgf@nfold@parseclosepath#1#2{% - \pgf@process{\pgfpointdiff{\pgf@nfold@next@last}{\pgf@x#1\pgf@y#2}}% - % closepath segments should always be processed even if they have zero length - \pgfpointtaxicabnorm\pgf@xa% - \ifdim\pgf@xa<0.1pt\relax% - \pgf@nfold@parse@closepath@zerolength{#1}{#2}% - \else% - \pgf@nfold@parse@line@common{#1}{#2}{o}% - \fi% -}% - -\def\pgf@nfold@parse@closepath@zerolength#1#2{% - \pgf@nfold@parser@moveup% - \let\pgf@nfold@next@type=z% - \let\pgf@nfold@next@visible=1% - % Set the start and end tangent to the tangent of the first segment - \let\pgf@nfold@next@tang@i\pgf@nfold@connsubpath@tang@i - \let\pgf@nfold@next@tang@ii\pgf@nfold@connsubpath@tang@i - \let\pgf@nfold@next@angle@i\pgf@nfold@connsubpath@angle@i - \let\pgf@nfold@next@angle@ii\pgf@nfold@connsubpath@angle@i - \let\pgf@nfold@next@first\pgf@nfold@cur@last - % If problems arise, we need to put a fake point here (like \pgf@nfold@next@first + \pgf@nfold@next@tang@i) - \def\pgf@nfold@next@last{\pgf@x#1\pgf@y#2}% - \pgf@nfold@parser@handlesegment% -} - -\def\pgf@nfold@parseinvisibleline#1#2{% - \pgf@process{\pgfpointdiff{\pgf@nfold@next@last}{\pgf@x#1\pgf@y#2}}% - \pgfpointtaxicabnorm\pgf@xa% - % In order to correctly render the start/end join in a closed path, - % the \pgfpathclose segment is copied to the start of the path as an invisible line. - % Counterintuitively, an "invisibleline" segment has next@visible=1 because - % we want its end join to be rendered. - % In case the \pgfpathclose segment has non-zero length, we can just use a copy of - % this segment for the invisible line. Otherwise, the invisble line segment must will receive - % the same angle/tangent as the last finite-sized segment, which is the second-to-last - % segment overall (cached in \pgf@nfold@sectolast@segment). - \ifdim\pgf@xa>.1pt\relax% - \pgf@nfold@parse@line@common{#1}{#2}{i}% - \else% - \begingroup% - % find the tangent of the second-to-last segment - \let\pgf@nfold@parser@handlesegment\relax% - \pgf@nfold@sectolast@segment% - \global\let\pgf@nfold@tmp\pgf@nfold@next@tang@ii% - \endgroup% - % Construct an invisible line with length 1pt and the correct tangent. - % This step might not be needed since the join computations only require the tangent, - % but the invisibleline segment would be inconsistent otherwise, so better play it safe. - \pgfextract@process\pgf@nfold@next@first{\pgfpointdiff{\pgf@nfold@tmp}{\pgfqpoint{#1}{#2}}}% - % write the tangent into (\pgf@x, \pgf@y) where the next macro expects it to be - \pgf@nfold@tmp% - \pgf@nfold@parse@line@common{#1}{#2}{i}% - \fi% -}% - -\def\pgf@nfold@parselast{% - \pgf@nfold@parser@moveup% - \let\pgf@nfold@next@type=t% - \let\pgf@nfold@next@visible=0% - \pgf@nfold@parser@handlesegment% -} - -% Mostly for the sake of completeness; using TikZ' "\path (0,0) rectangle (1,1);" does not call this code -\def\pgf@nfold@parserect#1#2#3#4{% - \pgf@nfold@parsemoveto{#1}{#2}% - \pgf@xc=#1\relax - \pgf@yc=#2\relax - \pgf@xd=#3\relax - \pgf@yd=#4\relax - \advance\pgf@yc\pgf@yd% - \edef\pgf@temp{{\the\pgf@xc}{\the\pgf@yc}}% - \expandafter\pgf@nfold@parselineto\pgf@temp% - \advance\pgf@xc\pgf@xd% - \edef\pgf@temp{{\the\pgf@xc}{\the\pgf@yc}}% - \expandafter\pgf@nfold@parselineto\pgf@temp% - \advance\pgf@yc-\pgf@yd% - \edef\pgf@temp{{\the\pgf@xc}{\the\pgf@yc}}% - \expandafter\pgf@nfold@parselineto\pgf@temp% - \advance\pgf@xc-\pgf@xd% - \edef\pgf@temp{{\the\pgf@xc}{\the\pgf@yc}}% - \expandafter\pgf@nfold@parselineto\pgf@temp% - \edef\pgf@marshal{\noexpand\pgf@nfold@parsemoveto{\the\pgf@xc}{\the\pgf@yc}}% - \pgf@marshal% -} - -% adds the contents of \pgf@nfold@macrotoadd to #1 -\def\pgf@nfold@addmacro#1{% - % need a \gdef because we have nested groups in the subdivision - \expandafter\expandafter\expandafter\gdef% - \expandafter\expandafter\expandafter#1% - \expandafter\expandafter\expandafter{% - \expandafter#1\pgf@nfold@macrotoadd}% -} - - -% -% Tokens for the parsed path -% - -%#3: cached normalised tangent (for efficiency) -\def\pgf@nfold@token@lineto#1#2#3{% - \pgfoffsetline@{#1}{#2}{\pgf@nfold@shiftamount}{#3}% -} - -\def\pgf@nfold@token@lineto@continue#1#2#3{% - \pgfoffsetlinenomove@{#1}{#2}{\pgf@nfold@shiftamount}{#3}% -} - -\def\pgf@nfold@token@invisibleline#1#2#3{% - % An invisible line should execute a moveto to the end point of the line - \pgfqpointscale{\pgf@nfold@shiftamount}{#3}% - \pgf@xc=-\pgf@y% - \pgf@y=\pgf@x% - \pgf@x=\pgf@xc% - \pgfpathmoveto{\pgfpointadd{}{#2}}% -} - -% #5, #6: cached normalised tangents at start and end (for efficiency) -\def\pgf@nfold@token@curveto#1#2#3#4#5#6{% - \def\pgf@tmp@tang@i{#5}% - \def\pgf@tmp@tang@ii{#6}% - \pgf@offset@bezier@segment@{#1}{#2}{#3}{#4}{\pgf@nfold@shiftamount}% - \pgfpathmoveto{\pgf@bezier@offset@i}% - \pgfpathcurveto{\pgf@bezier@offset@ii}{\pgf@bezier@offset@iii}{\pgf@bezier@offset@iv}% -} - -\def\pgf@nfold@token@curveto@continue#1#2#3#4#5#6{% - \def\pgf@tmp@tang@i{#5}% - \def\pgf@tmp@tang@ii{#6}% - \pgf@offset@bezier@segment@{#1}{#2}{#3}{#4}{\pgf@nfold@shiftamount}% - \pgfpathcurveto{\pgf@bezier@offset@ii}{\pgf@bezier@offset@iii}{\pgf@bezier@offset@iv}% -} - -\def\pgf@nfold@token@closepath{% - \pgfpathclose% -} - -% This is needed for some edge case explained above. -% #1: segment@start, which is actually the end point of the current segment in the edge case -% #2: the angle of the current segment (start or end does not matter for straight lines) -\def\pgf@nfold@token@edgecase@movetostart#1#2{% - \pgfpathmoveto{\pgfpointadd% - {#1}{\pgfpointpolar{#2+90}{\pgf@nfold@shiftamount}}}% -} - - -\def\pgf@nfold@parse@setupfirst{% - \let\pgf@nfold@next@type=f% - % technically, @visible can be derived from @type, but I think this is more efficient - \let\pgf@nfold@next@visible=0% - \edef\pgf@nfold@next@last{\pgf@x\the\pgf@path@lastx\pgf@y\the\pgf@path@lasty}% - % the following only need to be set if visible=1 - % TODO these are disabled temporarily; an attempt to read them suggests that there - % is a bug, because their content has no meaning at this point. Consider reenabling - % if compile errors show up, but if they do, the root of the problem is likely to be elsewhere - %\let\pgf@nfold@next@tang@i=\pgfpointorigin% - %\let\pgf@nfold@next@tang@ii=\pgfpointorigin% - % \def\pgf@nfold@next@angle@i{0}% - % \def\pgf@nfold@next@angle@ii{0}% - % \let\pgf@nfold@next@first\pgfpointorigin% - % the following only need to be set if type=c - % \let\pgf@nfold@next@supporta\pgfpointorigin% - % \let\pgf@nfold@next@supportb\pgfpointorigin% -} - -\def\pgf@nfold@clampangle{ - % The computed angles are values between 0 and 360, so their difference is between 360 and -360; - % we want the difference to be between -180 and 180 - \ifdim\pgfmathresult pt<-180pt\relax - \pgfutil@tempdima=\pgfmathresult pt - \advance\pgfutil@tempdima by 360pt - \edef\pgfmathresult{\pgf@sys@tonumber\pgfutil@tempdima} - \else\ifdim\pgfmathresult pt>180pt\relax - \pgfutil@tempdima=\pgfmathresult pt - \advance\pgfutil@tempdima by -360pt - \edef\pgfmathresult{\pgf@sys@tonumber\pgfutil@tempdima} - \fi\fi -} - - - -\def\pgf@nfold@parser@moveup{% - \let\pgf@nfold@prev@type\pgf@nfold@cur@type% - \let\pgf@nfold@prev@visible\pgf@nfold@cur@visible% - \let\pgf@nfold@prev@tang@i\pgf@nfold@cur@tang@i% - \let\pgf@nfold@prev@tang@ii\pgf@nfold@cur@tang@ii% - \let\pgf@nfold@prev@angle@i\pgf@nfold@cur@angle@i% - \let\pgf@nfold@prev@angle@ii\pgf@nfold@cur@angle@ii% - \let\pgf@nfold@prev@first\pgf@nfold@cur@first% - \let\pgf@nfold@prev@supporta\pgf@nfold@cur@supporta% - \let\pgf@nfold@prev@supportb\pgf@nfold@cur@supportb% - \let\pgf@nfold@prev@last\pgf@nfold@cur@last% - \let\pgf@nfold@cur@type\pgf@nfold@next@type% - \let\pgf@nfold@cur@visible\pgf@nfold@next@visible% - \let\pgf@nfold@cur@tang@i\pgf@nfold@next@tang@i% - \let\pgf@nfold@cur@tang@ii\pgf@nfold@next@tang@ii% - \let\pgf@nfold@cur@angle@i\pgf@nfold@next@angle@i% - \let\pgf@nfold@cur@angle@ii\pgf@nfold@next@angle@ii - \let\pgf@nfold@cur@first\pgf@nfold@next@first% - \let\pgf@nfold@cur@supporta\pgf@nfold@next@supporta% - \let\pgf@nfold@cur@supportb\pgf@nfold@next@supportb% - \let\pgf@nfold@cur@last\pgf@nfold@next@last% -} - -% -% Iterating over the parsed soft path -% ----------------------------------- -% - -\newcount\pgf@nfold@index -\def\pgf@nfold@run@loop{% - \pgf@nfold@index=\pgf@nfold@order% - \pgf@nfold@run@loop@% -} - -\def\pgf@nfold@run@loop@{% - \pgf@nfold@loop@inner% - \advance\pgf@nfold@index by -1\relax - \ifnum\pgf@nfold@index>0\relax% - \pgf@nfold@run@loop@% - \fi% -} - -\def\pgf@nfold@loop@inner{% - \pgfmathsetmacro{\pgf@nfold@shift@fraction}% - {-1+2*(\pgf@nfold@index-1)/(\pgf@nfold@order-1)}% - % Do not store shiftamount as a length (i.e. with pt) because we want to use it in \pgfqpointscale{}{} - \pgfmathsetmacro{\pgf@nfold@shiftamount}{\pgf@nfold@hwidth*\pgf@nfold@shift@fraction} - % Transformations are already baked into the path; without this call, they would be applied twice - \pgftransformreset% - \parsedpath% - \pgfsyssoftpath@flushcurrentpath% - \pgf@up@action% -} - -% Computes both the width of the component lines into \pgf@x and the distance -% from the center to the outermost line centers into \pgf@y -% from the current values of \pgflinewidth and \pgfinnerlinewidth. -\def\pgf@nfold@compute@widths@from@double{ - \pgf@x=\pgflinewidth\relax% - \pgf@y=\pgf@x\relax% - \advance\pgf@x-\pgfinnerlinewidth\relax% - \advance\pgf@y+\pgfinnerlinewidth\relax% - \pgf@x=.5\pgf@x\relax% - \pgf@y=.25\pgf@y\relax% -} - -\def\pgf@nfold@render@cached@softpath{% - \pgfscope% must use a scope, otherwise we break the arrow tips - % Compute the full and constituent part line widths - \pgf@nfold@compute@widths@from@double% - \pgfsetlinewidth\pgf@x% - \edef\pgf@nfold@hwidth{\the\pgf@y}% - \pgfprocessround{\pgf@nfold@cachedpath}{\pgf@nfold@cachedpath}% remove tokens from the soft path - \pgf@nfold@parsearrows% - \pgf@nfold@parsesoftpath{\pgf@nfold@cachedpath}{\parsedpath}% - \pgf@nfold@run@loop% - \endpgfscope% -} - - -% -% user interface and pgf/TikZ keys -% -------------------------------- -% - -% Outputs a provided soft path in #1 offset by a distance provided in #2. -\def\pgfoffsetpath#1#2{% - \begingroup - \pgfmathsetlengthmacro\pgf@nfold@parsed@hwidth{#2} - % \pgf@nfold@hwidth must always be positive - \pgf@x=\pgf@nfold@parsed@hwidth\relax - \ifdim\pgf@x<0pt\relax - \pgf@x=-\pgf@x - \def\pgf@nfold@shift@fraction{-1} - \else - \def\pgf@nfold@shift@fraction{1} - \fi - \edef\pgf@nfold@parsed@hwidth{\the\pgf@x} - \pgfoffsetpathqfraction{#1}{\pgf@nfold@parsed@hwidth}{\pgf@nfold@shift@fraction} - \endgroup -} - -% Outputs a provided soft path in #1 offset by #3*#2 where #2 is a length (>= 0 pt) -% and #3 is a number between -1.0 and 1.0. This differs from \pgfoffsetpath{#1}{#2*#3} -% in how the joins between segments are rendered. In particular, \pgfoffsetpathfraction{#1}{10pt}{0} -% does *not* yield the original path, but a new path in the centre of #1 drawn at line width 20pt. -% -\def\pgfoffsetpathfraction#1#2#3{% - \begingroup - \pgfmathsetlengthmacro\pgf@nfold@parsed@hwidth{#2} - \pgfmathsetmacro\pgf@nfold@shift@fraction{#3} - \pgfoffsetpathqfraction{#1}{\pgf@nfold@parsed@hwidth}{\pgf@nfold@shift@fraction} - \endgroup -} - -% This has the same output as the #3-th segment of nfold=#4. -\def\pgfoffsetpathindex#1#2#3#4{% - \begingroup - \pgfmathsetmacro\pgf@nfold@shift@fraction{-1+2*(#3-1)/(#4-1)} - \pgfoffsetpathqfraction{#1}{#2}{\pgf@nfold@shift@fraction} - \endgroup -} - -% A quick version that skips processing the input values -\def\pgfoffsetpathqfraction#1#2#3{% - \begingroup - \pgf@x=#2\relax - \edef\pgf@nfold@hwidth{\the\pgf@x} - \edef\pgf@nfold@shift@fraction{#3} - \pgf@x=\pgf@nfold@shift@fraction\pgf@x\relax - \edef\pgf@nfold@shiftamount{\pgf@sys@tonumber\pgf@x} - \pgfprocessround{#1}{\pgf@nfold@cachedpath}% remove tokens from the soft path - \pgf@nfold@parsesoftpath{\pgf@nfold@cachedpath}{\parsedpath}% - % Transformations are already baked into the path; without this call, they would be applied twice - \pgftransformreset% - \parsedpath% - \endgroup -} - - -\pgfkeys{ - /pgf/nfold/.code={% - \pgf@nfold@order=#1\relax% - \ifnum\pgf@nfold@order<1\relax% - \pgfutil@packageerror{tikz-nfold}{The key /pgf/nfold must take a value of at least 1, got \the\pgf@nfold@order}{}% - \fi% - % If nfold > numcached AND intersections is not loaded AND we draw an Implies tip, we get an error. - % We check the first two conditions now and set the respective flag - \ifnum\pgf@nfold@order>\pgf@nfold@intersec@numcached\relax - \ifdefined\pgfintersectionofpaths\else - \pgf@nfold@intersectionsnotloadedtrue - \fi - \fi - }, - /pgf/nfold/.default=2 -} - +\usepgflibrary{nfold} +\usetikzlibrary{arrows.meta} -% use \tikzset for scoping reasons, does not appear to be equivalent to \pgfset{/tikz/...=...} \tikzset{ nfold/.code={ \edef\pgf@tmp{\noexpand\pgfkeys{/pgf/nfold=#1}} - % patch \tikz@double@setup to set /pgf/nfold=#1 as well \expandafter\expandafter\expandafter\def% \expandafter\expandafter\expandafter\tikz@double@setup% \expandafter\expandafter\expandafter{\expandafter\tikz@double@setup\pgf@tmp} }, nfold/.default=2, scaling nfold/.code={% - \pgfscope% scope to contain \tikz@double@setup + \pgfscope% \tikz@double@setup - % extract double distance between line centers into \pgf@x \pgf@nfold@compute@widths@from@double \pgf@y=2\pgf@y - % store (order-1)*\pgf@x in \pgf@xa \c@pgf@counta=#1 \advance\c@pgf@counta by -1\relax \global\pgf@y=\c@pgf@counta\pgf@y @@ -1329,21 +47,16 @@ } }, scaling nfold/.default=2, - % This simply defines the key if tikzcd is not loaded, so we don't run into any errors commutative diagrams/scaling nfold/.code={ - \pgfscope% scope to contain \tikz@double@setup + \pgfscope% \tikz@double@setup - % extract double distance between line centers into \pgf@x \pgf@nfold@compute@widths@from@double - % store (order-1)*\pgf@y in \pgf@ya \c@pgf@counta=#1 \advance\c@pgf@counta by -1\relax \pgf@ya=\c@pgf@counta\pgf@y - % compute the label offset, which is (order-2)*\pgf@y + .5*\pgf@x \advance\c@pgf@counta by -1\relax \pgf@xa=\c@pgf@counta\pgf@y \advance\pgf@xa by .5\pgf@x - % save the results in \pgf@x and \pgf@y \global\pgf@x=\pgf@xa \global\pgf@y=2\pgf@ya \endpgfscope |