diff options
author | Norbert Preining <norbert@preining.info> | 2023-08-31 03:01:22 +0000 |
---|---|---|
committer | Norbert Preining <norbert@preining.info> | 2023-08-31 03:01:22 +0000 |
commit | 7cda3a1cc32bd43dab837e2b73046dab2aeaec98 (patch) | |
tree | 48236f7b604cedb33b9977bcf4960b7dd5313641 /graphics/pgf/contrib/hobby | |
parent | 4fee29360f7566a474b6143951b0744fa151edc9 (diff) |
CTAN sync 202308310301
Diffstat (limited to 'graphics/pgf/contrib/hobby')
-rw-r--r-- | graphics/pgf/contrib/hobby/README (renamed from graphics/pgf/contrib/hobby/README.txt) | 0 | ||||
-rw-r--r-- | graphics/pgf/contrib/hobby/hobby.pdf | bin | 523036 -> 506560 bytes | |||
-rw-r--r-- | graphics/pgf/contrib/hobby/hobby.tex (renamed from graphics/pgf/contrib/hobby/hobby_doc.tex) | 220 | ||||
-rw-r--r-- | graphics/pgf/contrib/hobby/hobby_code.dtx (renamed from graphics/pgf/contrib/hobby/hobby.dtx) | 1162 | ||||
-rw-r--r-- | graphics/pgf/contrib/hobby/hobby_code.pdf | bin | 444339 -> 514512 bytes |
5 files changed, 749 insertions, 633 deletions
diff --git a/graphics/pgf/contrib/hobby/README.txt b/graphics/pgf/contrib/hobby/README index 04af0731d6..04af0731d6 100644 --- a/graphics/pgf/contrib/hobby/README.txt +++ b/graphics/pgf/contrib/hobby/README diff --git a/graphics/pgf/contrib/hobby/hobby.pdf b/graphics/pgf/contrib/hobby/hobby.pdf Binary files differindex 1235aa74c1..7b6065ea02 100644 --- a/graphics/pgf/contrib/hobby/hobby.pdf +++ b/graphics/pgf/contrib/hobby/hobby.pdf diff --git a/graphics/pgf/contrib/hobby/hobby_doc.tex b/graphics/pgf/contrib/hobby/hobby.tex index 6e487bfb18..f116a3d274 100644 --- a/graphics/pgf/contrib/hobby/hobby_doc.tex +++ b/graphics/pgf/contrib/hobby/hobby.tex @@ -1,4 +1,4 @@ -\immediate\write18{tex hobby.dtx} +%\immediate\write18{tex hobby.dtx} \documentclass{ltxdoc} \usepackage[T1]{fontenc} \usepackage{csquotes} @@ -11,8 +11,25 @@ \usepackage{listings} \usepackage{hyperref} \pgfplotsset{compat=1.9} -\lstloadlanguages{[LaTeX]TeX} -\lstset{breakatwhitespace=true,breaklines=true,language=TeX} + +\lstset{ + breakatwhitespace=true, + breaklines=true, + language=[LaTeX]TeX, + basicstyle=\small\ttfamily, + keepspaces=true, + columns=fullflexible +} +% hobby specific keywords (we can't put keywords with spaces :() +\lstset{ + emphstyle={\color{red}}, + emph={and,angle,blank,blanks,closed,controls,curl,curve,designated,disjoint,excess,finish,Hobby,hobby,in,invert,next,out,path,previous,quick,restore,save,shortcut,show,soft,tension,through,use} +} +% tikz keywords used in this documentation +\lstset{ + emphstyle={[2]\color{blue!70!black}}, + emph={[2]addplot,axis,blue,coordinates,distance,double,draw,every,foreach,grid,help,line,lines,plot,postaction,red,rotate,scale smooth,scale,smooth,style,thick,tikz,tikzpicture,to,ultra,white,width,xshift,yellow} +} \EnableCrossrefs \CodelineIndex @@ -25,7 +42,6 @@ \begin{center} \setlength{\parindent}{0pt} \fbox{\begin{minipage}{.9\linewidth} - \lstset{breakatwhitespace=true,breaklines=true,language=TeX,basicstyle=\small} \lstinputlisting[]{example.out} \end{minipage}} \fbox{\begin{minipage}{.9\linewidth} @@ -42,10 +58,10 @@ decoration={ show path construction, curveto code={ - \draw [blue, dashed] + \draw [blue, dashed] (\tikzinputsegmentfirst) -- (\tikzinputsegmentsupporta) node [at end, draw, solid, red, inner sep=2pt]{}; - \draw [blue, dashed] + \draw [blue, dashed] (\tikzinputsegmentsupportb) -- (\tikzinputsegmentlast) node [at start, draw, solid, red, inner sep=2pt]{}; } @@ -111,31 +127,31 @@ Figure~\ref{fig:metapost} compares the implementation with that given by MetaPos \begin{figure} \centering \begin{tikzpicture}[scale=.5] -\draw[scale=.1,postaction=show curve controls,line width=1mm,red] (0,0) -.. controls (26.76463,-1.84543) and (51.4094,14.58441) .. (60,40) -.. controls (67.09875,61.00188) and (59.76253,84.57518) .. (40,90) -.. controls (25.35715,94.01947) and (10.48064,84.5022) .. (10,70) -.. controls (9.62895,58.80421) and (18.80421,49.62895) .. (30,50); -\fill[green] (0,0) circle[radius=2pt] -(6,4) circle[radius=2pt] -(4,9) circle[radius=2pt] -(1,7) circle[radius=2pt] -(3,5) circle[radius=2pt]; -\draw[postaction=show curve controls,thick] (0,0) to[curve through={(6,4) .. (4,9) .. (1,7)}] (3,5); -\begin{scope}[xshift=10cm] -\draw[scale=.1,postaction=show curve controls,line width=1mm,red] (0,0) -.. controls (5.18756,-26.8353) and (60.36073,-18.40036) .. (60,40) -.. controls (59.87714,59.889) and (57.33896,81.64203) .. (40,90) -.. controls (22.39987,98.48387) and (4.72404,84.46368) .. (10,70) -.. controls (13.38637,60.7165) and (26.35591,59.1351) .. (30,50) -.. controls (39.19409,26.95198) and (-4.10555,21.23804) .. (0,0); % -\fill[green] (0,0) circle[radius=2pt] -(6,4) circle[radius=2pt] -(4,9) circle[radius=2pt] -(1,7) circle[radius=2pt] -(3,5) circle[radius=2pt]; -\draw[postaction=show curve controls,thick] (0,0) to[closed,curve through={(6,4) .. (4,9) .. (1,7)}] (3,5); -\end{scope} + \draw[scale=.1,postaction=show curve controls,line width=1mm,red] (0,0) + .. controls (26.76463,-1.84543) and (51.4094,14.58441) .. (60,40) + .. controls (67.09875,61.00188) and (59.76253,84.57518) .. (40,90) + .. controls (25.35715,94.01947) and (10.48064,84.5022) .. (10,70) + .. controls (9.62895,58.80421) and (18.80421,49.62895) .. (30,50); + \fill[green] (0,0) circle[radius=2pt] + (6,4) circle[radius=2pt] + (4,9) circle[radius=2pt] + (1,7) circle[radius=2pt] + (3,5) circle[radius=2pt]; + \draw[postaction=show curve controls,thick] (0,0) to[curve through={(6,4) .. (4,9) .. (1,7)}] (3,5); + \begin{scope}[xshift=10cm] + \draw[scale=.1,postaction=show curve controls,line width=1mm,red] (0,0) + .. controls (5.18756,-26.8353) and (60.36073,-18.40036) .. (60,40) + .. controls (59.87714,59.889) and (57.33896,81.64203) .. (40,90) + .. controls (22.39987,98.48387) and (4.72404,84.46368) .. (10,70) + .. controls (13.38637,60.7165) and (26.35591,59.1351) .. (30,50) + .. controls (39.19409,26.95198) and (-4.10555,21.23804) .. (0,0); % + \fill[green] (0,0) circle[radius=2pt] + (6,4) circle[radius=2pt] + (4,9) circle[radius=2pt] + (1,7) circle[radius=2pt] + (3,5) circle[radius=2pt]; + \draw[postaction=show curve controls,thick] (0,0) to[closed,curve through={(6,4) .. (4,9) .. (1,7)}] (3,5); + \end{scope} \end{tikzpicture} \caption{Hobby's algorithm in TikZ overlaying the output of MetaPost} \label{fig:metapost} @@ -150,7 +166,7 @@ It can be loaded with \textbf{Warning}: This package makes extensive use of \LaTeX3. On occasion, updates to \LaTeX3 packages have resulted in this package behaving oddly or not working at all. -The most up to date version of this package can be obtained from the \href{http://bazaar.launchpad.net/~tex-sx/tex-sx/development/files}{TeX-SX Launchpad page} (download \Verb+hobby.dtx+ and run \Verb+tex hobby.dtx+ to generate the files). +The most up to date version of this package can be obtained from my \href{https://github.org/loopspace/hobby}{github page} (download \Verb+hobby.dtx+ and run \Verb+tex hobby.dtx+ to generate the files). Often, such issues are reported on the \href{http://tex.stackexchange.com}{TeX-SX} site and workarounds quickly found so it is worth checking there as well. \bigskip @@ -166,13 +182,13 @@ However, note that the two methods are not completely synonymous due to how one \begin{example} \begin{tikzpicture}[scale=.5] -\draw (0,0) to[curve through={(6,4) .. (4,9) .. (1,7)}] (3,5); + \draw (0,0) to[curve through={(6,4) .. (4,9) .. (1,7)}] (3,5); \end{tikzpicture} \end{example} \begin{example} \begin{tikzpicture}[scale=.5] -\draw (0,0) to[curve through={(6,4) (4,9) (1,7)}] (3,5); + \draw (0,0) to[curve through={(6,4) (4,9) (1,7)}] (3,5); \end{tikzpicture} \end{example} @@ -181,7 +197,7 @@ Again, the dots are optional. \begin{example} \begin{tikzpicture}[scale=.5] -\draw (0,0) to[quick curve through={(6,4) .. (4,9) .. (1,7)}] (3,5); + \draw (0,0) to[quick curve through={(6,4) .. (4,9) .. (1,7)}] (3,5); \end{tikzpicture} \end{example} @@ -194,13 +210,13 @@ As a later version of TikZ may assign some action to that syntax, this package m \begin{example} \begin{tikzpicture}[scale=.5,use Hobby shortcut] -\draw (-3,0) -- (0,0) .. (6,4) .. (4,9) .. (1,7) .. (3,5) -- ++(2,0); + \draw (-3,0) -- (0,0) .. (6,4) .. (4,9) .. (1,7) .. (3,5) -- ++(2,0); \end{tikzpicture} \end{example} \begin{example} \begin{tikzpicture}[scale=.5,use quick Hobby shortcut] -\draw (-3,0) -- (0,0) .. (6,4) .. (4,9) .. (1,7) .. (3,5) -- ++(2,0); + \draw (-3,0) -- (0,0) .. (6,4) .. (4,9) .. (1,7) .. (3,5) -- ++(2,0); \end{tikzpicture} \end{example} @@ -211,13 +227,13 @@ This library registers three plot handlers: \Verb+hobby+, \Verb+closed hobby+, a The first is an open curve through the points using the full algorithm, the second is a closed curve, and the third uses the quick algorithm (and is thus an open curve). \begin{example} -\tikz[smooth] \draw plot coordinates {(0,0) (1,1) (2,0) (3,1) (2,1) (10:2cm)}; + \tikz[smooth] \draw plot coordinates {(0,0) (1,1) (2,0) (3,1) (2,1) (10:2cm)}; -\tikz[hobby] \draw plot coordinates {(0,0) (1,1) (2,0) (3,1) (2,1) (10:2cm)}; + \tikz[hobby] \draw plot coordinates {(0,0) (1,1) (2,0) (3,1) (2,1) (10:2cm)}; -\tikz[closed hobby] \draw plot coordinates {(0,0) (1,1) (2,0) (3,1) (2,1) (10:2cm)}; + \tikz[closed hobby] \draw plot coordinates {(0,0) (1,1) (2,0) (3,1) (2,1) (10:2cm)}; -\tikz[quick hobby] \draw plot coordinates {(0,0) (1,1) (2,0) (3,1) (2,1) (10:2cm)}; + \tikz[quick hobby] \draw plot coordinates {(0,0) (1,1) (2,0) (3,1) (2,1) (10:2cm)}; \end{example} This has the side effect that these can be used with the \Verb+pgfplots+ package. @@ -225,10 +241,10 @@ However, the Hobby algorithm is designed to draw a curve in 2D-{}space and does \begin{example} \begin{tikzpicture} -\begin{axis} -\addplot +[smooth] {rnd}; -\addplot +[hobby] {rnd}; -\end{axis} + \begin{axis} + \addplot +[smooth] {rnd}; + \addplot +[hobby] {rnd}; + \end{axis} \end{tikzpicture} \end{example} @@ -253,14 +269,14 @@ This applies the algorithm to the set of specified points and adds it to the cur \begin{example} \begin{tikzpicture} -\pgfpathmoveto{\pgfpoint{0}{0}} -\pgfpathlineto{\pgfpoint{1cm}{0}} -\pgfpathhobby{closed=true} -\pgfpathhobbypt{\pgfpoint{1cm}{2cm}}{tension in=2} -\pgfpathhobbypt{\pgfpoint{2cm}{1cm}} -\pgfpathhobbypt{\pgfpoint{3cm}{0cm}} -\pgfpathhobbyend -\pgfusepath{stroke} + \pgfpathmoveto{\pgfpoint{0}{0}} + \pgfpathlineto{\pgfpoint{1cm}{0}} + \pgfpathhobby{closed=true} + \pgfpathhobbypt{\pgfpoint{1cm}{2cm}}{tension in=2} + \pgfpathhobbypt{\pgfpoint{2cm}{1cm}} + \pgfpathhobbypt{\pgfpoint{3cm}{0cm}} + \pgfpathhobbyend + \pgfusepath{stroke} \end{tikzpicture} \end{example} @@ -287,10 +303,8 @@ Let us start with the customisations to the algorithm. \item Basic curve. \begin{example} \begin{tikzpicture} -\draw[postaction=show curve controls] -(0,0) to[curve through={(1,.5) .. (2,0) .. (3,.5)}] (4,0); -\draw[xshift=5cm,use Hobby shortcut,postaction=show curve controls] -(0,0) .. (1,.5) .. (2,0) .. (3,.5) .. (4,0); + \draw[postaction=show curve controls] (0,0) to[curve through={(1,.5) .. (2,0) .. (3,.5)}] (4,0); + \draw[xshift=5cm,use Hobby shortcut,postaction=show curve controls] (0,0) .. (1,.5) .. (2,0) .. (3,.5) .. (4,0); \end{tikzpicture} \end{example} @@ -298,10 +312,8 @@ Let us start with the customisations to the algorithm. %% \begin{example} \begin{tikzpicture}[scale=.5] -\draw[postaction=show curve controls] -(0,0) to[closed,curve through={(1,.5) .. (2,0) .. (3,.5)}] (4,0); -\draw[xshift=5cm,use Hobby shortcut,postaction=show curve controls] -([closed]0,0) .. (1,.5) .. (2,0) .. (3,.5) .. (4,0); + \draw[postaction=show curve controls] (0,0) to[closed,curve through={(1,.5) .. (2,0) .. (3,.5)}] (4,0); + \draw[xshift=5cm,use Hobby shortcut,postaction=show curve controls] ([closed]0,0) .. (1,.5) .. (2,0) .. (3,.5) .. (4,0); \end{tikzpicture} \end{example} @@ -309,38 +321,31 @@ Let us start with the customisations to the algorithm. The angles given are absolute. \begin{example} \begin{tikzpicture} -\draw[postaction=show curve controls] -(0,0) to[out angle=0,in angle=180,curve through={(1,.5) .. (2,0) .. (3,.5)}] (4,0); -\draw[xshift=5cm,use Hobby shortcut,postaction=show curve controls] -([out angle=0,in angle=180]0,0) .. (1,.5) .. (2,0) .. (3,.5) .. (4,0); + \draw[postaction=show curve controls] (0,0) to[out angle=0,in angle=180,curve through={(1,.5) .. (2,0) .. (3,.5)}] (4,0); + \draw[xshift=5cm,use Hobby shortcut,postaction=show curve controls] ([out angle=0,in angle=180]0,0) .. (1,.5) .. (2,0) .. (3,.5) .. (4,0); \end{tikzpicture} \end{example} \item Applying tension as the curve comes in to a point. \begin{example} \begin{tikzpicture} -\draw[postaction=show curve controls] -(0,0) to[curve through={(1,.5) .. ([tension in=2]2,0) .. (3,.5)}] (4,0); -\draw[xshift=5cm,use Hobby shortcut,postaction=show curve controls] -(0,0) .. (1,.5) .. ([tension in=2]2,0) .. (3,.5) .. (4,0); + \draw[postaction=show curve controls] (0,0) to[curve through={(1,.5) .. ([tension in=2]2,0) .. (3,.5)}] (4,0); + \draw[xshift=5cm,use Hobby shortcut,postaction=show curve controls] (0,0) .. (1,.5) .. ([tension in=2]2,0) .. (3,.5) .. (4,0); \end{tikzpicture} \end{example} \item Applying the same tension as a curve comes in and goes out of a point. \begin{example} \begin{tikzpicture} -\draw[postaction=show curve controls] -(0,0) to[curve through={(1,.5) .. ([tension=2]2,0) .. (3,.5)}] (4,0); + \draw[postaction=show curve controls] (0,0) to[curve through={(1,.5) .. ([tension=2]2,0) .. (3,.5)}] (4,0); \end{tikzpicture} \end{example} \item Specifying the \emph{curl} parameters. \begin{example} \begin{tikzpicture} -\draw[postaction=show curve controls] -(0,0) to[in curl=.1,out curl=3,curve through={(1,.5) .. (2,0) .. (3,.5)}] (4,0); -\draw[xshift=5cm,use Hobby shortcut,postaction=show curve controls] -(0,0) .. ([in curl=.1,out curl=3]1,.5) .. (2,0) .. (3,.5) .. (4,0); + \draw[postaction=show curve controls] (0,0) to[in curl=.1,out curl=3,curve through={(1,.5) .. (2,0) .. (3,.5)}] (4,0); + \draw[xshift=5cm,use Hobby shortcut,postaction=show curve controls] (0,0) .. ([in curl=.1,out curl=3]1,.5) .. (2,0) .. (3,.5) .. (4,0); \end{tikzpicture} \end{example} \end{itemize} @@ -354,9 +359,9 @@ By nudging the repeated point slightly, the behaviour changes drastically. \begin{example} \begin{tikzpicture}[use Hobby shortcut] -\draw (0,0) .. (1,0) .. (0,0) .. (0,-1); -\draw[xshift=2cm] (0,0) .. (1,0) .. (0,0.1) .. (0,-1); -\draw[xshift=4cm] (0,0) .. (1,0) .. (0,-0.1) .. (0,-1); + \draw (0,0) .. (1,0) .. (0,0) .. (0,-1); + \draw[xshift=2cm] (0,0) .. (1,0) .. (0,0.1) .. (0,-1); + \draw[xshift=4cm] (0,0) .. (1,0) .. (0,-0.1) .. (0,-1); \end{tikzpicture} \end{example} @@ -367,9 +372,9 @@ It is best to nudge it in the direction most normal to the line between the spec An alternative solution is to add an additional point for the curve to go through. \begin{example} \begin{tikzpicture}[use Hobby shortcut] -\draw (0,0) .. (1,0) .. (0,0) .. (0,-1); -\draw[xshift=2cm] (0,0) .. (1,0) .. (0,0.002) .. (0,-1); -\draw[xshift=4cm] (0,0) .. (1,0) .. (0,-0.002) .. (0,-1); + \draw (0,0) .. (1,0) .. (0,0) .. (0,-1); + \draw[xshift=2cm] (0,0) .. (1,0) .. (0,0.002) .. (0,-1); + \draw[xshift=4cm] (0,0) .. (1,0) .. (0,-0.002) .. (0,-1); \end{tikzpicture} \end{example} @@ -377,9 +382,9 @@ Lastly, it is possible to add an \Verb+excess angle+ key to a coordinate. This will add the corresponding multiple of \(2\pi\) to the angle difference. \begin{example} \begin{tikzpicture}[use Hobby shortcut] -\draw (0,0) .. (1,0) .. (0,0) .. (0,-1); -\draw[xshift=2cm] (0,0) .. ([excess angle=1]1,0) .. (0,0) .. (0,-1); -\draw[xshift=4cm] (0,0) .. ([excess angle=-1]1,0) .. (0,0) .. (0,-1); + \draw (0,0) .. (1,0) .. (0,0) .. (0,-1); + \draw[xshift=2cm] (0,0) .. ([excess angle=1]1,0) .. (0,0) .. (0,-1); + \draw[xshift=4cm] (0,0) .. ([excess angle=-1]1,0) .. (0,0) .. (0,-1); \end{tikzpicture} \end{example} @@ -393,8 +398,8 @@ The implementation allows for this by separating the generation of the path from \begin{example} \begin{tikzpicture} -\draw[line width=3mm,red,use Hobby shortcut,save Hobby path={saved}] (0,0) .. (1,1) .. (2,0); -\draw[xshift=2cm,ultra thick,yellow] (0,0) [restore and use Hobby path={saved}{}]; + \draw[line width=3mm,red,use Hobby shortcut,save Hobby path={saved}] (0,0) .. (1,1) .. (2,0); + \draw[xshift=2cm,ultra thick,yellow] (0,0) [restore and use Hobby path={saved}{}]; \end{tikzpicture} \end{example} % @@ -406,8 +411,8 @@ An alternative would be to use the key \Verb+disjoint+ which does add an initial \begin{example} \begin{tikzpicture} -\draw[line width=3mm,red,use Hobby shortcut,save Hobby path={saved}] (0,0) .. (1,1) .. (2,0); -\draw[xshift=2cm,ultra thick,yellow,restore and use Hobby path={saved}{disjoint}]; + \draw[line width=3mm,red,use Hobby shortcut,save Hobby path={saved}] (0,0) .. (1,1) .. (2,0); + \draw[xshift=2cm,ultra thick,yellow,restore and use Hobby path={saved}{disjoint}]; \end{tikzpicture} \end{example} % @@ -422,10 +427,9 @@ Only a \Verb+soft+ blank will be reversed in these circumstances. \begin{example} \begin{tikzpicture}[use Hobby shortcut,line width=1mm,rotate=90] -\draw[blue,save Hobby path={left}] - ([out angle=90,in angle=-90]1,0) .. (1,1) .. ([blank=soft]0,2) .. (1,3) .. (1,4); -\draw[red] ([out angle=90,in angle=-90]0,0) .. (0,1) .. (1,2) .. (0,3) .. (0,4); -\draw[blue,restore and use Hobby path={left}{disjoint,invert soft blanks}]; + \draw[blue,save Hobby path={left}] ([out angle=90,in angle=-90]1,0) .. (1,1) .. ([blank=soft]0,2) .. (1,3) .. (1,4); + \draw[red] ([out angle=90,in angle=-90]0,0) .. (0,1) .. (1,2) .. (0,3) .. (0,4); + \draw[blue,restore and use Hobby path={left}{disjoint,invert soft blanks}]; \end{tikzpicture} \end{example} % @@ -487,8 +491,8 @@ Non-{}soft-{}blank segments are still not drawn. \begin{example} \begin{tikzpicture}[use Hobby shortcut] -\draw (0,0) .. (1,1) .. ([blank=soft]2,0) .. (3,1) .. ([blank]4,0) .. (5,1); -\draw[red,use previous Hobby path={invert soft blanks,disjoint}]; + \draw (0,0) .. (1,1) .. ([blank=soft]2,0) .. (3,1) .. ([blank]4,0) .. (5,1); + \draw[red,use previous Hobby path={invert soft blanks,disjoint}]; \end{tikzpicture} \end{example} % @@ -505,9 +509,8 @@ As a more practical application, consider the following rendering of a trefoil k double distance=.5mm } ] -\draw ([closed]0,2) .. ([blank=soft]210:.5) .. (-30:2) .. -([blank=soft]0,.5) .. (210:2) .. ([blank=soft]-30:.5); -\draw[use previous Hobby path={invert soft blanks,disjoint}]; + \draw ([closed]0,2) .. ([blank=soft]210:.5) .. (-30:2) .. ([blank=soft]0,.5) .. (210:2) .. ([blank=soft]-30:.5); + \draw[use previous Hobby path={invert soft blanks,disjoint}]; \end{tikzpicture} \end{example} % @@ -525,11 +528,11 @@ This could easily be generalised using the \Verb+\foreach+ command, as demonstra } ] \def\nfoil{9} -\draw ([closed]0,2) -\foreach \k in {1,...,\nfoil} { - .. ([blank=soft]90+360*\k/\nfoil-180/\nfoil:-.5) .. (90+360*\k/\nfoil:2) -}; -\draw[use previous Hobby path={invert soft blanks,disjoint}]; + \draw ([closed]0,2) + foreach \k in {1,...,\nfoil}{ + .. ([blank=soft]90+360*\k/\nfoil-180/\nfoil:-.5) .. (90+360*\k/\nfoil:2) + }; + \draw[use previous Hobby path={invert soft blanks,disjoint}]; \end{tikzpicture} \end{example} % @@ -548,7 +551,7 @@ However, Hobby's formulae for the lengths of the control points is still being u \begin{example} \begin{tikzpicture}[ - use Hobby shortcut, + use Hobby shortcut, tangent/.style={% in angle={(180+#1)}, Hobby finish, @@ -556,10 +559,9 @@ However, Hobby's formulae for the lengths of the control points is still being u out angle=#1, }, ] -\draw[help lines] (-5,-5) grid (5,5); -\draw (-5,0) -- (5,0) (0,-5) -- (0,5); -\draw[thick] (-5,2) .. ([tangent=0]-3,3) .. (-1,1) .. (0,-1.3) .. % -([tangent=0]1,-2) .. ([tangent=45]2,-1.5) .. ([tangent=0]3,-2) .. (5,-4); + \draw[help lines] (-5,-5) grid (5,5); + \draw (-5,0) -- (5,0) (0,-5) -- (0,5); + \draw[thick] (-5,2) .. ([tangent=0]-3,3) .. (-1,1) .. (0,-1.3) .. ([tangent=0]1,-2) .. ([tangent=45]2,-1.5) .. ([tangent=0]3,-2) .. (5,-4); \end{tikzpicture} \end{example} % @@ -672,7 +674,7 @@ Using \(\phi_1 = - \psi_1 - \theta_1\), the first rearranges to: %% The second should be substituted in to the general equation with \(i = n-1\). This yields: -%% +%% \begin{align*} d_{n-1} \overline{\tau}_{n} \overline{\tau}_{n-1}^2 &\theta_{n-2} \\ {}+ @@ -861,7 +863,7 @@ which we can row reduce to: \[ \begin{bmatrix} 1 & 1 \\ -0 & d_1 + d_0 +0 & d_1 + d_0 \end{bmatrix} \Theta = -\psi_1 \begin{bmatrix} 1 \\ d_1 diff --git a/graphics/pgf/contrib/hobby/hobby.dtx b/graphics/pgf/contrib/hobby/hobby_code.dtx index d555a5b2f3..03eb60574c 100644 --- a/graphics/pgf/contrib/hobby/hobby.dtx +++ b/graphics/pgf/contrib/hobby/hobby_code.dtx @@ -41,7 +41,7 @@ See http://www.latex-project.org/lppl.txt \endpreamble \postamble -Copyright (C) 2012 by Andrew Stacey <loopspace@mathforge.org> +Copyright (C) 2012-2021 by Andrew Stacey <loopspace@mathforge.org> This file may be distributed and/or modified under the conditions of the LaTeX Project Public License, either version 1.3 of this @@ -62,6 +62,7 @@ and the derived files hobby.code.tex pgflibraryhobby.code.tex tikzlibraryhobby.code.tex pml3array.sty + hobby-l3draw.sty hobby.ins hobby.pdf hobby_code.pdf @@ -71,10 +72,9 @@ and the derived files hobby.code.tex \usedir{tex/latex/hobby} \generate{\file{tikzlibraryhobby.code.tex} {\from{hobby.dtx}{tikzlibrary}}} \generate{\file{pgflibraryhobby.code.tex} {\from{hobby.dtx}{pgflibrary}}} -\generate{\file{hobby.code.tex} -{\from{hobby.dtx}{hobby}}} -\generate{\file{pml3array.sty} -{\from{hobby.dtx}{array}}} +\generate{\file{hobby.code.tex} {\from{hobby.dtx}{hobby}}} +\generate{\file{pml3array.sty} {\from{hobby.dtx}{array}}} +\generate{\file{hobby-l3draw.sty} {\from{hobby.dtx}{l3hobby}}} %</install> %<install>\endbatchfile %<*internal> @@ -111,7 +111,7 @@ and the derived files hobby.code.tex %</driver> % \fi % -% \CheckSum{3382} +% \CheckSum{3427} % % \CharacterTable % {Upper-case \A\B\C\D\E\F\G\H\I\J\K\L\M\N\O\P\Q\R\S\T\U\V\W\X\Y\Z @@ -151,8 +151,6 @@ and the derived files hobby.code.tex % % We use \LaTeX3 syntax so need to load the requisite packages % \begin{macrocode} -\RequirePackage{expl3} -\RequirePackage{xparse} \RequirePackage{pml3array} \ExplSyntaxOn % \end{macrocode} @@ -167,7 +165,7 @@ and the derived files hobby.code.tex % % We declare all our variables. % -% Start with version and date, together with a check to see if we've been loaded twice (fail gracefully if so). +% Start with version and date, together with a check to see if we've been loaded twice (fail gracefully if so). % % \begin{macrocode} \tl_clear:N \l_tmpa_tl @@ -183,8 +181,8 @@ and the derived files hobby.code.tex \tl_new:N \g__hobby_version \tl_new:N \g__hobby_date -\tl_set:Nn \g__hobby_version {1.8} -\tl_set:Nn \g__hobby_date {2017-06-01} +\tl_gset:Nn \g__hobby_version {1.10} +\tl_gset:Nn \g__hobby_date {2023-08-30} \DeclareDocumentCommand \hobbyVersion {} { \tl_use:N \g__hobby_version @@ -234,186 +232,186 @@ and the derived files hobby.code.tex % \end{macrocode} % \end{macro} % -% \begin{macro}{\l_hobby_points_array} -% \Verb+\l_hobby_points_array+ is an array holding the specified points on the path. -% In the \LaTeX3 code, a ``point'' is a token list of the form \Verb+x = <number>, y = <number>+. +% \begin{macro}{\g__hobby_points_array} +% \Verb+\g__hobby_points_array+ is an array holding the specified points on the path. +% In the \LaTeX3 code, a ``point'' is a token list of the form \Verb+<number>, <number>+. % This gives us the greatest flexibility in passing points back and forth between the \LaTeX3 code and any calling code. % The array is indexed by integers beginning with \(0\). % In the documentation, we will use the notation \(z_k\) to refer to the \(k\)th point. % \begin{macrocode} -\array_new:N \l_hobby_points_array +\array_new:N \g__hobby_points_array % \end{macrocode} % \end{macro} % -% \begin{macro}{\l_hobby_points_x_array} -% \Verb+\l_hobby_points_x_array+ is an array holding the \(x\)--{}coordinates of the specified points. +% \begin{macro}{\g__hobby_points_x_array} +% \Verb+\g__hobby_points_x_array+ is an array holding the \(x\)--{}coordinates of the specified points. % \begin{macrocode} -\array_new:N \l_hobby_points_x_array +\array_new:N \g__hobby_points_x_array % \end{macrocode} % \end{macro} % % \begin{macro}{\l_hobby_points_y_array} -% \Verb+\l_hobby_points_y_array+ is an array holding the \(y\)--{}coordinates of the specified points. +% \Verb+\g__hobby_points_y_array+ is an array holding the \(y\)--{}coordinates of the specified points. % \begin{macrocode} -\array_new:N \l_hobby_points_y_array +\array_new:N \g__hobby_points_y_array % \end{macrocode} % \end{macro} % -% \begin{macro}{\l_hobby_actions_array} -% \Verb+\l_hobby_actions_array+ is an array holding the (encoded) action to be taken out on the segment of the path ending at that point. +% \begin{macro}{\g__hobby_actions_array} +% \Verb+\g__hobby_actions_array+ is an array holding the (encoded) action to be taken out on the segment of the path ending at that point. % \begin{macrocode} -\array_new:N \l_hobby_actions_array +\array_new:N \g__hobby_actions_array % \end{macrocode} % \end{macro} % -% \begin{macro}{\l_hobby_angles_array} -% \Verb+\l_hobby_angles_array+ is an array holding the angles of the lines between the points. +% \begin{macro}{\g__hobby_angles_array} +% \Verb+\g__hobby_angles_array+ is an array holding the angles of the lines between the points. % Specifically, the angle indexed by \(k\) is the angle in radians of the line from \(z_k\) to \(z_{k+1}\). % \begin{macrocode} -\array_new:N \l_hobby_angles_array +\array_new:N \g__hobby_angles_array % \end{macrocode} % \end{macro} % -% \begin{macro}{\l_hobby_distances_array} -% \Verb+\l_hobby_distances_array+ is an array holding the distances between the points. +% \begin{macro}{\g__hobby_distances_array} +% \Verb+\g__hobby_distances_array+ is an array holding the distances between the points. % Specifically, the distance indexed by \(k\), which we will write as \(d_k\), is the length of the line from \(z_k\) to \(z_{k+1}\). % \begin{macrocode} -\array_new:N \l_hobby_distances_array +\array_new:N \g__hobby_distances_array % \end{macrocode} % \end{macro} % -% \begin{macro}{\l_hobby_tension_out_array} -% \Verb+\l_hobby_tension_out_array+ is an array holding the tension for the path as it leaves each point. +% \begin{macro}{\g__hobby_tension_out_array} +% \Verb+\g__hobby_tension_out_array+ is an array holding the tension for the path as it leaves each point. % This is a parameter that controls how much the curve ``flexes'' as it leaves the point. % In the following, this will be written \(\tau_k\). % \begin{macrocode} -\array_new:N \l_hobby_tension_out_array +\array_new:N \g__hobby_tension_out_array % \end{macrocode} % \end{macro} % -% \begin{macro}{\l_hobby_tension_in_array} -% \Verb+\l_hobby_tension_in_array+ is an array holding the tension for the path as it arrives at each point. +% \begin{macro}{\g__hobby_tension_in_array} +% \Verb+\g__hobby_tension_in_array+ is an array holding the tension for the path as it arrives at each point. % This is a parameter that controls how much the curve ``flexes'' as it gets to the point. % In the following, this will be written \(\overline{\tau}_k\). % \begin{macrocode} -\array_new:N \l_hobby_tension_in_array +\array_new:N \g__hobby_tension_in_array % \end{macrocode} % \end{macro} % -% \begin{macro}{\l_hobby_matrix_a_array} -% \Verb+\l_hobby_matrix_a_array+ is an array holding the subdiagonal of the linear system that has to be solved to find the angles of the control points. +% \begin{macro}{\g__hobby_matrix_a_array} +% \Verb+\g__hobby_matrix_a_array+ is an array holding the subdiagonal of the linear system that has to be solved to find the angles of the control points. % In the following, this will be denoted by \(A_i\). % The first index is \(1\). % \begin{macrocode} -\array_new:N \l_hobby_matrix_a_array +\array_new:N \g__hobby_matrix_a_array % \end{macrocode} % \end{macro} % -% \begin{macro}{\l_hobby_matrix_b_array} -% \Verb+\l_hobby_matrix_b_array+ is an array holding the diagonal of the linear system that has to be solved to find the angles of the control points. +% \begin{macro}{\g__hobby_matrix_b_array} +% \Verb+\g__hobby_matrix_b_array+ is an array holding the diagonal of the linear system that has to be solved to find the angles of the control points. % In the following, this will be denoted by \(B_i\). % The first index is \(0\). % \begin{macrocode} -\array_new:N \l_hobby_matrix_b_array +\array_new:N \g__hobby_matrix_b_array % \end{macrocode} % \end{macro} % -% \begin{macro}{\l_hobby_matrix_c_array} -% \Verb+\l_hobby_matrix_c_array+ is an array holding the superdiagonal of the linear system that has to be solved to find the angles of the control points. +% \begin{macro}{\g__hobby_matrix_c_array} +% \Verb+\g__hobby_matrix_c_array+ is an array holding the superdiagonal of the linear system that has to be solved to find the angles of the control points. % In the following, this will be denoted by \(C_i\). % The first index is \(0\). % \begin{macrocode} -\array_new:N \l_hobby_matrix_c_array +\array_new:N \g__hobby_matrix_c_array % \end{macrocode} % \end{macro} % -% \begin{macro}{\l_hobby_matrix_d_array} -% \Verb+\l_hobby_matrix_d_array+ is an array holding the target vector of the linear system that has to be solved to find the angles of the control points. +% \begin{macro}{\g__hobby_matrix_d_array} +% \Verb+\g__hobby_matrix_d_array+ is an array holding the target vector of the linear system that has to be solved to find the angles of the control points. % In the following, this will be denoted by \(D_i\). % The first index is \(1\). % \begin{macrocode} -\array_new:N \l_hobby_matrix_d_array +\array_new:N \g__hobby_matrix_d_array % \end{macrocode} % \end{macro} % -% \begin{macro}{\l_hobby_vector_u_array} -% \Verb+\l_hobby_vector_u_array+ is an array holding the perturbation of the linear system for closed paths. +% \begin{macro}{\g__hobby_vector_u_array} +% \Verb+\g__hobby_vector_u_array+ is an array holding the perturbation of the linear system for closed paths. % The coefficient matrix for an \emph{open} path is tridiagonal and that means that Gaussian elimination runs faster than expected (\(O(n)\) instead of \(O(n^3)\)). % The matrix for a closed path is not tridiagonal but is not far off. % It can be solved by perturbing it to a tridiagonal matrix and then modifying the result. -% This array represents a utility vector in that perturbation. +% This array represents a utility vector in that perturbation. % In the following, the vector will be denoted by \(u\). % The first index is \(1\). % \begin{macrocode} -\array_new:N \l_hobby_vector_u_array +\array_new:N \g__hobby_vector_u_array % \end{macrocode} % \end{macro} % -% \begin{macro}{\l_hobby_excess_angle_array} -% \Verb+\l_hobby_excess_angle_array+ is an array that allows the user to say that the algorithm should add a multiple of \(2 \pi\) to the angle differences. +% \begin{macro}{\g__hobby_excess_angle_array} +% \Verb+\g__hobby_excess_angle_array+ is an array that allows the user to say that the algorithm should add a multiple of \(2 \pi\) to the angle differences. % This is because these angles are wrapped to the interval \((-\pi,\pi]\) but the wrapping might go wrong near the end points due to computation accuracy. % The first index is \(1\). % \begin{macrocode} -\array_new:N \l_hobby_excess_angle_array +\array_new:N \g__hobby_excess_angle_array % \end{macrocode} % \end{macro} % -% \begin{macro}{\l_hobby_psi_array} -% \Verb+\l_hobby_psi_array+ is an array holding the difference of the angles of the lines entering and exiting a point. +% \begin{macro}{\g__hobby_psi_array} +% \Verb+\g__hobby_psi_array+ is an array holding the difference of the angles of the lines entering and exiting a point. % That is, \(\psi_k\) is the angle between the lines joining \(z_k\) to \(z_{k-1}\) and \(z_{k+1}\). % The first index is \(1\). % \begin{macrocode} -\array_new:N \l_hobby_psi_array +\array_new:N \g__hobby_psi_array % \end{macrocode} % \end{macro} % -% \begin{macro}{\l_hobby_theta_array} -% \Verb+\l_hobby_theta_array+ is an array holding the angles of the outgoing control points for the generated path. +% \begin{macro}{\g__hobby_theta_array} +% \Verb+\g__hobby_theta_array+ is an array holding the angles of the outgoing control points for the generated path. % These are measured relative to the line joining the point to the next point on the path. % The first index is \(0\). % \begin{macrocode} -\array_new:N \l_hobby_theta_array +\array_new:N \g__hobby_theta_array % \end{macrocode} % \end{macro} % -% \begin{macro}{\l_hobby_phi_array} -% \Verb+\l_hobby_phi_array+ is an array holding the angles of the incoming control points for the generated path. +% \begin{macro}{\g__hobby_phi_array} +% \Verb+\g__hobby_phi_array+ is an array holding the angles of the incoming control points for the generated path. % These are measured relative to the line joining the point to the previous point on the path. % The first index is \(1\). % \begin{macrocode} -\array_new:N \l_hobby_phi_array +\array_new:N \g__hobby_phi_array % \end{macrocode} % \end{macro} % -% \begin{macro}{\l_hobby_sigma_array} -% \Verb+\l_hobby_sigma_array+ is an array holding the lengths of the outgoing control points for the generated path. +% \begin{macro}{\g__hobby_sigma_array} +% \Verb+\g__hobby_sigma_array+ is an array holding the lengths of the outgoing control points for the generated path. % The units are such that the length of the line to the next specified point is one unit. % \begin{macrocode} -\array_new:N \l_hobby_sigma_array +\array_new:N \g__hobby_sigma_array % \end{macrocode} % \end{macro} % -% \begin{macro}{\l_hobby_rho_array} -% \Verb+\l_hobby_rho_array+ is an array holding the lengths of the incoming control points for the generated path. +% \begin{macro}{\g__hobby_rho_array} +% \Verb+\g__hobby_rho_array+ is an array holding the lengths of the incoming control points for the generated path. % The units are such that the length of the line to the previous specified point is one unit. % \begin{macrocode} -\array_new:N \l_hobby_rho_array +\array_new:N \g__hobby_rho_array % \end{macrocode} % \end{macro} % -% \begin{macro}{\l_hobby_controla_array} -% \Verb+\l_hobby_controla_array+ is an array holding the coordinates of the first control points on the curves. -% The format is the same as for \Verb+\l_hobby_points_array+. +% \begin{macro}{\g__hobby_controla_array} +% \Verb+\g__hobby_controla_array+ is an array holding the coordinates of the first control points on the curves. +% The format is the same as for \Verb+\g__hobby_points_array+. % \begin{macrocode} -\array_new:N \l_hobby_controla_array +\array_new:N \g__hobby_controla_array % \end{macrocode} % \end{macro} % -% \begin{macro}{\l_hobby_controlb_array} -% \Verb+\l_hobby_controlb_array+ is an array holding the coordinates of the second control points on the curves. -% The format is the same as for \Verb+\l_hobby_points_array+. +% \begin{macro}{\g__hobby_controlb_array} +% \Verb+\g__hobby_controlb_array+ is an array holding the coordinates of the second control points on the curves. +% The format is the same as for \Verb+\g__hobby_points_array+. % \begin{macrocode} -\array_new:N \l_hobby_controlb_array +\array_new:N \g__hobby_controlb_array % \end{macrocode} % \end{macro} % @@ -425,6 +423,20 @@ and the derived files hobby.code.tex % \end{macrocode} % \end{macro} % +% \begin{macro}{\l_hobby_tempa_tl} +% \Verb+\l_hobby_tempa_tl+ is a temporary variable of type \Verb+tl+. +% \begin{macrocode} +\fp_new:N \l_hobby_tempa_tl +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\l_hobby_tempb_tl} +% \Verb+\l_hobby_tempb_tl+ is a temporary variable of type \Verb+tl+. +% \begin{macrocode} +\fp_new:N \l_hobby_tempb_tl +% \end{macrocode} +% \end{macro} +% % \begin{macro}{\l_hobby_tempa_fp} % \Verb+\l_hobby_tempa_fp+ is a temporary variable of type \Verb+fp+. % \begin{macrocode} @@ -460,56 +472,56 @@ and the derived files hobby.code.tex % \end{macrocode} % \end{macro} % -% \begin{macro}{\l_hobby_in_curl_fp} -% \Verb+\l_hobby_in_curl_fp+ is the ``curl'' at the end of an open path. +% \begin{macro}{\g__hobby_in_curl_fp} +% \Verb+\g__hobby_in_curl_fp+ is the ``curl'' at the end of an open path. % This is used if the angle at the end is not specified. % \begin{macrocode} -\fp_new:N \l_hobby_in_curl_fp -\fp_set:Nn \l_hobby_in_curl_fp {1} +\fp_new:N \g__hobby_in_curl_fp +\fp_gset:Nn \g__hobby_in_curl_fp {1} % \end{macrocode} % \end{macro} % -% \begin{macro}{\l_hobby_out_curl_fp} -% \Verb+\l_hobby_out_curl_fp+ is the ``curl'' at the start of an open path. +% \begin{macro}{\g__hobby_out_curl_fp} +% \Verb+\g__hobby_out_curl_fp+ is the ``curl'' at the start of an open path. % This is used if the angle at the start is not specified. % \begin{macrocode} -\fp_new:N \l_hobby_out_curl_fp -\fp_set:Nn \l_hobby_out_curl_fp {1} +\fp_new:N \g__hobby_out_curl_fp +\fp_gset:Nn \g__hobby_out_curl_fp {1} % \end{macrocode} % \end{macro} % -% \begin{macro}{\l_hobby_in_angle_fp} -% \Verb+\l_hobby_in_angle_fp+ is the angle at the end of an open path. +% \begin{macro}{\g__hobby_in_angle_fp} +% \Verb+\g__hobby_in_angle_fp+ is the angle at the end of an open path. % If this is not specified, it will be computed automatically. % It is set to \Verb+\c_inf_fp+ to allow easy detection of when it has been specified. % \begin{macrocode} -\fp_new:N \l_hobby_in_angle_fp -\fp_set_eq:NN \l_hobby_in_angle_fp \c_inf_fp +\fp_new:N \g__hobby_in_angle_fp +\fp_gset_eq:NN \g__hobby_in_angle_fp \c_inf_fp % \end{macrocode} % \end{macro} % -% \begin{macro}{\l_hobby_out_angle_fp} -% \Verb+\l_hobby_out_angle_fp+ is the angle at the start of an open path. +% \begin{macro}{\g__hobby_out_angle_fp} +% \Verb+\g__hobby_out_angle_fp+ is the angle at the start of an open path. % If this is not specified, it will be computed automatically. % It is set to \Verb+\c_inf_fp+ to allow easy detection of when it has been specified. % \begin{macrocode} -\fp_new:N \l_hobby_out_angle_fp -\fp_set_eq:NN \l_hobby_out_angle_fp \c_inf_fp +\fp_new:N \g__hobby_out_angle_fp +\fp_gset_eq:NN \g__hobby_out_angle_fp \c_inf_fp % \end{macrocode} % \end{macro} % -% \begin{macro}{\l_hobby_npoints_int} -% \Verb+\l_hobby_npoints_int+ is one less than the number of points on the curve. +% \begin{macro}{\g__hobby_npoints_int} +% \Verb+\g__hobby_npoints_int+ is one less than the number of points on the curve. % As our list of points starts at \(0\), this is the index of the last point. -% In the algorithm for a closed curve, some points are repeated whereupon this is incremented so that it is always the index of the last point. +% In the algorithm for a closed curve, some points are repeated whereupon this is incremented so that it is always the index of the last point. % \begin{macrocode} -\int_new:N \l_hobby_npoints_int +\int_new:N \g__hobby_npoints_int % \end{macrocode} % \end{macro} % -% \begin{macro}{\l_hobby_draw_int} +% \begin{macro}{\g__hobby_draw_int} % \begin{macrocode} -\int_new:N \l_hobby_draw_int +\int_new:N \g__hobby_draw_int % \end{macrocode} % \end{macro} % @@ -517,8 +529,10 @@ and the derived files hobby.code.tex % Using keys makes it easier to pass points from the algorithm code to the calling code and vice versa without either knowing too much about the other. % \begin{macrocode} \keys_define:nn {hobby / read in all} { - x .fp_set:N = \l_hobby_tempa_fp, - y .fp_set:N = \l_hobby_tempb_fp, + point .code:n = { + \fp_set:Nn \l_hobby_tempa_fp {\clist_item:nn {#1} {1}} + \fp_set:Nn \l_hobby_tempb_fp {\clist_item:nn {#1} {2}} + }, tension~out .fp_set:N = \l_hobby_tempc_fp, tension~in .fp_set:N = \l_hobby_tempd_fp, excess~angle .fp_set:N = \l_hobby_temps_fp, @@ -529,31 +543,31 @@ and the derived files hobby.code.tex blank .default:n = false, invert~soft~blanks .choice:, invert~soft~blanks / true .code:n = { - \int_gset:Nn \l_hobby_draw_int {0} + \int_gset:Nn \g__hobby_draw_int {0} }, invert~soft~blanks / false .code:n = { - \int_gset:Nn \l_hobby_draw_int {1} + \int_gset:Nn \g__hobby_draw_int {1} }, invert~soft~blanks .default:n = true, tension~out .default:n = 1, tension~in .default:n = 1, excess~angle .default:n = 0, - in~angle .fp_gset:N = \l_hobby_in_angle_fp, - out~angle .fp_gset:N = \l_hobby_out_angle_fp, - in~curl .fp_gset:N = \l_hobby_in_curl_fp, - out~curl .fp_gset:N = \l_hobby_out_curl_fp, - closed .bool_gset:N = \l_hobby_closed_bool, + in~angle .fp_gset:N = \g__hobby_in_angle_fp, + out~angle .fp_gset:N = \g__hobby_out_angle_fp, + in~curl .fp_gset:N = \g__hobby_in_curl_fp, + out~curl .fp_gset:N = \g__hobby_out_curl_fp, + closed .bool_gset:N = \g__hobby_closed_bool, closed .default:n = true, - disjoint .bool_gset:N = \l_hobby_disjoint_bool, + disjoint .bool_gset:N = \g__hobby_disjoint_bool, disjoint .default:n = true, break~default .code:n = { - \keys_define:nn { hobby / read in all } + \keys_define:nn { hobby / read in all } { break .default:n = #1 } }, blank~default .code:n = { - \keys_define:nn { hobby / read in all } + \keys_define:nn { hobby / read in all } { blank .default:n = #1 } @@ -563,32 +577,32 @@ and the derived files hobby.code.tex % There are certain other parameters that can be set for a given curve. % \begin{macrocode} \keys_define:nn { hobby / read in params} { - in~angle .fp_gset:N = \l_hobby_in_angle_fp, - out~angle .fp_gset:N = \l_hobby_out_angle_fp, - in~curl .fp_gset:N = \l_hobby_in_curl_fp, - out~curl .fp_gset:N = \l_hobby_out_curl_fp, - closed .bool_gset:N = \l_hobby_closed_bool, + in~angle .fp_gset:N = \g__hobby_in_angle_fp, + out~angle .fp_gset:N = \g__hobby_out_angle_fp, + in~curl .fp_gset:N = \g__hobby_in_curl_fp, + out~curl .fp_gset:N = \g__hobby_out_curl_fp, + closed .bool_gset:N = \g__hobby_closed_bool, closed .default:n = true, - disjoint .bool_gset:N = \l_hobby_disjoint_bool, + disjoint .bool_gset:N = \g__hobby_disjoint_bool, disjoint .default:n = true, break~default .code:n = { - \keys_define:nn { hobby / read in all } + \keys_define:nn { hobby / read in all } { break .default:n = #1 } }, blank~default .code:n = { - \keys_define:nn { hobby / read in all } + \keys_define:nn { hobby / read in all } { blank .default:n = #1 } }, invert~soft~blanks .choice:, invert~soft~blanks / true .code:n = { - \int_gset:Nn \l_hobby_draw_int {0} + \int_gset:Nn \g__hobby_draw_int {0} }, invert~soft~blanks / false .code:n = { - \int_gset:Nn \l_hobby_draw_int {1} + \int_gset:Nn \g__hobby_draw_int {1} }, invert~soft~blanks .default:n = true, } @@ -596,22 +610,22 @@ and the derived files hobby.code.tex % \begin{macro}{\hobby_distangle:n} % Computes the distance and angle between successive points. % The argument given is the index of the current point. -% Assumptions: the points are in \Verb+\l_hobby_points_x_array+ and \Verb+\l_hobby_points_y_array+ and the index of the last point is \Verb+\l_hobby_npoints_int+. +% Assumptions: the points are in \Verb+\g__hobby_points_x_array+ and \Verb+\g__hobby_points_y_array+ and the index of the last point is \Verb+\g__hobby_npoints_int+. % \begin{macrocode} \cs_set:Nn \hobby_distangle:n { \fp_set:Nn \l_hobby_tempa_fp { - (\array_get:Nn \l_hobby_points_x_array {#1 + 1}) - - (\array_get:Nn \l_hobby_points_x_array {#1})} + (\array_get:Nn \g__hobby_points_x_array {#1 + 1}) + - (\array_get:Nn \g__hobby_points_x_array {#1})} \fp_set:Nn \l_hobby_tempb_fp { - (\array_get:Nn \l_hobby_points_y_array {#1 + 1}) - - (\array_get:Nn \l_hobby_points_y_array {#1})} + (\array_get:Nn \g__hobby_points_y_array {#1 + 1}) + - (\array_get:Nn \g__hobby_points_y_array {#1})} \fp_set:Nn \l_hobby_tempc_fp { atan ( \l_hobby_tempb_fp, \l_hobby_tempa_fp ) } \fp_veclen:NVV \l_hobby_tempd_fp \l_hobby_tempa_fp \l_hobby_tempb_fp - \array_push:Nx \l_hobby_angles_array {\fp_to_tl:N \l_hobby_tempc_fp} - \array_push:Nx \l_hobby_distances_array {\fp_to_tl:N \l_hobby_tempd_fp} + \array_gpush:Nx \g__hobby_angles_array {\fp_to_tl:N \l_hobby_tempc_fp} + \array_gpush:Nx \g__hobby_distances_array {\fp_to_tl:N \l_hobby_tempd_fp} } % \end{macrocode} % \end{macro} @@ -647,13 +661,13 @@ and the derived files hobby.code.tex % \begin{macrocode} \cs_new_protected:Npn \hobby_append_point_copy:n #1 { - \hobby_append_point_copy_aux:Nn \l_hobby_points_array {#1} - \hobby_append_point_copy_aux:Nn \l_hobby_points_x_array {#1} - \hobby_append_point_copy_aux:Nn \l_hobby_points_y_array {#1} - \hobby_append_point_copy_aux:Nn \l_hobby_tension_in_array {#1} - \hobby_append_point_copy_aux:Nn \l_hobby_tension_out_array {#1} - \hobby_append_point_copy_aux:Nn \l_hobby_excess_angle_array {#1} - \hobby_append_point_copy_aux:Nn \l_hobby_actions_array {#1} + \hobby_append_point_copy_aux:Nn \g__hobby_points_array {#1} + \hobby_append_point_copy_aux:Nn \g__hobby_points_x_array {#1} + \hobby_append_point_copy_aux:Nn \g__hobby_points_y_array {#1} + \hobby_append_point_copy_aux:Nn \g__hobby_tension_in_array {#1} + \hobby_append_point_copy_aux:Nn \g__hobby_tension_out_array {#1} + \hobby_append_point_copy_aux:Nn \g__hobby_excess_angle_array {#1} + \hobby_append_point_copy_aux:Nn \g__hobby_actions_array {#1} } \cs_new_protected:Npn \hobby_append_point_copy_aux:Nn #1#2 { \array_gpush:Nx #1 { \array_get:Nn #1 {#2} } } @@ -666,17 +680,17 @@ and the derived files hobby.code.tex % So these must be set up by a wrapper function which then calls this one. % The list of required information is: % \begin{enumerate} -% \item \Verb+\l_hobby_points_x_array+ -% \item \Verb+\l_hobby_points_y_array+ -% \item \Verb+\l_hobby_tension_out_array+ -% \item \Verb+\l_hobby_tension_in_array+ -% \item \Verb+\l_hobby_excess_angle_array+ -% \item \Verb+\l_hobby_in_curl_fp+ -% \item \Verb+\l_hobby_out_curl_fp+ -% \item \Verb+\l_hobby_in_angle_fp+ -% \item \Verb+\l_hobby_out_angle_fp+ -% \item \Verb+\l_hobby_closed_bool+ -% \item \Verb+\l_hobby_actions_array+ +% \item \Verb+\g__hobby_points_x_array+ +% \item \Verb+\g__hobby_points_y_array+ +% \item \Verb+\g__hobby_tension_out_array+ +% \item \Verb+\g__hobby_tension_in_array+ +% \item \Verb+\g__hobby_excess_angle_array+ +% \item \Verb+\g__hobby_in_curl_fp+ +% \item \Verb+\g__hobby_out_curl_fp+ +% \item \Verb+\g__hobby_in_angle_fp+ +% \item \Verb+\g__hobby_out_angle_fp+ +% \item \Verb+\g__hobby_closed_bool+ +% \item \Verb+\g__hobby_actions_array+ % \end{enumerate} % % \begin{macrocode} @@ -687,22 +701,22 @@ and the derived files hobby.code.tex % To do this, we need to make the end node an internal node by repeating the \(z_1\) node as the \(z_{n+1}\)th node. % We also check that the last (\(z_n\)) and first (\(z_0\)) nodes are the same, otherwise we repeat the \(z_0\) node as well. % \begin{macrocode} -\bool_if:NT \l_hobby_closed_bool { +\bool_if:NT \g__hobby_closed_bool { % \end{macrocode} % Are the \(x\)-values of the first and last points different? % \begin{macrocode} - \fp_compare:nTF {(\array_get:Nn \l_hobby_points_x_array {0}) + \fp_compare:nTF {(\array_get:Nn \g__hobby_points_x_array {0}) = - (\array_top:N \l_hobby_points_x_array)} + (\array_top:N \g__hobby_points_x_array)} { % \end{macrocode} % No, so compare the \(y\)-values. % Are the \(y\)-values of the first and last points different? % \begin{macrocode} \fp_compare:nF { - \array_get:Nn \l_hobby_points_y_array {0} + \array_get:Nn \g__hobby_points_y_array {0} = - \array_top:N \l_hobby_points_y_array + \array_top:N \g__hobby_points_y_array } { % \end{macrocode} @@ -724,29 +738,29 @@ and the derived files hobby.code.tex } % \end{macrocode} % -% Set \Verb+\l_hobby_npoints_int+ to the number of points (minus one). +% Set \Verb+\g__hobby_npoints_int+ to the number of points (minus one). % \begin{macrocode} -\int_gset:Nn \l_hobby_npoints_int {\array_length:N \l_hobby_points_y_array} +\int_gset:Nn \g__hobby_npoints_int {\array_length:N \g__hobby_points_y_array} % \end{macrocode} % At this point, we need to decide what to do. % This will depend on whether we have any intermediate points. % \begin{macrocode} -\int_compare:nNnTF {\l_hobby_npoints_int} = {0} { +\int_compare:nNnTF {\g__hobby_npoints_int} = {0} { % \end{macrocode} % Only one point, do nothing % \begin{macrocode} } { - \int_compare:nNnTF {\l_hobby_npoints_int} = {1} { + \int_compare:nNnTF {\g__hobby_npoints_int} = {1} { % \end{macrocode} % Only two points, skip processing. % Just need to set the incoming and outgoing angles % \begin{macrocode} \hobby_distangle:n {0} -\fp_compare:nF { \l_hobby_out_angle_fp == \c_inf_fp } +\fp_compare:nF { \g__hobby_out_angle_fp == \c_inf_fp } { - \fp_set:Nn \l_hobby_tempa_fp { \l_hobby_out_angle_fp - - \array_get:Nn \l_hobby_angles_array {0}} + \fp_set:Nn \l_hobby_tempa_fp { \g__hobby_out_angle_fp + - \array_get:Nn \g__hobby_angles_array {0}} % \end{macrocode} % We want to ensure that these angles lie in the range \((-\pi,\pi]\). % So if the angle is bigger than \(\pi\), we subtract \(2 \pi\). @@ -763,24 +777,24 @@ and the derived files hobby.code.tex { \fp_add:Nn \l_hobby_tempa_fp {2 * \c_pi_fp} } - \array_put:Nnx \l_hobby_theta_array {0} {\fp_to_tl:N \l_hobby_tempa_fp} - \fp_compare:nT { \l_hobby_in_angle_fp == \c_inf_fp } + \array_gput:Nnx \g__hobby_theta_array {0} {\fp_to_tl:N \l_hobby_tempa_fp} + \fp_compare:nT { \g__hobby_in_angle_fp == \c_inf_fp } { %^^A \fp_mul:Nn \l_hobby_tempa_fp {-1} - \array_put:Nnx \l_hobby_phi_array {1}{ \fp_to_tl:N \l_hobby_tempa_fp} + \array_gput:Nnx \g__hobby_phi_array {1}{ \fp_to_tl:N \l_hobby_tempa_fp} } } -\fp_compare:nTF { \l_hobby_in_angle_fp == \c_inf_fp } +\fp_compare:nTF { \g__hobby_in_angle_fp == \c_inf_fp } { - \fp_compare:nT { \l_hobby_out_angle_fp == \c_inf_fp } + \fp_compare:nT { \g__hobby_out_angle_fp == \c_inf_fp } { - \array_put:Nnx \l_hobby_phi_array {1} {0} - \array_put:Nnx \l_hobby_theta_array {0} {0} + \array_gput:Nnx \g__hobby_phi_array {1} {0} + \array_gput:Nnx \g__hobby_theta_array {0} {0} } } { - \fp_set:Nn \l_hobby_tempa_fp { - \l_hobby_in_angle_fp + \c_pi_fp -+ (\array_get:Nn \l_hobby_angles_array {0})} + \fp_set:Nn \l_hobby_tempa_fp { - \g__hobby_in_angle_fp + \c_pi_fp ++ (\array_get:Nn \g__hobby_angles_array {0})} \fp_compare:nT {\l_hobby_tempa_fp > \c_pi_fp } { \fp_sub:Nn \l_hobby_tempa_fp {2 * \c_pi_fp} @@ -790,12 +804,12 @@ and the derived files hobby.code.tex \fp_add:Nn \l_hobby_tempa_fp {2 * \c_pi_fp} } - \array_put:Nnx \l_hobby_phi_array {1} + \array_gput:Nnx \g__hobby_phi_array {1} {\fp_to_tl:N \l_hobby_tempa_fp} - \fp_compare:nT { \l_hobby_out_angle_fp == \c_inf_fp } + \fp_compare:nT { \g__hobby_out_angle_fp == \c_inf_fp } { %^^A \fp_mul:Nn \l_hobby_tempa_fp {-1} - \array_put:Nnx \l_hobby_theta_array {0}{ \fp_to_tl:N \l_hobby_tempa_fp} + \array_gput:Nnx \g__hobby_theta_array {0}{ \fp_to_tl:N \l_hobby_tempa_fp} } } @@ -811,7 +825,7 @@ and the derived files hobby.code.tex } % \end{macrocode} % \end{macro} -% +% % % \begin{macro}{\hobby_compute_path:} % This is the path builder where we have enough points to run the algorithm. @@ -822,16 +836,16 @@ and the derived files hobby.code.tex % Our first step is to go through the list of points and compute the distances and angles between successive points. % Thus \(d_i\) is the distance from \(z_i\) to \(z_{i+1}\) and the angle is the angle of the line from \(z_i\) to \(z_{i+1}\). % \begin{macrocode} -\int_step_function:nnnN {0} {1} {\l_hobby_npoints_int - 1} \hobby_distangle:n +\int_step_function:nnnN {0} {1} {\g__hobby_npoints_int - 1} \hobby_distangle:n % \end{macrocode} % % For the majority of the code, we're only really interested in the differences of the angles. % So for each internal point we compute the differences in the angles. % \begin{macrocode} - \int_step_inline:nnnn {1} {1} {\l_hobby_npoints_int - 1} { + \int_step_inline:nnnn {1} {1} {\g__hobby_npoints_int - 1} { \fp_set:Nx \l_hobby_tempa_fp { - \array_get:Nn \l_hobby_angles_array {##1} - - \array_get:Nn \l_hobby_angles_array {##1 - 1}} + \array_get:Nn \g__hobby_angles_array {##1} + - \array_get:Nn \g__hobby_angles_array {##1 - 1}} % \end{macrocode} % We want to ensure that these angles lie in the range \((-\pi,\pi]\). % So if the angle is bigger than \(\pi\), we subtract \(2 \pi\). @@ -851,14 +865,14 @@ and the derived files hobby.code.tex } {} % \end{macrocode} -% The wrapping routine might not get it right at the edges so we add in the override. +% The wrapping routine might not get it right at the edges so we add in the override. % \begin{macrocode} -\array_get:NnNTF \l_hobby_excess_angle_array {##1} \l_tmpa_tl { +\array_get:NnNTF \g__hobby_excess_angle_array {##1} \l_tmpa_tl { \fp_add:Nn \l_hobby_tempa_fp {2 * \c_pi_fp * \l_tmpa_tl} }{} % \end{macrocode} % \begin{macrocode} - \array_put:Nnx \l_hobby_psi_array {##1}{\fp_to_tl:N \l_hobby_tempa_fp} + \array_gput:Nnx \g__hobby_psi_array {##1}{\fp_to_tl:N \l_hobby_tempa_fp} } % \end{macrocode} % @@ -866,11 +880,11 @@ and the derived files hobby.code.tex % We start with the subdiagonal. % This is indexed from \(1\) to \(n-1\). % \begin{macrocode} - \int_step_inline:nnnn {1} {1} {\l_hobby_npoints_int - 1} { - \array_put:Nnx \l_hobby_matrix_a_array {##1} {\fp_to_tl:n { - \array_get:Nn \l_hobby_tension_in_array {##1}^2 - * \array_get:Nn \l_hobby_distances_array {##1} - * \array_get:Nn \l_hobby_tension_in_array {##1 + 1} + \int_step_inline:nnnn {1} {1} {\g__hobby_npoints_int - 1} { + \array_gput:Nnx \g__hobby_matrix_a_array {##1} {\fp_to_tl:n { + \array_get:Nn \g__hobby_tension_in_array {##1}^2 + * \array_get:Nn \g__hobby_distances_array {##1} + * \array_get:Nn \g__hobby_tension_in_array {##1 + 1} }} } % \end{macrocode} @@ -878,30 +892,30 @@ and the derived files hobby.code.tex % Next, we attack main diagonal. % We might need to adjust the first and last terms, but we'll do that in a minute. % \begin{macrocode} - \int_step_inline:nnnn {1} {1} {\l_hobby_npoints_int - 1} { + \int_step_inline:nnnn {1} {1} {\g__hobby_npoints_int - 1} { - \array_put:Nnx \l_hobby_matrix_b_array {##1} {\fp_to_tl:n -{(3 * (\array_get:Nn \l_hobby_tension_in_array {##1 + 1}) - 1) * - (\array_get:Nn \l_hobby_tension_out_array {##1})^2 * -(\array_get:Nn \l_hobby_tension_out_array {##1 - 1}) -* ( \array_get:Nn \l_hobby_distances_array {##1 - 1}) + \array_gput:Nnx \g__hobby_matrix_b_array {##1} {\fp_to_tl:n +{(3 * (\array_get:Nn \g__hobby_tension_in_array {##1 + 1}) - 1) * + (\array_get:Nn \g__hobby_tension_out_array {##1})^2 * +(\array_get:Nn \g__hobby_tension_out_array {##1 - 1}) +* ( \array_get:Nn \g__hobby_distances_array {##1 - 1}) + -(3 * (\array_get:Nn \l_hobby_tension_out_array {##1 - 1}) - 1) -* (\array_get:Nn \l_hobby_tension_in_array {##1})^2 -* (\array_get:Nn \l_hobby_tension_in_array {##1 + 1}) -* (\array_get:Nn \l_hobby_distances_array {##1})} +(3 * (\array_get:Nn \g__hobby_tension_out_array {##1 - 1}) - 1) +* (\array_get:Nn \g__hobby_tension_in_array {##1})^2 +* (\array_get:Nn \g__hobby_tension_in_array {##1 + 1}) +* (\array_get:Nn \g__hobby_distances_array {##1})} } } % \end{macrocode} % % Next, the superdiagonal. % \begin{macrocode} - \int_step_inline:nnnn {1} {1} {\l_hobby_npoints_int - 2} { + \int_step_inline:nnnn {1} {1} {\g__hobby_npoints_int - 2} { - \array_put:Nnx \l_hobby_matrix_c_array {##1} {\fp_to_tl:n -{(\array_get:Nn \l_hobby_tension_in_array {##1})^2 -* (\array_get:Nn \l_hobby_tension_in_array {##1 - 1}) -* (\array_get:Nn \l_hobby_distances_array {##1 - 1}) + \array_gput:Nnx \g__hobby_matrix_c_array {##1} {\fp_to_tl:n +{(\array_get:Nn \g__hobby_tension_in_array {##1})^2 +* (\array_get:Nn \g__hobby_tension_in_array {##1 - 1}) +* (\array_get:Nn \g__hobby_distances_array {##1 - 1}) }} } @@ -909,19 +923,19 @@ and the derived files hobby.code.tex % % Lastly (before the adjustments), the target vector. % \begin{macrocode} - \int_step_inline:nnnn {1} {1} {\l_hobby_npoints_int - 2} { + \int_step_inline:nnnn {1} {1} {\g__hobby_npoints_int - 2} { - \array_put:Nnx \l_hobby_matrix_d_array {##1} {\fp_to_tl:n + \array_gput:Nnx \g__hobby_matrix_d_array {##1} {\fp_to_tl:n { -- (\array_get:Nn \l_hobby_psi_array {##1 + 1}) -* (\array_get:Nn \l_hobby_tension_out_array {##1})^2 -* (\array_get:Nn \l_hobby_tension_out_array {##1 - 1}) -* (\array_get:Nn \l_hobby_distances_array {##1 - 1}) -- (3 * (\array_get:Nn \l_hobby_tension_out_array {##1 - 1}) - 1) -* (\array_get:Nn \l_hobby_psi_array {##1}) -* (\array_get:Nn \l_hobby_tension_in_array {##1})^2 -* (\array_get:Nn \l_hobby_tension_in_array {##1 + 1}) -* (\array_get:Nn \l_hobby_distances_array {##1}) +- (\array_get:Nn \g__hobby_psi_array {##1 + 1}) +* (\array_get:Nn \g__hobby_tension_out_array {##1})^2 +* (\array_get:Nn \g__hobby_tension_out_array {##1 - 1}) +* (\array_get:Nn \g__hobby_distances_array {##1 - 1}) +- (3 * (\array_get:Nn \g__hobby_tension_out_array {##1 - 1}) - 1) +* (\array_get:Nn \g__hobby_psi_array {##1}) +* (\array_get:Nn \g__hobby_tension_in_array {##1})^2 +* (\array_get:Nn \g__hobby_tension_in_array {##1 + 1}) +* (\array_get:Nn \g__hobby_distances_array {##1}) } } } @@ -930,51 +944,51 @@ and the derived files hobby.code.tex % Next, there are some adjustments at the ends. % These differ depending on whether the path is open or closed. % \begin{macrocode} -\bool_if:NTF \l_hobby_closed_bool { +\bool_if:NTF \g__hobby_closed_bool { % \end{macrocode} % Closed path % \begin{macrocode} -\array_put:Nnx \l_hobby_matrix_c_array {0} {\fp_to_tl:n { -- (\array_get:Nn \l_hobby_distances_array {\l_hobby_npoints_int - 2}) -* (\array_get:Nn \l_hobby_tension_out_array {\l_hobby_npoints_int - 2}) -* (\array_get:Nn \l_hobby_tension_out_array {\l_hobby_npoints_int - 1})^2 +\array_gput:Nnx \g__hobby_matrix_c_array {0} {\fp_to_tl:n { +- (\array_get:Nn \g__hobby_distances_array {\g__hobby_npoints_int - 2}) +* (\array_get:Nn \g__hobby_tension_out_array {\g__hobby_npoints_int - 2}) +* (\array_get:Nn \g__hobby_tension_out_array {\g__hobby_npoints_int - 1})^2 }} -\array_put:Nnn \l_hobby_matrix_b_array {0} {1} -\array_put:Nnn \l_hobby_matrix_d_array {0} {0} +\array_gput:Nnn \g__hobby_matrix_b_array {0} {1} +\array_gput:Nnn \g__hobby_matrix_d_array {0} {0} -\array_put:Nnx \l_hobby_matrix_b_array {\l_hobby_npoints_int - 1} {\fp_to_tl:n { -(\array_get:Nn \l_hobby_matrix_b_array {\l_hobby_npoints_int - 1}) -+ 1 +\array_gput:Nnx \g__hobby_matrix_b_array {\g__hobby_npoints_int - 1} {\fp_to_tl:n { +(\array_get:Nn \g__hobby_matrix_b_array {\g__hobby_npoints_int - 1}) ++ 1 }} - \array_put:Nnx \l_hobby_matrix_d_array {\l_hobby_npoints_int - 1} {\fp_to_tl:n { -- (\array_get:Nn \l_hobby_psi_array {1}) -* (\array_get:Nn \l_hobby_tension_out_array {\l_hobby_npoints_int -1})^2 -* (\array_get:Nn \l_hobby_tension_out_array {\l_hobby_npoints_int -2}) -* (\array_get:Nn \l_hobby_distances_array {\l_hobby_npoints_int - 2}) -- (3 * (\array_get:Nn \l_hobby_tension_out_array {\l_hobby_npoints_int - 2}) - 1) -* (\array_get:Nn \l_hobby_psi_array {\l_hobby_npoints_int - 1}) -* (\array_get:Nn \l_hobby_tension_in_array {\l_hobby_npoints_int - 1})^2 -* (\array_get:Nn \l_hobby_tension_in_array {\l_hobby_npoints_int}) -* (\array_get:Nn \l_hobby_distances_array {\l_hobby_npoints_int -1}) + \array_gput:Nnx \g__hobby_matrix_d_array {\g__hobby_npoints_int - 1} {\fp_to_tl:n { +- (\array_get:Nn \g__hobby_psi_array {1}) +* (\array_get:Nn \g__hobby_tension_out_array {\g__hobby_npoints_int -1})^2 +* (\array_get:Nn \g__hobby_tension_out_array {\g__hobby_npoints_int -2}) +* (\array_get:Nn \g__hobby_distances_array {\g__hobby_npoints_int - 2}) +- (3 * (\array_get:Nn \g__hobby_tension_out_array {\g__hobby_npoints_int - 2}) - 1) +* (\array_get:Nn \g__hobby_psi_array {\g__hobby_npoints_int - 1}) +* (\array_get:Nn \g__hobby_tension_in_array {\g__hobby_npoints_int - 1})^2 +* (\array_get:Nn \g__hobby_tension_in_array {\g__hobby_npoints_int}) +* (\array_get:Nn \g__hobby_distances_array {\g__hobby_npoints_int -1}) } } % \end{macrocode} % We also need to populate the \(u\)-vector % \begin{macrocode} - \array_put:Nnn \l_hobby_vector_u_array {0} {1} -\array_put:Nnn \l_hobby_vector_u_array {\l_hobby_npoints_int - 1} {1} - \int_step_inline:nnnn {1} {1} {\l_hobby_npoints_int - 2} { - \array_put:Nnn \l_hobby_vector_u_array {##1} {0} + \array_gput:Nnn \g__hobby_vector_u_array {0} {1} +\array_gput:Nnn \g__hobby_vector_u_array {\g__hobby_npoints_int - 1} {1} + \int_step_inline:nnnn {1} {1} {\g__hobby_npoints_int - 2} { + \array_gput:Nnn \g__hobby_vector_u_array {##1} {0} } % \end{macrocode} % And define the significant entry in the \(v\)-vector. % \begin{macrocode} \fp_set:Nn \l_hobby_matrix_v_fp { -(\array_get:Nn \l_hobby_tension_out_array {\l_hobby_npoints_int -1})^2 -* (\array_get:Nn \l_hobby_tension_out_array {\l_hobby_npoints_int -2}) -* (\array_get:Nn \l_hobby_distances_array {\l_hobby_npoints_int -2}) +(\array_get:Nn \g__hobby_tension_out_array {\g__hobby_npoints_int -1})^2 +* (\array_get:Nn \g__hobby_tension_out_array {\g__hobby_npoints_int -2}) +* (\array_get:Nn \g__hobby_distances_array {\g__hobby_npoints_int -2}) } } { @@ -982,39 +996,39 @@ and the derived files hobby.code.tex % Open path. % First, we test to see if \(\theta_0\) has been specified. % \begin{macrocode} -\fp_compare:nTF { \l_hobby_out_angle_fp == \c_inf_fp } +\fp_compare:nTF { \g__hobby_out_angle_fp == \c_inf_fp } { - \array_put:Nnx \l_hobby_matrix_b_array {0} {\fp_to_tl:n { - (\array_get:Nn \l_hobby_tension_in_array {1})^3 -* \l_hobby_in_curl_fp + \array_gput:Nnx \g__hobby_matrix_b_array {0} {\fp_to_tl:n { + (\array_get:Nn \g__hobby_tension_in_array {1})^3 +* \g__hobby_in_curl_fp + -(3 * (\array_get:Nn \l_hobby_tension_in_array {1}) - 1) -* (\array_get:Nn \l_hobby_tension_out_array {0})^3 +(3 * (\array_get:Nn \g__hobby_tension_in_array {1}) - 1) +* (\array_get:Nn \g__hobby_tension_out_array {0})^3 }} - \array_put:Nnx \l_hobby_matrix_c_array {0} {\fp_to_tl:n { - (\array_get:Nn \l_hobby_tension_out_array {0})^3 + \array_gput:Nnx \g__hobby_matrix_c_array {0} {\fp_to_tl:n { + (\array_get:Nn \g__hobby_tension_out_array {0})^3 + -(3 * (\array_get:Nn \l_hobby_tension_out_array {0}) - 1) -* (\array_get:Nn \l_hobby_tension_in_array {1})^3 -* \l_hobby_in_curl_fp +(3 * (\array_get:Nn \g__hobby_tension_out_array {0}) - 1) +* (\array_get:Nn \g__hobby_tension_in_array {1})^3 +* \g__hobby_in_curl_fp }} - \array_put:Nnx \l_hobby_matrix_d_array {0} {\fp_to_tl:n { --( (\array_get:Nn \l_hobby_tension_out_array {0})^3 + \array_gput:Nnx \g__hobby_matrix_d_array {0} {\fp_to_tl:n { +-( (\array_get:Nn \g__hobby_tension_out_array {0})^3 + -(3 * (\array_get:Nn \l_hobby_tension_out_array {0}) - 1) -* (\array_get:Nn \l_hobby_tension_in_array {1})^3 -* \l_hobby_in_curl_fp) -* (\array_get:Nn \l_hobby_psi_array {1}) +(3 * (\array_get:Nn \g__hobby_tension_out_array {0}) - 1) +* (\array_get:Nn \g__hobby_tension_in_array {1})^3 +* \g__hobby_in_curl_fp) +* (\array_get:Nn \g__hobby_psi_array {1}) }} - + } { - \array_put:Nnn \l_hobby_matrix_b_array {0} {1} - \array_put:Nnn \l_hobby_matrix_c_array {0} {0} - \fp_set:Nn \l_hobby_tempa_fp { \l_hobby_out_angle_fp - - \array_get:Nn \l_hobby_angles_array {0}} + \array_gput:Nnn \g__hobby_matrix_b_array {0} {1} + \array_gput:Nnn \g__hobby_matrix_c_array {0} {0} + \fp_set:Nn \l_hobby_tempa_fp { \g__hobby_out_angle_fp + - \array_get:Nn \g__hobby_angles_array {0}} % \end{macrocode} % We want to ensure that these angles lie in the range \((-\pi,\pi]\). % So if the angle is bigger than \(\pi\), we subtract \(2 \pi\). @@ -1031,46 +1045,46 @@ and the derived files hobby.code.tex { \fp_add:Nn \l_hobby_tempa_fp {2 * \c_pi_fp} } - \array_put:Nnx \l_hobby_matrix_d_array {0} {\fp_to_tl:N \l_hobby_tempa_fp} + \array_gput:Nnx \g__hobby_matrix_d_array {0} {\fp_to_tl:N \l_hobby_tempa_fp} } % \end{macrocode} % % Next, if \(\phi_n\) has been given. % \begin{macrocode} -\fp_compare:nTF { \l_hobby_in_angle_fp == \c_inf_fp } +\fp_compare:nTF { \g__hobby_in_angle_fp == \c_inf_fp } { - \array_put:Nnx \l_hobby_matrix_b_array {\l_hobby_npoints_int - 1} {\fp_to_tl:n { -\array_get:Nn \l_hobby_matrix_b_array {\l_hobby_npoints_int - 1} -- (\array_get:Nn \l_hobby_tension_out_array {\l_hobby_npoints_int - 1})^2 -* (\array_get:Nn \l_hobby_tension_out_array {\l_hobby_npoints_int - 2}) -* (\array_get:Nn \l_hobby_distances_array {\l_hobby_npoints_int - 2}) + \array_gput:Nnx \g__hobby_matrix_b_array {\g__hobby_npoints_int - 1} {\fp_to_tl:n { +\array_get:Nn \g__hobby_matrix_b_array {\g__hobby_npoints_int - 1} +- (\array_get:Nn \g__hobby_tension_out_array {\g__hobby_npoints_int - 1})^2 +* (\array_get:Nn \g__hobby_tension_out_array {\g__hobby_npoints_int - 2}) +* (\array_get:Nn \g__hobby_distances_array {\g__hobby_npoints_int - 2}) * -((3 * (\array_get:Nn \l_hobby_tension_in_array {\l_hobby_npoints_int} ) - 1) -* (\array_get:Nn \l_hobby_tension_out_array {\l_hobby_npoints_int - 1})^3 \l_tmpa_tl -* \l_hobby_out_curl_fp +((3 * (\array_get:Nn \g__hobby_tension_in_array {\g__hobby_npoints_int} ) - 1) +* (\array_get:Nn \g__hobby_tension_out_array {\g__hobby_npoints_int - 1})^3 \l_tmpa_tl +* \g__hobby_out_curl_fp + -(\array_get:Nn \l_hobby_tension_in_array {\l_hobby_npoints_int })^3) +(\array_get:Nn \g__hobby_tension_in_array {\g__hobby_npoints_int })^3) / -((3 * (\array_get:Nn \l_hobby_tension_out_array {\l_hobby_npoints_int -2}) - 1) -* (\array_get:Nn \l_hobby_tension_in_array {\l_hobby_npoints_int})^3 +((3 * (\array_get:Nn \g__hobby_tension_out_array {\g__hobby_npoints_int -2}) - 1) +* (\array_get:Nn \g__hobby_tension_in_array {\g__hobby_npoints_int})^3 + -( \array_get:Nn \l_hobby_tension_out_array {\l_hobby_npoints_int - 1})^3 -* \l_hobby_out_curl_fp) +( \array_get:Nn \g__hobby_tension_out_array {\g__hobby_npoints_int - 1})^3 +* \g__hobby_out_curl_fp) }} - \array_put:Nnx \l_hobby_matrix_d_array {\l_hobby_npoints_int - 1} {\fp_to_tl:n { -- (3 * (\array_get:Nn \l_hobby_tension_out_array {\l_hobby_npoints_int - 2}) - 1) -* (\array_get:Nn \l_hobby_psi_array {\l_hobby_npoints_int - 1}) -* (\array_get:Nn \l_hobby_tension_in_array {\l_hobby_npoints_int - 1})^2 -* (\array_get:Nn \l_hobby_tension_in_array {\l_hobby_npoints_int}) -* (\array_get:Nn \l_hobby_distances_array {\l_hobby_npoints_int - 1}) + \array_gput:Nnx \g__hobby_matrix_d_array {\g__hobby_npoints_int - 1} {\fp_to_tl:n { +- (3 * (\array_get:Nn \g__hobby_tension_out_array {\g__hobby_npoints_int - 2}) - 1) +* (\array_get:Nn \g__hobby_psi_array {\g__hobby_npoints_int - 1}) +* (\array_get:Nn \g__hobby_tension_in_array {\g__hobby_npoints_int - 1})^2 +* (\array_get:Nn \g__hobby_tension_in_array {\g__hobby_npoints_int}) +* (\array_get:Nn \g__hobby_distances_array {\g__hobby_npoints_int - 1}) }} } { - \fp_set:Nn \l_hobby_tempa_fp { - \l_hobby_in_angle_fp + \c_pi_fp -+ (\array_get:Nn \l_hobby_angles_array {\l_hobby_npoints_int - 1})} + \fp_set:Nn \l_hobby_tempa_fp { - \g__hobby_in_angle_fp + \c_pi_fp ++ (\array_get:Nn \g__hobby_angles_array {\g__hobby_npoints_int - 1})} \fp_compare:nT {\l_hobby_tempa_fp > \c_pi_fp } { \fp_sub:Nn \l_hobby_tempa_fp {2 * \c_pi_fp} @@ -1080,20 +1094,20 @@ and the derived files hobby.code.tex \fp_add:Nn \l_hobby_tempa_fp {2 * \c_pi_fp} } - \array_put:Nnx \l_hobby_phi_array {\l_hobby_npoints_int} + \array_gput:Nnx \g__hobby_phi_array {\g__hobby_npoints_int} {\fp_to_tl:N \l_hobby_tempa_fp} - \array_put:Nnx \l_hobby_matrix_d_array {\l_hobby_npoints_int - 1} {\fp_to_tl:n { + \array_gput:Nnx \g__hobby_matrix_d_array {\g__hobby_npoints_int - 1} {\fp_to_tl:n { \l_hobby_tempa_fp - * (\array_get:Nn \l_hobby_tension_out_array {\l_hobby_npoints_int - 1})^2 -* (\array_get:Nn \l_hobby_tension_out_array {\l_hobby_npoints_int - 2}) -* (\array_get:Nn \l_hobby_distances_array {\l_hobby_npoints_int - 2}) + * (\array_get:Nn \g__hobby_tension_out_array {\g__hobby_npoints_int - 1})^2 +* (\array_get:Nn \g__hobby_tension_out_array {\g__hobby_npoints_int - 2}) +* (\array_get:Nn \g__hobby_distances_array {\g__hobby_npoints_int - 2}) - -(3 * ( \array_get:Nn \l_hobby_tension_out_array {\l_hobby_npoints_int - 2}) - 1) -* (\array_get:Nn \l_hobby_psi_array {\l_hobby_npoints_int - 1}) -* (\array_get:Nn \l_hobby_tension_in_array {\l_hobby_npoints_int - 1})^2 -* (\array_get:Nn \l_hobby_tension_in_array {\l_hobby_npoints_int}) -* (\array_get:Nn \l_hobby_distances_array {\l_hobby_npoints_int - 1}) }} +(3 * ( \array_get:Nn \g__hobby_tension_out_array {\g__hobby_npoints_int - 2}) - 1) +* (\array_get:Nn \g__hobby_psi_array {\g__hobby_npoints_int - 1}) +* (\array_get:Nn \g__hobby_tension_in_array {\g__hobby_npoints_int - 1})^2 +* (\array_get:Nn \g__hobby_tension_in_array {\g__hobby_npoints_int}) +* (\array_get:Nn \g__hobby_distances_array {\g__hobby_npoints_int - 1}) }} } % \end{macrocode} % End of adjustments for open paths. @@ -1104,43 +1118,43 @@ and the derived files hobby.code.tex % Now we have the tridiagonal matrix in place, we implement the solution. % We start with the forward eliminations. % \begin{macrocode} -\int_step_inline:nnnn {1} {1} {\l_hobby_npoints_int - 1} { +\int_step_inline:nnnn {1} {1} {\g__hobby_npoints_int - 1} { - \array_put:Nnx \l_hobby_matrix_b_array {##1} {\fp_to_tl:n { - (\array_get:Nn \l_hobby_matrix_b_array {##1 - 1}) -* (\array_get:Nn \l_hobby_matrix_b_array {##1}) + \array_gput:Nnx \g__hobby_matrix_b_array {##1} {\fp_to_tl:n { + (\array_get:Nn \g__hobby_matrix_b_array {##1 - 1}) +* (\array_get:Nn \g__hobby_matrix_b_array {##1}) - -(\array_get:Nn \l_hobby_matrix_c_array {##1 - 1}) -* (\array_get:Nn \l_hobby_matrix_a_array {##1}) +(\array_get:Nn \g__hobby_matrix_c_array {##1 - 1}) +* (\array_get:Nn \g__hobby_matrix_a_array {##1}) }} % \end{macrocode} % The last time, we don't touch the \(C\)-vector. % \begin{macrocode} - \int_compare:nT {##1 < \l_hobby_npoints_int - 1} { + \int_compare:nT {##1 < \g__hobby_npoints_int - 1} { - \array_put:Nnx \l_hobby_matrix_c_array {##1} {\fp_to_tl:n { -(\array_get:Nn \l_hobby_matrix_b_array {##1 - 1}) - * (\array_get:Nn \l_hobby_matrix_c_array {##1}) + \array_gput:Nnx \g__hobby_matrix_c_array {##1} {\fp_to_tl:n { +(\array_get:Nn \g__hobby_matrix_b_array {##1 - 1}) + * (\array_get:Nn \g__hobby_matrix_c_array {##1}) }} } - \array_put:Nnx \l_hobby_matrix_d_array {##1} {\fp_to_tl:n { -(\array_get:Nn \l_hobby_matrix_b_array {##1 - 1}) - * (\array_get:Nn \l_hobby_matrix_d_array {##1}) + \array_gput:Nnx \g__hobby_matrix_d_array {##1} {\fp_to_tl:n { +(\array_get:Nn \g__hobby_matrix_b_array {##1 - 1}) + * (\array_get:Nn \g__hobby_matrix_d_array {##1}) - - (\array_get:Nn \l_hobby_matrix_d_array {##1 - 1}) - * (\array_get:Nn \l_hobby_matrix_a_array {##1}) + (\array_get:Nn \g__hobby_matrix_d_array {##1 - 1}) + * (\array_get:Nn \g__hobby_matrix_a_array {##1}) }} % \end{macrocode} % On a closed path, we also want to know \(M^{-1} u\) so need to do the elimination steps on \(u\) as well. % \begin{macrocode} - \bool_if:NT \l_hobby_closed_bool { - \array_put:Nnx \l_hobby_vector_u_array {##1} {\fp_to_tl:n { -(\array_get:Nn \l_hobby_matrix_b_array {##1 - 1}) -* (\array_get:Nn \l_hobby_vector_u_array {##1}) + \bool_if:NT \g__hobby_closed_bool { + \array_gput:Nnx \g__hobby_vector_u_array {##1} {\fp_to_tl:n { +(\array_get:Nn \g__hobby_matrix_b_array {##1 - 1}) +* (\array_get:Nn \g__hobby_vector_u_array {##1}) - -(\array_get:Nn \l_hobby_vector_u_array {##1 - 1}) -* (\array_get:Nn \l_hobby_matrix_a_array {##1}) +(\array_get:Nn \g__hobby_vector_u_array {##1 - 1}) +* (\array_get:Nn \g__hobby_matrix_a_array {##1}) }} } } @@ -1148,42 +1162,42 @@ and the derived files hobby.code.tex % Now we start the back substitution. % The first step is slightly different to the general step. % \begin{macrocode} - \array_put:Nnx \l_hobby_theta_array {\l_hobby_npoints_int - 1} {\fp_to_tl:n { -(\array_get:Nn \l_hobby_matrix_d_array {\l_hobby_npoints_int - 1}) -/ (\array_get:Nn \l_hobby_matrix_b_array {\l_hobby_npoints_int - 1}) + \array_gput:Nnx \g__hobby_theta_array {\g__hobby_npoints_int - 1} {\fp_to_tl:n { +(\array_get:Nn \g__hobby_matrix_d_array {\g__hobby_npoints_int - 1}) +/ (\array_get:Nn \g__hobby_matrix_b_array {\g__hobby_npoints_int - 1}) }} % \end{macrocode} % For a closed path, we need to work with \(u\) as well. % \begin{macrocode} -\bool_if:NT \l_hobby_closed_bool { - \array_put:Nnx \l_hobby_vector_u_array {\l_hobby_npoints_int - 1} {\fp_to_tl:n { - (\array_get:Nn \l_hobby_vector_u_array {\l_hobby_npoints_int - 1}) -/ (\array_get:Nn \l_hobby_matrix_b_array {\l_hobby_npoints_int - 1}) +\bool_if:NT \g__hobby_closed_bool { + \array_gput:Nnx \g__hobby_vector_u_array {\g__hobby_npoints_int - 1} {\fp_to_tl:n { + (\array_get:Nn \g__hobby_vector_u_array {\g__hobby_npoints_int - 1}) +/ (\array_get:Nn \g__hobby_matrix_b_array {\g__hobby_npoints_int - 1}) }} } % \end{macrocode} % Now we iterate over the vectors, doing the remaining back substitutions. % \begin{macrocode} -\int_step_inline:nnnn {\l_hobby_npoints_int - 2} {-1} {0} { +\int_step_inline:nnnn {\g__hobby_npoints_int - 2} {-1} {0} { - \array_put:Nnx \l_hobby_theta_array {##1} {\fp_to_tl:n { -( (\array_get:Nn \l_hobby_matrix_d_array {##1}) - - (\array_get:Nn \l_hobby_theta_array {##1 + 1}) - * (\array_get:Nn \l_hobby_matrix_c_array {##1}) -) / (\array_get:Nn \l_hobby_matrix_b_array {##1}) + \array_gput:Nnx \g__hobby_theta_array {##1} {\fp_to_tl:n { +( (\array_get:Nn \g__hobby_matrix_d_array {##1}) + - (\array_get:Nn \g__hobby_theta_array {##1 + 1}) + * (\array_get:Nn \g__hobby_matrix_c_array {##1}) +) / (\array_get:Nn \g__hobby_matrix_b_array {##1}) }} } -\bool_if:NT \l_hobby_closed_bool { +\bool_if:NT \g__hobby_closed_bool { % \end{macrocode} % On a closed path, we also need to work out \(M^{-1} u\). % \begin{macrocode} -\int_step_inline:nnnn {\l_hobby_npoints_int - 2} {-1} {0} { - \array_put:Nnx \l_hobby_vector_u_array {##1} {\fp_to_tl:n +\int_step_inline:nnnn {\g__hobby_npoints_int - 2} {-1} {0} { + \array_gput:Nnx \g__hobby_vector_u_array {##1} {\fp_to_tl:n { - ((\array_get:Nn \l_hobby_vector_u_array {##1}) - - (\array_get:Nn \l_hobby_vector_u_array {##1 + 1}) - * (\array_get:Nn \l_hobby_matrix_c_array {##1}) - ) / (\array_get:Nn \l_hobby_matrix_b_array {##1}) + ((\array_get:Nn \g__hobby_vector_u_array {##1}) + - (\array_get:Nn \g__hobby_vector_u_array {##1 + 1}) + * (\array_get:Nn \g__hobby_matrix_c_array {##1}) + ) / (\array_get:Nn \g__hobby_matrix_b_array {##1}) }} } % \end{macrocode} @@ -1192,21 +1206,21 @@ and the derived files hobby.code.tex % \begin{macrocode} \fp_set:Nn \l_hobby_tempb_fp { -((\array_get:Nn \l_hobby_theta_array {1}) +((\array_get:Nn \g__hobby_theta_array {1}) * \l_hobby_matrix_v_fp -- (\array_get:Nn \l_hobby_theta_array {\l_hobby_npoints_int - 1}) +- (\array_get:Nn \g__hobby_theta_array {\g__hobby_npoints_int - 1}) ) / ( -(\array_get:Nn \l_hobby_vector_u_array {1}) +(\array_get:Nn \g__hobby_vector_u_array {1}) * \l_hobby_matrix_v_fp -- (\array_get:Nn \l_hobby_vector_u_array {\l_hobby_npoints_int - 1}) +- (\array_get:Nn \g__hobby_vector_u_array {\g__hobby_npoints_int - 1}) + 1 )} -\int_step_inline:nnnn {0} {1} {\l_hobby_npoints_int - 1} { +\int_step_inline:nnnn {0} {1} {\g__hobby_npoints_int - 1} { - \array_put:Nnx \l_hobby_theta_array {##1} {\fp_to_tl:n { - (\array_get:Nn \l_hobby_theta_array {##1}) - - (\array_get:Nn \l_hobby_vector_u_array {##1}) + \array_gput:Nnx \g__hobby_theta_array {##1} {\fp_to_tl:n { + (\array_get:Nn \g__hobby_theta_array {##1}) + - (\array_get:Nn \g__hobby_vector_u_array {##1}) * \l_hobby_tempb_fp }} } @@ -1216,11 +1230,11 @@ and the derived files hobby.code.tex % Now that we have computed the \(\theta_i\)s, we can quickly compute the \(\phi_i\)s. % % \begin{macrocode} -\int_step_inline:nnnn {1} {1} {\l_hobby_npoints_int - 1} { +\int_step_inline:nnnn {1} {1} {\g__hobby_npoints_int - 1} { - \array_put:Nnx \l_hobby_phi_array {##1} {\fp_to_tl:n { - - (\array_get:Nn \l_hobby_psi_array {##1}) - - (\array_get:Nn \l_hobby_theta_array {##1}) + \array_gput:Nnx \g__hobby_phi_array {##1} {\fp_to_tl:n { + - (\array_get:Nn \g__hobby_psi_array {##1}) + - (\array_get:Nn \g__hobby_theta_array {##1}) }} } % \end{macrocode} @@ -1229,28 +1243,28 @@ and the derived files hobby.code.tex % If the path is closed, we can drop our added point. % Cheaply, of course. % \begin{macrocode} -\bool_if:NTF \l_hobby_closed_bool { - \int_gdecr:N \l_hobby_npoints_int +\bool_if:NTF \g__hobby_closed_bool { + \int_gdecr:N \g__hobby_npoints_int }{ % \end{macrocode} % If \(\phi_n\) was not given, we compute it from \(\theta_{n-1}\). % \begin{macrocode} -\fp_compare:nT { \l_hobby_in_angle_fp == \c_inf_fp } +\fp_compare:nT { \g__hobby_in_angle_fp == \c_inf_fp } { - \array_put:Nnx \l_hobby_phi_array {\l_hobby_npoints_int} {\fp_to_tl:n { -((3 * (\array_get:Nn \l_hobby_tension_in_array {\l_hobby_npoints_int}) - 1) -* (\array_get:Nn \l_hobby_tension_out_array {\l_hobby_npoints_int - 1})^3 -* \l_hobby_out_curl_fp + \array_gput:Nnx \g__hobby_phi_array {\g__hobby_npoints_int} {\fp_to_tl:n { +((3 * (\array_get:Nn \g__hobby_tension_in_array {\g__hobby_npoints_int}) - 1) +* (\array_get:Nn \g__hobby_tension_out_array {\g__hobby_npoints_int - 1})^3 +* \g__hobby_out_curl_fp + -(\array_get:Nn \l_hobby_tension_in_array {\l_hobby_npoints_int })^3) +(\array_get:Nn \g__hobby_tension_in_array {\g__hobby_npoints_int })^3) / -((3 * (\array_get:Nn \l_hobby_tension_out_array {\l_hobby_npoints_int -2}) - 1) -* (\array_get:Nn \l_hobby_tension_in_array {\l_hobby_npoints_int})^3 \l_tmpa_tl +((3 * (\array_get:Nn \g__hobby_tension_out_array {\g__hobby_npoints_int -2}) - 1) +* (\array_get:Nn \g__hobby_tension_in_array {\g__hobby_npoints_int})^3 \l_tmpa_tl + -(\array_get:Nn \l_hobby_tension_out_array {\l_hobby_npoints_int - 1})^3 -* \l_hobby_out_curl_fp) +(\array_get:Nn \g__hobby_tension_out_array {\g__hobby_npoints_int - 1})^3 +* \g__hobby_out_curl_fp) * -(\array_get:Nn \l_hobby_theta_array {\l_hobby_npoints_int -1}) +(\array_get:Nn \g__hobby_theta_array {\g__hobby_npoints_int -1}) }} } } @@ -1267,58 +1281,58 @@ and the derived files hobby.code.tex % \end{macrocode} % Next task is to compute the \(\rho_i\) and \(\sigma_i\). % \begin{macrocode} -\int_step_inline:nnnn {0} {1} {\l_hobby_npoints_int - 1} { +\int_step_inline:nnnn {0} {1} {\g__hobby_npoints_int - 1} { - \fp_set:Nn \l_hobby_tempa_fp {\array_get:Nn \l_hobby_theta_array {##1}} + \fp_set:Nn \l_hobby_tempa_fp {\array_get:Nn \g__hobby_theta_array {##1}} - \fp_set:Nn \l_hobby_tempb_fp {\array_get:Nn \l_hobby_phi_array {##1 + 1}} + \fp_set:Nn \l_hobby_tempb_fp {\array_get:Nn \g__hobby_phi_array {##1 + 1}} \hobby_ctrllen:NVV \l_hobby_temps_fp \l_hobby_tempa_fp \l_hobby_tempb_fp - \array_put:Nnx \l_hobby_sigma_array {##1 + 1} {\fp_to_tl:N \l_hobby_temps_fp} + \array_gput:Nnx \g__hobby_sigma_array {##1 + 1} {\fp_to_tl:N \l_hobby_temps_fp} \hobby_ctrllen:NVV \l_hobby_temps_fp \l_hobby_tempb_fp \l_hobby_tempa_fp - \array_put:Nnx \l_hobby_rho_array {##1} {\fp_to_tl:N \l_hobby_temps_fp} + \array_gput:Nnx \g__hobby_rho_array {##1} {\fp_to_tl:N \l_hobby_temps_fp} } % \end{macrocode} % Lastly, we generate the coordinates of the control points. % \begin{macrocode} -\int_step_inline:nnnn {0} {1} {\l_hobby_npoints_int - 1} { -\array_gput:Nnx \l_hobby_controla_array {##1 + 1} {x = \fp_eval:n { -(\array_get:Nn \l_hobby_points_x_array {##1}) +\int_step_inline:nnnn {0} {1} {\g__hobby_npoints_int - 1} { +\array_gput:Nnx \g__hobby_controla_array {##1 + 1} {\fp_eval:n { +(\array_get:Nn \g__hobby_points_x_array {##1}) + - (\array_get:Nn \l_hobby_distances_array {##1}) * - (\array_get:Nn \l_hobby_rho_array {##1}) * -cos ( (\array_get:Nn \l_hobby_angles_array {##1}) + (\array_get:Nn \g__hobby_distances_array {##1}) * + (\array_get:Nn \g__hobby_rho_array {##1}) * +cos ( (\array_get:Nn \g__hobby_angles_array {##1}) + - (\array_get:Nn \l_hobby_theta_array {##1})) + (\array_get:Nn \g__hobby_theta_array {##1})) /3 -}, y = \fp_eval:n { -( \array_get:Nn \l_hobby_points_y_array {##1}) + - (\array_get:Nn \l_hobby_distances_array {##1}) * - (\array_get:Nn \l_hobby_rho_array {##1}) * -sin ( (\array_get:Nn \l_hobby_angles_array {##1}) +}, \fp_eval:n { +( \array_get:Nn \g__hobby_points_y_array {##1}) + + (\array_get:Nn \g__hobby_distances_array {##1}) * + (\array_get:Nn \g__hobby_rho_array {##1}) * +sin ( (\array_get:Nn \g__hobby_angles_array {##1}) + - (\array_get:Nn \l_hobby_theta_array {##1})) + (\array_get:Nn \g__hobby_theta_array {##1})) /3 } } } -\int_step_inline:nnnn {1} {1} {\l_hobby_npoints_int} { - \array_gput:Nnx \l_hobby_controlb_array {##1} { - x = \fp_eval:n {\array_get:Nn \l_hobby_points_x_array {##1} -- (\array_get:Nn \l_hobby_distances_array {##1 - 1}) -* (\array_get:Nn \l_hobby_sigma_array {##1}) -* cos((\array_get:Nn \l_hobby_angles_array {##1 - 1}) -- (\array_get:Nn \l_hobby_phi_array {##1}))/3 -}, y = \fp_eval:n { - (\array_get:Nn \l_hobby_points_y_array {##1}) -- (\array_get:Nn \l_hobby_distances_array {##1 - 1}) -* (\array_get:Nn \l_hobby_sigma_array {##1}) -* sin((\array_get:Nn \l_hobby_angles_array {##1 - 1}) -- (\array_get:Nn \l_hobby_phi_array {##1}))/3 +\int_step_inline:nnnn {1} {1} {\g__hobby_npoints_int} { + \array_gput:Nnx \g__hobby_controlb_array {##1} { + \fp_eval:n {\array_get:Nn \g__hobby_points_x_array {##1} +- (\array_get:Nn \g__hobby_distances_array {##1 - 1}) +* (\array_get:Nn \g__hobby_sigma_array {##1}) +* cos((\array_get:Nn \g__hobby_angles_array {##1 - 1}) +- (\array_get:Nn \g__hobby_phi_array {##1}))/3 +}, \fp_eval:n { + (\array_get:Nn \g__hobby_points_y_array {##1}) +- (\array_get:Nn \g__hobby_distances_array {##1 - 1}) +* (\array_get:Nn \g__hobby_sigma_array {##1}) +* sin((\array_get:Nn \g__hobby_angles_array {##1 - 1}) +- (\array_get:Nn \g__hobby_phi_array {##1}))/3 } } } } @@ -1329,7 +1343,7 @@ sin ( (\array_get:Nn \l_hobby_angles_array {##1}) % Initialise the settings for Hobby's algorithm % \begin{macrocode} \NewDocumentCommand \hobbyinit {m m m} { - \hobby_set_cmds:nnn#1#2#3 + \hobby_set_cmds:NNN #1#2#3 \hobby_clear_path: } % \end{macrocode} @@ -1339,35 +1353,45 @@ sin ( (\array_get:Nn \l_hobby_angles_array {##1}) % This adds a point, possibly with tensions, to the current stack. % \begin{macrocode} \NewDocumentCommand \hobbyaddpoint { m } { - \keys_set:nn { hobby/read in all } - { - tension~out, - tension~in, - excess~angle, - blank, - break, - #1 - } - \tl_if_eq:VnTF {\l_tmpa_tl} {true} - {\tl_set:Nn \l_tmpa_tl {2}} - { - \tl_if_eq:VnTF {\l_tmpa_tl} {soft} - {\tl_set:Nn \l_tmpa_tl {0}} - {\tl_set:Nn \l_tmpa_tl {1}} - } - \tl_if_eq:VnTF {\l_tmpb_tl} {true} - {\tl_put_right:Nn \l_tmpa_tl {1}} - {\tl_put_right:Nn \l_tmpa_tl {0}} - \array_gpush:Nx \l_hobby_actions_array {\l_tmpa_tl} - \array_gpush:Nx \l_hobby_tension_out_array {\fp_to_tl:N \l_hobby_tempc_fp} - \array_gpush:Nx \l_hobby_tension_in_array {\fp_to_tl:N \l_hobby_tempd_fp} - \array_gpush:Nx \l_hobby_excess_angle_array {\fp_to_tl:N \l_hobby_temps_fp} - \array_gpush:Nx \l_hobby_points_array { - x = \fp_use:N \l_hobby_tempa_fp, - y = \fp_use:N \l_hobby_tempb_fp } - \array_gpush:Nx \l_hobby_points_x_array {\fp_to_tl:N \l_hobby_tempa_fp} - \array_gpush:Nx \l_hobby_points_y_array {\fp_to_tl:N \l_hobby_tempb_fp} + \keys_set:nn { hobby/read in all } + { + tension~out, + tension~in, + excess~angle, + blank, + break, + #1 + } + \tl_if_eq:VnTF \l_tmpa_tl {true} + {\tl_set:Nn \l_tmpa_tl {2}} + { + \tl_if_eq:VnTF \l_tmpa_tl {soft} + {\tl_set:Nn \l_tmpa_tl {0}} + {\tl_set:Nn \l_tmpa_tl {1}} + } + \tl_if_eq:VnTF \l_tmpb_tl {true} + {\tl_put_right:Nn \l_tmpa_tl {1}} + {\tl_put_right:Nn \l_tmpa_tl {0}} + \tl_set:Nx \l_hobby_tempa_tl {\fp_use:N \l_hobby_tempa_fp} + \tl_set:Nx \l_hobby_tempb_tl {\fp_use:N \l_hobby_tempb_fp} + \hobby_add_point:VVVVVV \l_hobby_tempa_tl \l_hobby_tempb_tl \l_hobby_tempc_fp \l_hobby_tempd_fp \l_hobby_temps_fp \l_tmpa_tl +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\hobby_add_point:n} +% \begin{macrocode} +\cs_new_nopar:Npn \hobby_add_point:nnnnnn #1#2#3#4#5#6 +{ + \array_gpush:Nn \g__hobby_actions_array { #6 } + \array_gpush:Nn \g__hobby_tension_out_array { #3 } + \array_gpush:Nn \g__hobby_tension_in_array { #4 } + \array_gpush:Nn \g__hobby_excess_angle_array { #5 } + \array_gpush:Nn \g__hobby_points_array { #1, #2 } + \array_gpush:Nn \g__hobby_points_x_array { #1 } + \array_gpush:Nn \g__hobby_points_y_array { #2 } } +\cs_generate_variant:Nn \hobby_add_point:nnnnnn {VVVVVV} % \end{macrocode} % \end{macro} % @@ -1383,7 +1407,7 @@ sin ( (\array_get:Nn \l_hobby_angles_array {##1}) % \end{macrocode} % \end{macro} % -% \begin{macro}{\hobby_set_cmds:nnn} +% \begin{macro}{\hobby_set_cmds:NNN} % The path-generation code doesn't know what to actually do with the path so the initialisation code will set some macros to do that. % This is an auxiliary command that sets these macros. % \begin{macrocode} @@ -1393,7 +1417,7 @@ sin ( (\array_get:Nn \l_hobby_angles_array {##1}) \cs_generate_variant:Nn \hobby_moveto:nnn {VVV,nnV} \cs_generate_variant:Nn \hobby_curveto:nnn {VVV} \cs_generate_variant:Nn \hobby_close:n {V} -\cs_new:Nn \hobby_set_cmds:nnn { +\cs_new:Nn \hobby_set_cmds:NNN { \cs_gset_eq:NN \hobby_moveto:nnn #1 \cs_gset_eq:NN \hobby_curveto:nnn #2 \cs_gset_eq:NN \hobby_close:n #3 @@ -1405,7 +1429,7 @@ sin ( (\array_get:Nn \l_hobby_angles_array {##1}) % This is the user (well, sort of) command that generates the curve. % \begin{macrocode} \NewDocumentCommand \hobbygenpath { } { - \array_if_empty:NF \l_hobby_points_array { + \array_if_empty:NF \g__hobby_points_array { \hobby_gen_path: } } @@ -1496,7 +1520,7 @@ sin ( (\array_get:Nn \l_hobby_angles_array {##1}) % This is the user (well, sort of) command that generates a curve and uses it. % \begin{macrocode} \NewDocumentCommand \hobbygenusepath { } { - \array_if_empty:NF \l_hobby_points_array { + \array_if_empty:NF \g__hobby_points_array { \hobby_gen_path: \hobby_use_path: } @@ -1518,29 +1542,30 @@ sin ( (\array_get:Nn \l_hobby_angles_array {##1}) % As the curve data is stored globally, the same data can be reused by calling this function more than once without calling the generating function. % \begin{macrocode} \tl_new:N \l_tmpc_tl +\tl_new:N \l_tmpd_tl \cs_new:Nn \hobby_use_path: { - \bool_if:NT \l_hobby_disjoint_bool { - \array_get:NnN \l_hobby_points_array {0} \l_tmpa_tl + \bool_if:NT \g__hobby_disjoint_bool { + \array_get:NnN \g__hobby_points_array {0} \l_tmpa_tl \hobby_moveto:nnV {} {} \l_tmpa_tl } - \int_step_inline:nnnn {1} {1} {\l_hobby_npoints_int} { - \array_get:NnN \l_hobby_controla_array {##1} \l_tmpa_tl - \array_get:NnN \l_hobby_controlb_array {##1} \l_tmpb_tl - \array_get:NnN \l_hobby_points_array {##1} \l_tmpc_tl - \array_get:NnN \l_hobby_actions_array {##1} \l_tmpd_tl - \int_compare:nNnTF {\tl_item:Nn \l_tmpd_tl {1}} = {\l_hobby_draw_int} { + \int_step_inline:nnnn {1} {1} {\g__hobby_npoints_int} { + \array_get:NnN \g__hobby_controla_array {##1} \l_tmpa_tl + \array_get:NnN \g__hobby_controlb_array {##1} \l_tmpb_tl + \array_get:NnN \g__hobby_points_array {##1} \l_tmpc_tl + \array_get:NnN \g__hobby_actions_array {##1} \l_tmpd_tl + \int_compare:nNnTF {\tl_item:Nn \l_tmpd_tl {1}} = {\g__hobby_draw_int} { \hobby_curveto:VVV \l_tmpa_tl \l_tmpb_tl \l_tmpc_tl }{ - \bool_gset_false:N \l_hobby_closed_bool + \bool_gset_false:N \g__hobby_closed_bool \hobby_moveto:VVV \l_tmpa_tl \l_tmpb_tl \l_tmpc_tl } \tl_if_eq:xnTF {\tl_item:Nn \l_tmpd_tl {2}} {1} { - \bool_gset_false:N \l_hobby_closed_bool + \bool_gset_false:N \g__hobby_closed_bool \hobby_moveto:VVV \l_tmpa_tl \l_tmpb_tl \l_tmpc_tl }{} } - \bool_if:NT \l_hobby_closed_bool { - \array_get:NnN \l_hobby_points_array {0} \l_tmpa_tl + \bool_if:NT \g__hobby_closed_bool { + \array_get:NnN \g__hobby_points_array {0} \l_tmpa_tl \hobby_close:V \l_tmpa_tl } } @@ -1552,42 +1577,42 @@ sin ( (\array_get:Nn \l_hobby_angles_array {##1}) % \begin{macrocode} \cs_new:Nn \hobby_save_path:n { \tl_clear:N \l_tmpa_tl - \tl_put_right:Nn \l_tmpa_tl {\int_gset:Nn \l_hobby_npoints_int} - \tl_put_right:Nx \l_tmpa_tl {{\int_use:N \l_hobby_npoints_int}} - \bool_if:NTF \l_hobby_disjoint_bool { + \tl_put_right:Nn \l_tmpa_tl {\int_gset:Nn \g__hobby_npoints_int} + \tl_put_right:Nx \l_tmpa_tl {{\int_use:N \g__hobby_npoints_int}} + \bool_if:NTF \g__hobby_disjoint_bool { \tl_put_right:Nn \l_tmpa_tl {\bool_gset_true:N} }{ \tl_put_right:Nn \l_tmpa_tl {\bool_gset_false:N} } - \tl_put_right:Nn \l_tmpa_tl {\l_hobby_disjoint_bool} - \bool_if:NTF \l_hobby_closed_bool { + \tl_put_right:Nn \l_tmpa_tl {\g__hobby_disjoint_bool} + \bool_if:NTF \g__hobby_closed_bool { \tl_put_right:Nn \l_tmpa_tl {\bool_gset_true:N} }{ \tl_put_right:Nn \l_tmpa_tl {\bool_gset_false:N} } - \tl_put_right:Nn \l_tmpa_tl {\l_hobby_closed_bool} - \tl_put_right:Nn \l_tmpa_tl {\array_gclear:N \l_hobby_points_array} - \array_map_inline:Nn \l_hobby_points_array { + \tl_put_right:Nn \l_tmpa_tl {\g__hobby_closed_bool} + \tl_put_right:Nn \l_tmpa_tl {\array_gclear:N \g__hobby_points_array} + \array_map_inline:Nn \g__hobby_points_array { \tl_put_right:Nn \l_tmpa_tl { - \array_gput:Nnn \l_hobby_points_array {##1} {##2} + \array_gput:Nnn \g__hobby_points_array {##1} {##2} } } - \tl_put_right:Nn \l_tmpa_tl {\array_gclear:N \l_hobby_actions_array} - \array_map_inline:Nn \l_hobby_actions_array { + \tl_put_right:Nn \l_tmpa_tl {\array_gclear:N \g__hobby_actions_array} + \array_map_inline:Nn \g__hobby_actions_array { \tl_put_right:Nn \l_tmpa_tl { - \array_gput:Nnn \l_hobby_actions_array {##1} {##2} + \array_gput:Nnn \g__hobby_actions_array {##1} {##2} } } - \tl_put_right:Nn \l_tmpa_tl {\array_gclear:N \l_hobby_controla_array} - \array_map_inline:Nn \l_hobby_controla_array { + \tl_put_right:Nn \l_tmpa_tl {\array_gclear:N \g__hobby_controla_array} + \array_map_inline:Nn \g__hobby_controla_array { \tl_put_right:Nn \l_tmpa_tl { - \array_gput:Nnn \l_hobby_controla_array {##1} {##2} + \array_gput:Nnn \g__hobby_controla_array {##1} {##2} } } - \tl_put_right:Nn \l_tmpa_tl {\array_gclear:N \l_hobby_controlb_array} - \array_map_inline:Nn \l_hobby_controlb_array { + \tl_put_right:Nn \l_tmpa_tl {\array_gclear:N \g__hobby_controlb_array} + \array_map_inline:Nn \g__hobby_controlb_array { \tl_put_right:Nn \l_tmpa_tl { - \array_gput:Nnn \l_hobby_controlb_array {##1} {##2} + \array_gput:Nnn \g__hobby_controlb_array {##1} {##2} } } \tl_gclear_new:c {g_hobby_#1_path} @@ -1636,36 +1661,36 @@ sin ( (\array_get:Nn \l_hobby_angles_array {##1}) % \begin{macrocode} \cs_new:Nn \hobby_clear_path: { -\array_gclear:N \l_hobby_points_array -\array_gclear:N \l_hobby_points_x_array -\array_gclear:N \l_hobby_points_y_array -\array_gclear:N \l_hobby_angles_array -\array_gclear:N \l_hobby_actions_array -\array_gclear:N \l_hobby_distances_array -\array_gclear:N \l_hobby_tension_out_array -\array_gclear:N \l_hobby_tension_in_array -\array_gclear:N \l_hobby_excess_angle_array -\array_gclear:N \l_hobby_matrix_a_array -\array_gclear:N \l_hobby_matrix_b_array -\array_gclear:N \l_hobby_matrix_c_array -\array_gclear:N \l_hobby_matrix_d_array -\array_gclear:N \l_hobby_vector_u_array -\array_gclear:N \l_hobby_psi_array -\array_gclear:N \l_hobby_theta_array -\array_gclear:N \l_hobby_phi_array -\array_gclear:N \l_hobby_sigma_array -\array_gclear:N \l_hobby_rho_array -\array_gclear:N \l_hobby_controla_array -\array_gclear:N \l_hobby_controlb_array -\bool_gset_false:N \l_hobby_closed_bool -\bool_gset_false:N \l_hobby_disjoint_bool +\array_gclear:N \g__hobby_points_array +\array_gclear:N \g__hobby_points_x_array +\array_gclear:N \g__hobby_points_y_array +\array_gclear:N \g__hobby_angles_array +\array_gclear:N \g__hobby_actions_array +\array_gclear:N \g__hobby_distances_array +\array_gclear:N \g__hobby_tension_out_array +\array_gclear:N \g__hobby_tension_in_array +\array_gclear:N \g__hobby_excess_angle_array +\array_gclear:N \g__hobby_matrix_a_array +\array_gclear:N \g__hobby_matrix_b_array +\array_gclear:N \g__hobby_matrix_c_array +\array_gclear:N \g__hobby_matrix_d_array +\array_gclear:N \g__hobby_vector_u_array +\array_gclear:N \g__hobby_psi_array +\array_gclear:N \g__hobby_theta_array +\array_gclear:N \g__hobby_phi_array +\array_gclear:N \g__hobby_sigma_array +\array_gclear:N \g__hobby_rho_array +\array_gclear:N \g__hobby_controla_array +\array_gclear:N \g__hobby_controlb_array +\bool_gset_false:N \g__hobby_closed_bool +\bool_gset_false:N \g__hobby_disjoint_bool - \int_gset:Nn \l_hobby_npoints_int {-1} - \int_gset:Nn \l_hobby_draw_int {1} - \fp_gset_eq:NN \l_hobby_in_angle_fp \c_inf_fp - \fp_gset_eq:NN \l_hobby_out_angle_fp \c_inf_fp - \fp_gset_eq:NN \l_hobby_in_curl_fp \c_one_fp - \fp_gset_eq:NN \l_hobby_out_curl_fp \c_one_fp + \int_gset:Nn \g__hobby_npoints_int {-1} + \int_gset:Nn \g__hobby_draw_int {1} + \fp_gset_eq:NN \g__hobby_in_angle_fp \c_inf_fp + \fp_gset_eq:NN \g__hobby_out_angle_fp \c_inf_fp + \fp_gset_eq:NN \g__hobby_in_curl_fp \c_one_fp + \fp_gset_eq:NN \g__hobby_out_curl_fp \c_one_fp } % \end{macrocode} % \end{macro} @@ -1681,7 +1706,7 @@ sin ( (\array_get:Nn \l_hobby_angles_array {##1}) % \iffalse %<*pgflibrary> % \fi -% +% % The PGF level is very simple. % All we do is set up the path-construction commands that get passed to the path-generation function. % \begin{macrocode} @@ -1693,8 +1718,12 @@ sin ( (\array_get:Nn \l_hobby_angles_array {##1}) \pgfkeys{ /pgf/hobby/.is family, /pgf/hobby/.cd, - x/.code={\pgf@x=#1cm}, - y/.code={\pgf@y=#1cm} + point/.code={% + \hobby@parse@pt#1\relax} +} +\def\hobby@parse@pt#1,#2\relax{% + \pgf@x=#1cm\relax + \pgf@y=#2cm\relax } % \end{macrocode} % @@ -1738,7 +1767,7 @@ sin ( (\array_get:Nn \l_hobby_angles_array {##1}) % Translates a \LaTeX3 point to a PGF point. % \begin{macrocode} \def\hobby@topgf#1{% - \pgfqkeys{/pgf/hobby}{#1}% + \pgfqkeys{/pgf/hobby}{point={#1}}% } % \end{macrocode} % \end{macro} @@ -1763,7 +1792,7 @@ sin ( (\array_get:Nn \l_hobby_angles_array {##1}) \hobbysetparams{#1}% \pgfmathsetmacro\hobby@x{\the\pgf@path@lastx/1cm}% \pgfmathsetmacro\hobby@y{\the\pgf@path@lasty/1cm}% - \hobbyaddpoint{x = \hobby@x, y = \hobby@y}% + \hobbyaddpoint{point={\hobby@x, \hobby@y}}% } % \end{macrocode} % \end{macro} @@ -1783,7 +1812,7 @@ sin ( (\array_get:Nn \l_hobby_angles_array {##1}) % \begin{macro}{\pgfpathhobbyptparams} % \begin{macrocode} \def\pgfpathhobbyptparams#1{% - \hobbyaddpoint{#1,x = \hobby@x, y = \hobby@y}% + \hobbyaddpoint{#1,point={\hobby@x, \hobby@y}}% } % \end{macrocode} % \end{macro} @@ -1890,7 +1919,7 @@ sin ( (\array_get:Nn \l_hobby_angles_array {##1}) #1% \pgfmathsetmacro\hobby@x{\the\pgf@x/1cm}% \pgfmathsetmacro\hobby@y{\the\pgf@y/1cm}% - \hobbyaddpoint{x = \hobby@x, y = \hobby@y}% + \hobbyaddpoint{point={\hobby@x, \hobby@y}}% } % \end{macrocode} % \end{macro} @@ -2046,7 +2075,7 @@ sin ( (\array_get:Nn \l_hobby_angles_array {##1}) % \begin{macrocode} \hobby@quick@ctrlpts{\hobby@thetazero}{\hobby@phione}{\hobby@qpoints}{\hobby@qpointa}{\hobby@dzero}{\hobby@omegazero}% % \end{macrocode} -% Now call the call-back function +% Now call the call-back function % \begin{macrocode} \edef\hobby@temp{\noexpand\hobby@quick@curveto{\noexpand\pgfqpoint{\the\pgf@xa}{\the\pgf@ya}}{\noexpand\pgfqpoint{\the\pgf@xb}{\the\pgf@yb}}{\noexpand\pgfqpoint{\the\pgf@x}{\the\pgf@y}}}% \hobby@temp @@ -2077,7 +2106,7 @@ sin ( (\array_get:Nn \l_hobby_angles_array {##1}) % \begin{macrocode} \hobby@quick@ctrlpts{\hobby@thetaone}{\hobby@phitwo}{\hobby@qpoints}{\hobby@qpointa}{\hobby@done}{\hobby@omegaone}% % \end{macrocode} -% Now call the call-back function +% Now call the call-back function % \begin{macrocode} \edef\hobby@temp{\noexpand\hobby@quick@curveto{\noexpand\pgfqpoint{\the\pgf@xa}{\the\pgf@ya}}{\noexpand\pgfqpoint{\the\pgf@xb}{\the\pgf@yb}}{\noexpand\pgfqpoint{\the\pgf@x}{\the\pgf@y}}}% \hobby@temp @@ -2131,7 +2160,7 @@ sin ( (\array_get:Nn \l_hobby_angles_array {##1}) % \iffalse %<*tikzlibrary> % \fi -% +% % \begin{macrocode} \usepgflibrary{hobby} \let\hobby@this@opts=\pgfutil@empty @@ -2163,7 +2192,7 @@ sin ( (\array_get:Nn \l_hobby_angles_array {##1}) \expandafter\gdef\expandafter\hobby@point@options\expandafter% {\hobby@point@options,tension out=#1}% }, - tension/.code = {% + tension/.append code = {% \expandafter\gdef\expandafter\hobby@point@options\expandafter% {\hobby@point@options,tension=#1}% }, @@ -2221,7 +2250,7 @@ sin ( (\array_get:Nn \l_hobby_angles_array {##1}) in curl/.style = {% add option to Hobby path={in curl=#1}% }, - out curl/.code = {% + out curl/.style = {% add option to Hobby path={out curl=#1}% }, use Hobby shortcut/.code={% @@ -2233,28 +2262,25 @@ sin ( (\array_get:Nn \l_hobby_angles_array {##1}) \global\let\hobby@curveto@delegate=\hobby@qcurveto@auto }, use previous Hobby path/.code={% - \pgfextra{\hobbyusepath{#1}} + \hobbyusepath{#1}% }, use previous Hobby path/.default={},% save Hobby path/.code={% \xdef\hobby@path@name{#1}% }, restore Hobby path/.code={% - \pgfextra{% - \hobbyinit\hobby@tikz@moveto\hobby@tikz@curveto\hobby@tikz@close - \global\let\hobby@collected@onpath\pgfutil@empty - \hobbyrestorepath{#1}} + \hobbyinit\hobby@tikz@moveto\hobby@tikz@curveto\hobby@tikz@close + \global\let\hobby@collected@onpath\pgfutil@empty + \hobbyrestorepath{#1}% }, restore and use Hobby path/.code 2 args={% - \pgfextra{% - \hobbyinit\hobby@tikz@moveto\hobby@tikz@curveto\hobby@tikz@close - \global\let\hobby@collected@onpath\pgfutil@empty - \hobbyrestorepath{#1}% - \hobbyusepath{#2}% - } + \hobbyinit\hobby@tikz@moveto\hobby@tikz@curveto\hobby@tikz@close + \global\let\hobby@collected@onpath\pgfutil@empty + \hobbyrestorepath{#1}% + \hobbyusepath{#2}% }, show Hobby path/.code={% - \pgfextra{\hobbyshowpath{#1}} + \hobbyshowpath{#1}% }, Hobby action/.code={% \expandafter\gdef\expandafter\hobby@action\expandafter{\hobby@action#1}% @@ -2390,10 +2416,10 @@ sin ( (\array_get:Nn \l_hobby_angles_array {##1}) \pgfmathsetmacro\hobby@x{\the\pgf@x/1cm}% \pgfmathsetmacro\hobby@y{\the\pgf@y/1cm}% \ifx\hobby@initial@pt\pgfutil@empty - \xdef\hobby@initial@pt{x = \hobby@x, y = \hobby@y}% + \xdef\hobby@initial@pt{\hobby@x, \hobby@y}% \fi \expandafter\hobbyaddpoint\expandafter{\hobby@point@options,% - x = \hobby@x, y = \hobby@y}% + point={\hobby@x, \hobby@y}}% \def\hobby@point@options{}% \let\tikz@scan@point@options=\pgfutil@empty \pgfutil@ifnextchar\relax{% @@ -2452,10 +2478,10 @@ sin ( (\array_get:Nn \l_hobby_angles_array {##1}) \let\tikz@collected@onpath=\pgfutil@empty \pgfmathsetmacro\hobby@x{\the\tikz@lastx/1cm}% \pgfmathsetmacro\hobby@y{\the\tikz@lasty/1cm}% - \xdef\hobby@initial@pt{x = \hobby@x, y = \hobby@y}% + \xdef\hobby@initial@pt{\hobby@x, \hobby@y}% \expandafter\hobbysetparams\expandafter{\hobby@next@opts}% \expandafter\hobbyaddpoint\expandafter{\hobby@point@options,% - x = \hobby@x, y = \hobby@y}% + point={\hobby@x, \hobby@y} }% \hobby@init@tikz@commands \tikzset{designated Hobby path=this}% \let\tikz@scan@point@options=\pgfutil@empty @@ -2478,7 +2504,7 @@ sin ( (\array_get:Nn \l_hobby_angles_array {##1}) \pgfmathsetmacro\hobby@y{\the\pgf@y/1cm}% \expandafter\hobbysetparams\expandafter{\hobby@this@opts}% \expandafter\hobbyaddpoint\expandafter{\hobby@point@options,% - x = \hobby@x, y = \hobby@y}% + point={\hobby@x, \hobby@y}}% \hobby@action \global\let\hobby@this@opts=\pgfutil@empty \global\let\hobby@action=\pgfutil@empty @@ -2936,7 +2962,7 @@ sin ( (\array_get:Nn \l_hobby_angles_array {##1}) % \iffalse %<*array> % \fi -% +% % % A lot of our data structures are really arrays. % These are implemented as \LaTeX3 ``property lists''. @@ -2953,11 +2979,12 @@ sin ( (\array_get:Nn \l_hobby_angles_array {##1}) \int_new:N \l_array_base_int \int_new:N \l_array_top_int \int_new:N \l_array_tmp_int +\int_new:N \g_array_map_int % \end{macrocode} % The global variable \Verb+\g_array_base_int+ says what index a blank array should start with when pushed or unshifted. % \begin{macrocode} \int_new:N \g_array_base_int -\int_set:Nn \g_array_base_int {0} +\int_gset:Nn \g_array_base_int {0} % \end{macrocode} % \begin{macro}{\array_adjust_ends:Nn} % This ensures that the ``base'' and ``top'' are big enough to include the given index. @@ -3164,12 +3191,12 @@ sin ( (\array_get:Nn \l_hobby_angles_array {##1}) % \begin{macrocode} \cs_new_protected:Npn \array_map_inline:Nn #1#2 { - \int_gincr:N \g__prg_map_int - \cs_gset:cpn { array_map_inline_ \int_use:N \g__prg_map_int :nn } + \int_gincr:N \g_array_map_int + \cs_gset:cpn { array_map_inline_ \int_use:N \g_array_map_int :nn } ##1##2 {#2} \exp_args:NNc \array_map_function:NN #1 - { array_map_inline_ \int_use:N \g__prg_map_int :nn } - \__prg_break_point:Nn \array_map_break: { \int_gdecr:N \g__prg_map_int } + { array_map_inline_ \int_use:N \g_array_map_int :nn } + \prg_break_point:Nn \array_map_break: { \int_gdecr:N \g_array_map_int } } \cs_generate_variant:Nn \array_map_inline:Nn { c } % \end{macrocode} @@ -3180,12 +3207,12 @@ sin ( (\array_get:Nn \l_hobby_angles_array {##1}) % \begin{macrocode} \cs_new_protected:Npn \array_reverse_map_inline:Nn #1#2 { - \int_gincr:N \g__prg_map_int - \cs_gset:cpn { array_map_inline_ \int_use:N \g__prg_map_int :nn } + \int_gincr:N \g_array_map_int + \cs_gset:cpn { array_map_inline_ \int_use:N \g_array_map_int :nn } ##1##2 {#2} \exp_args:NNc \array_reverse_map_function:NN #1 - { array_map_inline_ \int_use:N \g__prg_map_int :nn } - \__prg_break_point:Nn \array_map_break: { \int_gdecr:N \g__prg_map_int } + { array_map_inline_ \int_use:N \g_array_map_int :nn } + \prg_break_point:Nn \array_map_break: { \int_gdecr:N \g_array_map_int } } \cs_generate_variant:Nn \array_reverse_map_inline:Nn { c } % \end{macrocode} @@ -3194,9 +3221,9 @@ sin ( (\array_get:Nn \l_hobby_angles_array {##1}) % \begin{macro}{\array_map_break:} % \begin{macrocode} \cs_new_nopar:Npn \array_map_break: - { \__prg_map_break:Nn \array_map_break: { } } + { \prg_map_break:Nn \array_map_break: { } } \cs_new_nopar:Npn \array_map_break:n - { \__prg_map_break:Nn \array_map_break: } + { \prg_map_break:Nn \array_map_break: } % \end{macrocode} % \end{macro} % @@ -3245,7 +3272,7 @@ sin ( (\array_get:Nn \l_hobby_angles_array {##1}) % \end{macrocode} % \end{macro} % -% \begin{macro}{\array_gpush:Nn}b +% \begin{macro}{\array_gpush:Nn} % \begin{macrocode} \cs_new_protected:Npn \array_gpush:Nn #1#2 { @@ -3435,7 +3462,7 @@ sin ( (\array_get:Nn \l_hobby_angles_array {##1}) % \begin{macrocode} \cs_new_protected:Npn \array_gdel:Nn #1#2 { - \exp_args:NNx \prop_gpop:Nn #1 {\int_eval:n {#2}} + \exp_args:NNx \prop_gremove:Nn #1 {\int_eval:n {#2}} \int_set:Nn \l_array_tmp_int {0} \array_map_inline:Nn #1 { \tl_if_eq:NNTF {##2} {\q_no_value} {} @@ -3496,5 +3523,92 @@ sin ( (\array_get:Nn \l_hobby_angles_array {##1}) % \iffalse %</array> % \fi -% +% +% \iffalse +%<*l3hobby> +% \fi +% +% \begin{macrocode} +\RequirePackage{expl3} +% \end{macrocode} +% +% Load the hobby core +% \begin{macrocode} +\input{hobby.code.tex} +% \end{macrocode} +% +% Register as an expl3 package +% \begin{macrocode} +\ProvidesExplPackage {hobby-l3draw} {2018/02/20} {1.0} {Interface for l3draw and hobby} +% \end{macrocode} +% +% Load the l3draw package +% \begin{macrocode} +\RequirePackage{l3draw} +% \end{macrocode} +% +% +% \begin{macro}{\hobby_draw_moveto:nnn} +% This provides our interface between hobby's moveto and l3draw's moveto +% \begin{macrocode} +\cs_new_protected:Npn \hobby_draw_moveto:nnn #1#2#3 +{ + \draw_path_canvas_moveto:n {#3} +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\hobby_draw_curveto:nnn} +% This provides our interface between hobby's curveto and l3draw's curveto +% \begin{macrocode} +\cs_set_eq:NN \hobby_draw_curveto:nnn \draw_path_canvas_curveto:nnn +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\hobby_draw_close:n} +% This provides our interface between hobby's close and l3draw's close +% \begin{macrocode} +\cs_new_protected:Npn \hobby_draw_close:n #1 +{ + \draw_path_close: +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\hobby_draw_addpoint:n} +% This processes a point and passes it one more step towards the hobby algorithm +% \begin{macrocode} +\cs_new_protected:Npn \hobby_draw_addpoint:n #1 +{ + \__draw_point_process:nn + { \__hobby_draw_addpoint:nn } + { \draw_point_transform:n {#1} } +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\__hobby_draw_curveto:nn} +% This provides our interface between l3draw's points and hobby's syntax +% \begin{macrocode} +\cs_new_protected:Npn \__hobby_draw_addpoint:nn #1#2 +{ + \hobby_add_point:nnnnnn {#1} {#2} {1} {1} {0} {10} +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\hobby_draw_init:} +% This initialises hobby's algorithm with the l3draw commands +% \begin{macrocode} +\cs_new_protected:Npn \hobby_draw_init: +{ + \hobby_set_cmds:NNN \hobby_draw_moveto:nnn \hobby_draw_curveto:nnn \hobby_draw_close:n + \hobby_clear_path: +} +% \end{macrocode} +% \end{macro} +% +% \iffalse +%</l3hobby> +% \fi %\Finale diff --git a/graphics/pgf/contrib/hobby/hobby_code.pdf b/graphics/pgf/contrib/hobby/hobby_code.pdf Binary files differindex 9b8f4973b9..f58e42fcfc 100644 --- a/graphics/pgf/contrib/hobby/hobby_code.pdf +++ b/graphics/pgf/contrib/hobby/hobby_code.pdf |