diff options
author | Karl Berry <karl@freefriends.org> | 2021-03-14 23:19:59 +0000 |
---|---|---|
committer | Karl Berry <karl@freefriends.org> | 2021-03-14 23:19:59 +0000 |
commit | ceca438fddde2040f41fc0723fc066a8345f5e2b (patch) | |
tree | 67b1de096b693347b60a6308446e3b2e02ff6c1e /Master/texmf-dist/tex/latex | |
parent | ce7d08a8d4a8e445cae634dce76820b4a81485d6 (diff) |
sankey (14mar21) (branch)
git-svn-id: svn://tug.org/texlive/branches/branch2020.0@58363 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist/tex/latex')
-rw-r--r-- | Master/texmf-dist/tex/latex/sankey/sankey-doc-preamble.sty | 226 | ||||
-rw-r--r-- | Master/texmf-dist/tex/latex/sankey/sankey.sty | 1201 | ||||
-rw-r--r-- | Master/texmf-dist/tex/latex/sankey/tikzlibrarydubins.code.tex | 425 |
3 files changed, 1096 insertions, 756 deletions
diff --git a/Master/texmf-dist/tex/latex/sankey/sankey-doc-preamble.sty b/Master/texmf-dist/tex/latex/sankey/sankey-doc-preamble.sty new file mode 100644 index 00000000000..9bfa992cf80 --- /dev/null +++ b/Master/texmf-dist/tex/latex/sankey/sankey-doc-preamble.sty @@ -0,0 +1,226 @@ +\usepackage[paper=a4paper,vmargin=1.5cm,left=4.5cm,right=3.5cm]{geometry} +\usepackage[utf8]{inputenc} +\usepackage{cmap} +\usepackage[T1]{fontenc} +\usepackage{lmodern} +\usepackage[final,protrusion=true,expansion=true]{microtype} +\usepackage{xcolor} +\PassOptionsToPackage{final,colorlinks,linkcolor=red!60!orange!85!black}{hyperref} +\usepackage[numbered]{hypdoc} +\usepackage{fancyvrb} +\usepackage[final]{listings} +\usepackage{enumitem} +\usepackage{bookmark} +\usepackage{siunitx} +\usepackage{footnote} +\usepackage{etoc} +\usepackage{accsupp} +\usepackage{tikz} +\usetikzlibrary{positioning,patterns.meta,fit} +\usepackage[british]{babel} +\usepackage{varioref} +\usepackage{embedfile} +\usepackage{dtx-attach} +\embedfile[mimetype=text/plain]{sankey.ins} +\usepackage{sankey} + +\colorlet{bgcode}{yellow!50!gray!5} +\colorlet{keyword}{blue!50!cyan!50!black} +\colorlet{comment}{red!75!black} + +\newcommand\emptyaccsupp[1]{\BeginAccSupp{ActualText={}}#1\EndAccSupp{}} + +\lstset{ + literate= + {á}{{\'a}}1 {é}{{\'e}}1 {í}{{\'i}}1 {ó}{{\'o}}1 {ú}{{\'u}}1 + {Á}{{\'A}}1 {É}{{\'E}}1 {Í}{{\'I}}1 {Ó}{{\'O}}1 {Ú}{{\'U}}1 + {à}{{\`a}}1 {è}{{\`e}}1 {ì}{{\`i}}1 {ò}{{\`o}}1 {ù}{{\`u}}1 + {À}{{\`A}}1 {È}{{\'E}}1 {Ì}{{\`I}}1 {Ò}{{\`O}}1 {Ù}{{\`U}}1 + {ä}{{\"a}}1 {ë}{{\"e}}1 {ï}{{\"i}}1 {ö}{{\"o}}1 {ü}{{\"u}}1 + {Ä}{{\"A}}1 {Ë}{{\"E}}1 {Ï}{{\"I}}1 {Ö}{{\"O}}1 {Ü}{{\"U}}1 + {â}{{\^a}}1 {ê}{{\^e}}1 {î}{{\^i}}1 {ô}{{\^o}}1 {û}{{\^u}}1 + {Â}{{\^A}}1 {Ê}{{\^E}}1 {Î}{{\^I}}1 {Ô}{{\^O}}1 {Û}{{\^U}}1 + {œ}{{\oe}}1 {Œ}{{\OE}}1 {æ}{{\ae}}1 {Æ}{{\AE}}1 {ß}{{\ss}}1 + {ç}{{\c c}}1 {Ç}{{\c C}}1 {ø}{{\o}}1 {å}{{\r a}}1 {Å}{{\r A}}1 + {€}{{\texteuro}}1 {£}{{\pounds}}1 {°}{{\degres}}1 + {’}{{\textquoteright}}1 {‘}{{\textquoteleft}}1 + {«}{{<<}}1 {»}{{>>}}1 + {—}{{---}}1 {−}{{$-$}}1 + {\^\^A}{{}}0 % verbatim in .dtx file +} + +\lstset{ + fancyvrb=true, + escapechar=`, + extendedchars=true, + fontadjust=true, + columns=fullflexible, + flexiblecolumns=true, + inputencoding=utf8, + keepspaces=true, + backgroundcolor=\color{bgcode}, + basicstyle=\mdseries\ttfamily, + keywordstyle=\color{keyword}, + stringstyle=\ttfamily\color{green!50!black}, + commentstyle=\color{comment}\itshape, + emphstyle=\bfseries\color{red}, + numbersep=5pt, + %numbers=left, + numberstyle=\tiny\emptyaccsupp, + showstringspaces=false, + upquote=true, + aboveskip=.5\parskip, + belowskip=.5\parskip, + framexleftmargin=1pt, + framexrightmargin=1pt, + gobble=2, % \lstlisting code in .dtx +} + +\lstdefinestyle{textsmall}{basicstyle=\color{black}\small\mdseries\ttfamily} +\lstdefinestyle{textfootnotesize}{basicstyle=\color{black}\footnotesize\mdseries\ttfamily} +\lstdefinestyle{textscriptsize}{basicstyle=\color{black}\scriptsize\mdseries\ttfamily} +\lstdefinestyle{texttiny}{basicstyle=\color{black}\tiny\mdseries\ttfamily} + +\lstdefinestyle{LaTeX}{ + language=[LaTeX]TeX, + moretexcs={ + Lab, + LabSet, + Qty, + QtySet, + colorlet, + coordinate, + countries, + country, + countryname, + definecolor, + draw, + endcountry, + fill, + foreach, + hashband, + hdist, + hwidth, + node, + nodename, + path, + sankeyadvance, + sankeydubins, + sankeyend, + sankeyend, + sankeyfork, + sankeynode, + sankeynodealias, + sankeynodeend, + sankeynodestart, + sankeyoutin, + sankeyset, + sankeystart, + sankeyturn, + sankeyturnleft, + sankeyturnleftbackward, + sankeyturnright, + sankeyturnrightbackward, + sisetup, + startcountry, + tikzset, + turnandstop, + usepackage, + vdist, + } +} +\lstdefinestyle{LaTeXsmall}{style=LaTeX,style=textsmall} +\lstdefinestyle{LaTeXfootnotesize}{style=LaTeX,style=textfootnotesize} +\lstdefinestyle{LaTeXscriptsize}{style=LaTeX,style=textscriptsize} +\lstdefinestyle{LaTeXtiny}{style=LaTeX,style=texttiny} + +\def\code{\lstinline[basicstyle=\mdseries\ttfamily\color{red!50!black}]} + +\edef\samplecodename{\jobname-code.vrb} + +\newcommand\constant[1]{\textcolor{violet}{\texttt{#1}}} +\newcommand\ARG[1]{\texttt{\{#1\}}} +\newcommand\OPTARG[1]{\textcolor{green!50!black}{\texttt{[#1]}}} +\newcommand\VAR[1]{\textit{\texttt{\ensuremath{\langle}#1\ensuremath{\rangle}}}} +\newcommand\NOTE[1]{\leavevmode\marginpar{#1}} + +\def\mynobreakpar{\par\nobreak\@afterheading} +\def\docprefix#1{\texttt{\textcolor{gray}{#1}}} +\def\sankeykeysprefix{/sankey} + +\newenvironment{sankeyoption}[5][]{% [prefix] key, val, default, initially + \begingroup + % + \def\keypath{#1}% + \def\key{#2}% + \def\val{#3}% + \def\default{#4}% + \def\initially{#5}% + %\setlength\parindent{\dimexpr.5\parindent\relax}% + % \vspace{.25\baselineskip plus .25\baselineskip minus 0mm} + \parfillskip 0pt plus 1fil% + \leavevmode% + \ttfamily% + \hspace*{-1cm}% + \textcolor{red!75!black}{\texttt{\docprefix{\ifdefempty{\keypath}{\sankeykeysprefix/}{\keypath/}}\key}}% + \ifdefempty{\val}{}{=\val}% + \hfill% + \ifdefempty{\default}{\null}{(default:\,\constant{\default})}% + \ifdefempty{\initially}{\null}{(initially:\,\constant{\initially})}% + \mynobreakpar% + \endgroup% + \parskip=.5\baselineskip plus .25\baselineskip minus .25\baselineskip + \parfillskip=30pt plus 1fil + \itemize[topsep=0pt,partopsep=0pt,itemsep=0pt]\item[] +}{% + \enditemize% +} + +\newcommand\MACRO{\hspace*{-1cm}} + +\newlist{sankeyconstantsdesc}{description}{1} +\setlist[sankeyconstantsdesc]{align=right,labelindent=1.5em,labelsep=.5em,leftmargin=!,font=\normalfont} + +\newlength{\myparskip} +\setlength{\myparskip}{.75\baselineskip plus 8\baselineskip minus .25\baselineskip} +\usepackage[skip=\myparskip]{parskip} +\newenvironment{miniblock}{% + \vspace{.5\parskip}% +}{% +} + +\tikzset{ + every picture/.style={ + execute at end picture={ + \begin{pgfonlayer}{background} + \node[fit=(current bounding box),inner sep=0](bb){}; + \def\rs{5mm} + \draw[gray!25] let + \p{sw}=(bb.south west), \p{ne}=(bb.north east), + \n{maxx}={ceil(\x{ne}/\rs)*\rs}, \n{minx}={floor(\x{sw}/\rs)*\rs}, + \n{maxy}={ceil(\y{ne}/\rs)*\rs}, \n{miny}={floor(\y{sw}/\rs)*\rs} + in (\n{minx},\n{miny}) grid (\n{maxx},\n{maxy}); + \begin{scope}[overlay] + \draw[gray!50,-latex] let + \p{sw}=(bb.south west), \p{ne}=(bb.north east), + \n{maxx}={ceil(\x{ne}/\rs)*\rs}, \n{minx}={floor(\x{sw}/\rs)*\rs}, + \n{maxy}={ceil(\y{ne}/\rs)*\rs}, \n{miny}={floor(\y{sw}/\rs)*\rs} + in (\n{minx},0) -- (\n{maxx}+1mm,0); + \draw[gray!50,-latex] let + \p{sw}=(bb.south west), \p{ne}=(bb.north east), + \n{maxx}={ceil(\x{ne}/\rs)*\rs}, \n{minx}={floor(\x{sw}/\rs)*\rs}, + \n{maxy}={ceil(\y{ne}/\rs)*\rs}, \n{miny}={floor(\y{sw}/\rs)*\rs} + in (0,\n{miny}) -- (0,\n{maxy}+1mm); + \end{scope} + \end{pgfonlayer} + } + } +} + +\def\MacroFont{ + \fontencoding\encodingdefault + \fontfamily\ttdefault + \fontseries\mddefault + \fontshape\shapedefault + \footnotesize% +} diff --git a/Master/texmf-dist/tex/latex/sankey/sankey.sty b/Master/texmf-dist/tex/latex/sankey/sankey.sty index 4c28a1fe0d4..b6734004f77 100644 --- a/Master/texmf-dist/tex/latex/sankey/sankey.sty +++ b/Master/texmf-dist/tex/latex/sankey/sankey.sty @@ -1,722 +1,811 @@ -% Copyright (C) 2016-2021 by Paul Gaborit -% -% This file may be distributed and/or modified -% -% 1. under the LaTeX Project Public License and/or -% -% 2. under the GNU Public License. - -\def\sankey@version{2.0} -\def\sankey@date{2021/01/27} -\ProvidesPackage{sankey}[\sankey@date\space\sankey@version\space sankey package] - +%% +%% This is file `sankey.sty', +%% generated with the docstrip utility. +%% +%% The original source files were: +%% +%% sankey.dtx (with options: `sankey') +%% +%% This is a generated file. +%% +%% Copyright (C) 2016, 2021 by Paul Gaborit +%% +%% This work may be distributed and/or modified under the conditions of the +%% LaTeX Project Public License, either version 1.3 of this license or (at +%% your option) any later version. The latest version of this license is +%% in +%% +%% <http://www.latex-project.org/lppl.txt> +%% +%% and version 1.3 or later is part of all distributions of LaTeX version +%% 2005/12/01 or later. +%% +%% This work has the LPPL maintenance status “maintained”. +%% +%% The Current Maintainer of this work is Paul Gaborit. +%% +%% This work consists of the files sankey.dtx, sankey.ins and the derived +%% files sankey.sty, tikzlibrarydubins.code.tex, sankey-doc-preamble.sty, +%% sankey-example1.tex, sankey-example2.tex, sankey-example3.tex, +%% sankey-example3-variation.tex, sankey-example4.tex, +%% sankey-example-energy.tex +%% +\NeedsTeXFormat{LaTeX2e}[2015/10/01] +\ProvidesPackage{sankey}[2021/03/14 v3.0 to draw Sankey diagrams] \RequirePackage{xparse} +\RequirePackage{etoolbox} \RequirePackage{xfp} \RequirePackage{tikz} -\usetikzlibrary{calc,decorations.markings,dubins} -\usepackage{etoolbox} - -% add a new layer to debug sankey diagrams +\usetikzlibrary{ + calc, + decorations.markings, + dubins +} +%% add a new layer to debug sankey diagrams \pgfdeclarelayer{background} \pgfdeclarelayer{foreground} \pgfdeclarelayer{sankeydebug} \pgfsetlayers{background,main,foreground,sankeydebug} - -% flag to debug sankey diagrams -\newtoggle{sankey debug} -\newtoggle{sankey node start} -\newtoggle{sankey node end} - -% macros to store and to retrieve the orientation and the quantity -% associated with each sankey node - -\def\sankeysetnodeqty#1#2{\expandafter\xdef\csname sankey@node@#1@qty\endcsname{#2}} - -\def\sankeygetnodeqty#1{% - \ifcsmacro{sankey@node@#1@qty}{% - \csname sankey@node@#1@qty\endcsname% - }{% - \PackageWarning{sankey}{Unknown sankey node '#1'}% - }% +\def\snk@newfield#1#2#3#4#5{ + % setter + \def#2##1##2{\expandafter#1\csname #4\endcsname{##2}} + % getter + \def#3##1{% + \ifcsdef{#4}{% + \csname#4\endcsname% + }{% + \PackageError{sankey}{#5}{unknown key with \string#3}% + }% + } } - -\def\sankeysetnodeorient#1#2{\expandafter\xdef\csname sankey@node@#1@orient\endcsname{#2}} - -\def\sankeygetnodeorient#1{% - \ifcsmacro{sankey@node@#1@orient}{% - \csname sankey@node@#1@orient\endcsname% - }{% - \PackageWarning{sankey}{Unknown sankey node '#1'}% - }% +\snk@newfield\xdef\snk@setnodeqty\sankeygetnodeqty% +{@snk@node@qty@#1}{Unknown sankey node '#1'} +\snk@newfield\xdef\snk@setnodeorient\sankeygetnodeorient% +{@snk@node@orient@#1}{Unknown sankey node '#1'} +\snk@newfield\def\snk@setstartfill\snk@getstartfill% +{@snk@start@fill@#1}{Unknown sankey start fill path #1} + +\snk@newfield\def\snk@setstartdraw\snk@getstartdraw% +{@snk@start@draw@#1}{Unknown sankey start draw path #1} +\snk@newfield\def\snk@setendfill\snk@getendfill% +{@snk@end@fill@#1}{Unknown sankey end fill path #1} + +\snk@newfield\def\snk@setenddraw\snk@getenddraw% +{@snk@end@draw@#1}{Unknown sankey end draw path #1} + +\newcommand\snk@ifnodedefined[3]{% + \ifcsdef{@snk@node@qty@#1}{#2}{#3}% +} +\newcommand\snk@errorifnotdefined[1]{% + \snk@ifnodedefined{#1}{}% + {\PackageError{sankey}{Unknown sankey node '#1'}{}}% } - -\def\sankeysetstartfill#1#2{\expandafter\gdef\csname sankey@start@fill@#1\endcsname{#2}} -\def\sankeysetstartdraw#1#2{\expandafter\gdef\csname sankey@start@draw@#1\endcsname{#2}} -\def\sankeysetendfill#1#2{\expandafter\gdef\csname sankey@end@fill@#1\endcsname{#2}} -\def\sankeysetenddraw#1#2{\expandafter\gdef\csname sankey@end@draw@#1\endcsname{#2}} -% -\def\sankeygetstartfill#1{\csname sankey@start@fill@#1\endcsname} -\def\sankeygetstartdraw#1{\csname sankey@start@draw@#1\endcsname} -\def\sankeygetendfill#1{\csname sankey@end@fill@#1\endcsname} -\def\sankeygetenddraw#1{\csname sankey@end@draw@#1\endcsname} - -% new shape \pgfdeclareshape{sankey node}{ \inheritsavedanchors[from=rectangle] \inheritanchor[from=rectangle]{center} - %\inheritanchorborder[from=rectangle] + \inheritanchorborder[from=rectangle] \anchor{left}{\pgf@process{\northeast}} \anchor{right}{\pgf@process{\southwest}} + % compatibility with 'fit' library + \inheritanchor[from=rectangle]{west} + \inheritanchor[from=rectangle]{east} + \inheritanchor[from=rectangle]{north} + \inheritanchor[from=rectangle]{south} + \inheritanchor[from=rectangle]{north west} + \inheritanchor[from=rectangle]{south east} + \inheritanchor[from=rectangle]{north east} + \inheritanchor[from=rectangle]{south west} } - -% pgfkeys family 'sankey' \pgfkeys{/sankey/.is family} - \NewDocumentCommand\sankeyset{m}{\pgfkeys{sankey,#1}} - \sankeyset{ + ratio quantity/.code={\edef\snk@totalqty{\fpeval{#1}}}, + ratio quantity/.value required, ratio length/.code={ - \pgfmathsetmacro\sankeytotallen{#1} - \edef\sankeytotallen{\sankeytotallen pt} + \pgfmathsetmacro\snk@totallen{#1} + \edef\snk@totallen{\snk@totallen pt} }, ratio length/.value required, - ratio quantity/.code={\edef\sankeytotalqty{\fpeval{#1}}}, - ratio quantity/.value required, ratio/.style args={#1/#2}{ ratio length=#1, ratio quantity=#2, }, ratio/.value required, - minimum radius/.estore in=\sankeyminradius, +} +\sankeyset{ + rotate/.code={\edef\snk@rotate{\fpeval{#1}}}, + rotate/.value required, +} +\sankeyset{ + minimum radius/.code={ + \pgfmathsetmacro\snk@minradius{#1} + \edef\snk@minradius{\snk@minradius pt} + }, minimum radius/.value required, - outin steps/.estore in=\sankeystepoutin, +} +\sankeyset{ + outin steps/.estore in=\snk@stepoutin, outon steps/.value required, - % +} +\newtoggle{sankey debug} +\sankeyset{ debug/.is choice, debug/true/.code={\toggletrue{sankey debug}}, debug/false/.code={\togglefalse{sankey debug}}, debug/.default=true, - % +} +\sankeyset{ start style/.is choice, - % end style/.is choice, - % default values - default parameters/.style={ - % default values + % to define new start and end styles + new start style/.code n args={3}{% name, fill path, draw path + \snk@setstartfill{#1}{#2} + \snk@setstartdraw{#1}{#3} + \sankeyset{start style/#1/.code={\def\snk@startstyle{#1}}} + }, + new end style/.code n args={3}{% name, fill path, draw path + \snk@setendfill{#1}{#2} + \snk@setenddraw{#1}{#3} + \sankeyset{end style/#1/.code={\def\snk@endstyle{#1}}} + }, +} +\sankeyset{ + debug color/.style={/utils/exec={\colorlet{debug color}{#1}}}, + @initial options/.style={ ratio=1cm/10, minimum radius=5mm,% outin steps=10, debug=false, start style=none, end style=none, - }, - % to make node - node parameters/.style={ - quantity/.code={% - %\typeout{quantity=##1}% - \edef\qty{\fpeval{##1}}% - %\typeout{qty=\qty}% - }, - quantity/.value required, - angle/.code={% - %\typeout{angle:##1}% - \pgfmathsetmacro\orient{##1}% + rotate=0, + % default fill/draw styles, + fill/.style={line width=0pt,fill=white}, + draw/.style={draw=black,line width=.4pt}, + % debug color used by all debug macros + debug color=red!75!black, + % debug line between left and right anchors + debug line/.style={overlay,draw=debug color,|-|}, + % debug line between center and label + debug normal/.style={overlay,draw=debug color}, + % debug node label + debug label/.style={ + overlay, + draw, + font=\ttfamily\tiny, + text=debug color,text opacity=1, + inner sep=.1em, + fill=white,fill opacity=1, + rounded corners=.1em, + node contents={\name}, }, - angle/.value required, - name/.store in=\name, - name/.value required, - at/.store in=\pos, - at/.value required, - as/.style={ - name=##1, - quantity=\sankeygetnodeqty{##1}, - angle=\sankeygetnodeorient{##1}, - at={##1.center}, - }, - as/.value required, - % - anchor/.is choice, - anchor/left/.code={\def\sankeyanchor{left}}, - anchor/right/.code={\def\sankeyanchor{right}}, - anchor/center/.code={\def\sankeyanchor{center}}, - anchor=center, - % - start/.is choice, - start/true/.code={\toggletrue{sankey node start}}, - start/false/.code={\togglefalse{sankey node start}}, - start/.default=true, - start=false, - % - end/.is choice, - end/true/.code={\toggletrue{sankey node end}}, - end/false/.code={\togglefalse{sankey node end}}, - end/.default=true, - end=false, + every node/.style={}, }, + every diagram/.style={}, } -% some styles -\sankeyset{ - node/.style={ - shape=sankey node, - inner sep=0,minimum height={\sankeyqtytolen{#1}}, - minimum width=0,draw=none,line width=0pt, - node contents={}, +\sankeyset{node parameters/.is family} +\sankeyset{node parameters, + name/.estore in=\name, + name/.value required, + quantity/.code={\edef\qty{\fpeval{#1}}}, + quantity/.value required, + angle/.code={\edef\orient{\snk@normalize@angle{#1}}}, + angle/.value required, + at/.code={\snk@getpos\pos{#1}}, + at/.value required, +} +\sankeyset{node parameters, + as/.style={ + name=#1, + quantity=\sankeygetnodeqty{#1}, + angle=\sankeygetnodeorient{#1}, + at={#1.center}, }, - fill/.style={line width=0pt,fill=white}, - draw/.style={draw=black,line width=.4pt}, - % debug color used by all debug macros - debug color/.style={/utils/exec={\colorlet{debug color}{#1}}}, - debug color=red!75!black, - % debug line between left and right anchors - debug line/.style={draw=debug color,|-|}, - % debug line between center and label - debug normal/.style={draw=debug color}, - % debug node label - debug label/.style={ - draw, - font=\ttfamily\tiny, - text=debug color,text opacity=1, - inner sep=.1em, - fill=white,fill opacity=1, - rounded corners=.1em, + as/.value required, +} +\sankeyset{node parameters, + anchor/.is choice, + anchor/left/.code={\def\snk@anchor{left}}, + anchor/right/.code={\def\snk@anchor{right}}, + anchor/center/.code={\def\snk@anchor{center}}, + anchor/.value required, +} +\newtoggle{sankey node start} +\newtoggle{sankey node end} +\sankeyset{node parameters, + start/.is choice, + start/true/.code={\toggletrue{sankey node start}}, + start/false/.code={\togglefalse{sankey node start}}, + start/.default=true, + % + end/.is choice, + end/true/.code={\toggletrue{sankey node end}}, + end/false/.code={\togglefalse{sankey node end}}, + end/.default=true, +} +\sankeyset{node parameters, + forked/.estore in=\snk@listofforks, + forked/.value required, + fork anchor/.estore in=\snk@forkanchor, + fork anchor/.value required, +} +\sankeyset{node parameters, + @initial parameters/.style={ + start=false, + end=false, + forked=, + fork anchor=, + anchor=center, + at={0,0}, + angle=0, }, } - \sankeyset{ - new start style/.code n args={3}{% name, fill path, draw path - \sankeysetstartfill{#1}{#2} - \sankeysetstartdraw{#1}{#3} - \sankeyset{start style/#1/.code={\def\sankeystartstyle{#1}}} - }, - new end style/.code n args={3}{% name, fill path, draw path - \sankeysetendfill{#1}{#2} - \sankeysetenddraw{#1}{#3} - \sankeyset{end style/#1/.code={\def\sankeyendstyle{#1}}} + % sankey node TikZ style + @sankey node/.style n args={3}{% name, pos, anchor + shape=sankey node, + inner sep=0, + minimum height={\sankeyqtytolen{\sankeygetnodeqty{#1}}}, + minimum width=0, + draw=none, + line width=0pt, + fill=none, + node contents={}, + rotate=\sankeygetnodeorient{#1}+\snk@rotate, + at={(#2)}, + name=#1, + anchor=#3, }, } - -% the new 'sankeydiagram' environment -\NewDocumentEnvironment{sankeydiagram}{O{}+b}{ - - \newcommand\sankeyarc[2]{% sn, en - \begingroup - \pgfmathsetmacro\startangle{\sankeygetnodeorient{##1}} - \pgfmathsetmacro\endangle{\sankeygetnodeorient{##2}} - \pgfmathsetmacro\rotateangle{\endangle-\startangle} - \pgfmathtruncatemacro\acwrotate{\rotateangle>0?1:0} - \path let - \p1=(##1.left),\p2=(##1.right), - \p3=(##2.left),\p4=(##2.right), - \n1={\sankeyqtytolen{\sankeygetnodeqty{##1}}}, - \n{maxr}={\sankeyminradius+\n1}, - \n{minr}={\sankeyminradius} - in \pgfextra{ - \ifnumequal{\acwrotate}{1}{ - \begin{pgfinterruptpath} - % fill the region - \path[/sankey/fill] - (\p1) arc(\startangle-90:\endangle-90:\n{minr}) -- (\p3) -- - (\p4) arc(\endangle-90:\startangle-90:\n{maxr}) -- (\p2) -- cycle; - % draw left and right borders - \path[/sankey/draw] - (\p1) arc(\startangle-90:\endangle-90:\n{minr}) - (\p4) arc(\endangle-90:\startangle-90:\n{maxr}); - \end{pgfinterruptpath} - }{ - \begin{pgfinterruptpath} - % fill the region - \path[/sankey/fill] - (\p1) arc(\startangle+90:\endangle+90:\n{maxr}) -- (\p3) -- - (\p4) arc(\endangle+90:\startangle+90:\n{minr}) -- (\p2) -- cycle; - % draw left and right borders - \path[/sankey/draw] - (\p1) arc(\startangle+90:\endangle+90:\n{maxr}) - (\p4) arc(\endangle+90:\startangle+90:\n{minr}); - \end{pgfinterruptpath} - } - }; - \endgroup +\NewDocumentEnvironment{sankeydiagram}{O{}}{ + \def\snk@getpos##1##2{% + \tikz@scan@one@point\pgfutil@firstofone(##2)\relax% + \edef##1{\the\pgf@x,\the\pgf@y}% } - - \newcommand\sankeymakenodenodebug{ - \begingroup - \sankeysetnodeqty{\name}{\qty} - \sankeysetnodeorient{\name}{\orient} - % \typeout{\qty,\orient} - \ifundef{\sankeyanchor}{\def\sankeyanchor{center}}{} - \node[/sankey/node=\qty,rotate=\orient,at/.expanded={(\pos)},name=\name,anchor=\sankeyanchor]; - \endgroup + \def\snk@modulo##1##2{\fpeval{##1-(floor((##1)/(##2),0)*##2)}} + \def\snk@normalize@angle##1{% + \fpeval{\snk@modulo{(##1)+180}{360}-180}% } - - \newcommand\sankeymakenode{ - \begingroup - \sankeymakenodenodebug{} + \def\snk@show@debug##1{% node name \iftoggle{sankey debug}{ + \begingroup + \edef\name{##1} + \edef\qty{\sankeygetnodeqty{\name}} + \edef\orient{\sankeygetnodeorient{\name}} \begin{pgfonlayer}{sankeydebug} - \pgfset{ - number format/relative*=-1, - number format/precision=1, - number format/fixed, - } \path[/sankey/debug line] (\name.left) -- (\name.right); - \pgfmathsetmacro{\len}{\sankeyqtytolen{\qty}/3} + \pgfmathsetmacro{\snk@len}{\sankeyqtytolen{\qty}/3} \path[/sankey/debug normal] (\name.center) - -- ($(\name.center)!\len pt!90:(\name.right)$) - node[/sankey/debug label,rotate=\orient+90,anchor=north] {\name:\pgfmathprintnumber{\qty}}; + -- ($(\name.center)!\snk@len pt!90:(\name.right)$) + node[/sankey/debug label,rotate=\orient+90+\snk@rotate,anchor=north]; \end{pgfonlayer} + \endgroup }{} + } + \def\snk@makeforkednode{ + \begingroup + \ifdefempty{\snk@listofforks}{ + \ifdefempty{\snk@forkanchor}{}{ + \PackageWarning{sankey}% + {Can't use 'fork anchor' key without 'forked' key} + } + }{ + \def\snk@tot{0} + \def\snk@added@values{} + \sankeyset{ + @add forked node/.code args={####1/####2}{ + \coordinate (####2) at ($(\name.left)% + !\fpeval{(\snk@tot+.5*(####1))/\qty}% + !(\name.right)$); + \edef\snk@orient{\orient} + \sankeynode[debug=false] + {name=####2,quantity=####1,at=####2,angle=\snk@orient} + \edef\snk@tot{\fpeval{\snk@tot+####1}} + \edef\snk@added@values{\snk@added@values+####1} + }, + @add forked node/.list/.expand once=\snk@listofforks, + } + \edef\snk@diff{\fpeval{abs(\qty-\snk@tot)}} + \ifnumequal{\snk@diff}{0}{}{ + \PackageWarning{sankey}% + {^^J*** Warning: bad sankey fork: % + \qty\space!=\space\snk@added@values(=\snk@tot)% + ^^J\snk@listofforks} + } + \ifdefempty{\snk@forkanchor}{ + \edef\snk@forkanchor{\name.\snk@anchor} + }{} + \snk@getpos\snk@c{$(\snk@forkanchor) - (\pos)$} + \sankeynode{as=\name,at={$(\name) - (\snk@c)$}} + \foreach \snk@subnodeqty/\snk@subnodename in \snk@listofforks { + \sankeynode{as=\snk@subnodename,at={$(\snk@subnodename) - (\snk@c)$}} + } + } \endgroup } - - \newcommand\sankeynodenodebug[1]{ + \def\snk@makenode{ \begingroup - \sankeyset{node parameters,##1} - %\typeout{sankeynodenodebug: '\name' at(\pos) angle(\orient) qty(\qty)} - \sankeymakenodenodebug{} + \snk@setnodeqty{\name}{\qty} + \edef\orient{\snk@normalize@angle{\orient}} + \snk@setnodeorient{\name}{\orient} + \ifundef{\snk@anchor}{\def\snk@anchor{center}}{} + \node[/sankey/@sankey node={\name}{\pos}{\snk@anchor}]; \endgroup } - - % ============================================================ - % user commands - % ============================================================ - - \NewDocumentCommand\sankeydubins{O{}mm}{% options, sn, en + \def\snk@filldrawstart{ + \begin{scope}[shift={(\name)},rotate=\orient] + \path[/sankey/fill] \snk@getstartfill{\snk@startstyle}; + \path[/sankey/draw] \snk@getstartdraw{\snk@startstyle}; + \end{scope} + } + \def\snk@filldrawend{ + \begin{scope}[shift={(\name)},rotate=\sankeygetnodeorient{\name}] + \path[/sankey/fill] \snk@getendfill{\snk@endstyle}; + \path[/sankey/draw] \snk@getenddraw{\snk@endstyle}; + \end{scope} + } + \def\snk@checkquantities##1##2##3{ \begingroup - \sankeyset{##1} - \pgfmathsetmacro\startangle{\sankeygetnodeorient{##2}} - \pgfmathsetmacro\endangle{\sankeygetnodeorient{##3}} - \edef\sqty{\sankeygetnodeqty{##2}} - \edef\eqty{\sankeygetnodeqty{##3}} - \ifdefstrequal{\sqty}{\eqty}{}{ + \edef\snk@qtyi{\sankeygetnodeqty{##1}} + \edef\snk@qtyii{\sankeygetnodeqty{##2}} + \ifdefstrequal{\snk@qtyi}{\snk@qtyii}{}{ \PackageError{sankey}% - {^^J*** \string\sankeyoutin: quantities differ between ##2 (\sqty) and ##3 (\eqty)^^J}% + {^^J*** \string##3: quantities differ between % + ##1 (\snk@qtyi) and ##2 (\snk@qtyii)% + ^^J}% {The quantities of the two Sankey nodes must be equal.} } + \endgroup + } + \NewDocumentCommand\sankeydubins{O{}mm}{% options, sn, en + \snk@errorifnotdefined{##2} + \snk@errorifnotdefined{##3} + \snk@checkquantities{##2}{##3}{\sankeydubins} + \begingroup + \sankeyset{##1} \pgfmathsetmacro\qty{\sankeygetnodeqty{##2}} - \pgfmathsetmacro\width{\sankeyqtytolen{\qty}} - %\typeout{startangle:\startangle,endangle:\endangle,qty:\qty,width:\width} \dubinspathset{ sankey/.style={ - start point=##2.center,start angle=\startangle, - end point=##3.center,end angle=\endangle, - minimum radius=\sankeyminradius + .5 * \width pt, + start point=##2.center,start angle=\sankeygetnodeorient{##2}, + end point=##3.center,end angle=\sankeygetnodeorient{##3}, + minimum radius=\snk@minradius + .5 * \sankeyqtytolen{\qty} pt, }, } \dubinspathcalc{sankey,store=sankey} - \dubinspathset{ left border/.style={ sankey, use store=sankey, - left and right minimum radii= - {\sankeyminradius} and {\sankeyminradius + \width pt}, + left and right minimum radii={\snk@minradius} + and {\snk@minradius + \sankeyqtytolen{\qty} pt}, }, right border/.style={ sankey, use store=sankey, left and right minimum radii= - {\sankeyminradius + \width pt} and {\sankeyminradius}, + {\snk@minradius + \sankeyqtytolen{\qty} pt} + and {\snk@minradius}, }, } - - \path let - \p1=(##2.left),\p2=(##2.right), - \p3=(##3.left),\p4=(##3.right) - in \pgfextra{ - \begin{pgfinterruptpath} - % fill the region - \path[/sankey/fill] - (\p1) - \dubinspath{left border} - -- (\p3) -- - (\p4) \dubinspath{right border,reverse} - -- (\p2) -- cycle; - - % draw left and right borders - \path[/sankey/draw] - (\p1) - \dubinspath{left border} - (\p2) - \dubinspath{right border} - ; - \end{pgfinterruptpath} - }; + % fill the region + \path[/sankey/fill] (##2.left) \dubinspath{left border} + -- (##3.left) -- (##3.right) \dubinspath{right border,reverse} + -- (##2.right) -- cycle; + % draw left and right borders + \path[/sankey/draw] (##2.left) \dubinspath{left border} + (##2.right) \dubinspath{right border}; \endgroup } - - \NewDocumentCommand\sankeyoutin{O{}mm}{% options, sn, en + \snk@errorifnotdefined{##2} + \snk@errorifnotdefined{##3} + \snk@checkquantities{##2}{##3}{\sankeyoutin} \begingroup \sankeyset{##1} - \edef\sn{##2} - \edef\en{##3} - \edef\sqty{\sankeygetnodeqty{\sn}} - \edef\eqty{\sankeygetnodeqty{\en}} - \ifdefstrequal{\sqty}{\eqty}{}{ - \PackageError{sankey}% - {^^J*** \string\sankeyoutin: quantities differ between \sn (\sqty) and \en (\eqty)^^J}% - {The quantities of the two Sankey nodes must be equal.} - } - %\typeout{*** sankeyoutin: \sn\space to \en\space (\sankeystepoutin)} - \pgfmathsetmacro\qty{\sankeygetnodeqty{\sn}} - \pgfmathsetmacro\mylength{\sankeyqtytolen{\qty}/2} - \pgfmathsetmacro\mystep{1/\sankeystepoutin} - %\typeout{*** a} - \pgfmathsetmacro\mybound{1-.5*\mystep} - %\typeout{*** b} - \pgfmathsetmacro\laststep{int(\sankeystepoutin-1)} - %\typeout{sankeystepoutin(\sankeystepoutin) mystep(\mystep) mybound(\mybound) laststep(\laststep)} - %\typeout{*** sankeyoutin: \startangle to \endangle} - \path[decorate,overlay,decoration={ + \edef\qty{\sankeygetnodeqty{##2}} + \pgfmathsetmacro\snk@len{\sankeyqtytolen{\qty}/2} + \edef\snk@step{\fpeval{1/\snk@stepoutin}} + \edef\snk@laststep{\inteval{\snk@stepoutin-1}} + \path[overlay,decorate,decoration={ markings, - mark=between positions \mystep and \mybound step \mystep with { - \def\sankeyoutinmidptname{sankeyoutinmidpt \pgfkeysvalueof{/pgf/decoration/mark info/sequence number}} + mark=between positions \snk@step and {\fpeval{1-.5*\snk@step}} + step \snk@step with { + \edef\snk@outinmidptname{% + snk@outinmidpt-% + \pgfkeysvalueof{/pgf/decoration/mark info/sequence number}% + } \path - (0,0) coordinate(\sankeyoutinmidptname) - (0,-\mylength pt) coordinate (\sankeyoutinmidptname\space r) - (0,\mylength pt) coordinate (\sankeyoutinmidptname\space l) + (0,0) coordinate(\snk@outinmidptname) + (0,-\snk@len pt) coordinate (\snk@outinmidptname-r) + (0,\snk@len pt) coordinate (\snk@outinmidptname-l) ; } - }](\sn.center) to[out=\sankeygetnodeorient{\sn},in=\sankeygetnodeorient{\en}+180] (\en.center); - \foreach \myptnum in {1,...,\laststep}{ - \def\sankeyoutinmidptname{sankeyoutinmidpt \myptnum} - \anglebetween\sankeyoutinmidptangle{\sankeyoutinmidptname\space r}{\sankeyoutinmidptname\space l} - \sankeynodenodebug{quantity=\qty,angle=\sankeyoutinmidptangle-90,name=\sankeyoutinmidptname,at=\sankeyoutinmidptname} + }] + (##2.center) + to[out=\sankeygetnodeorient{##2},in=\sankeygetnodeorient{##3}+180] + (##3.center); + \foreach \snk@ptnum in {1,...,\snk@laststep}{ + \edef\snk@outinmidptname{snk@outinmidpt-\snk@ptnum} + \dbp@anglebetween\snk@outinmidptangle% + {\snk@outinmidptname-r}{\snk@outinmidptname-l} + \sankeynode[debug=false]{% + name=\snk@outinmidptname, + quantity=\qty, + angle=\snk@outinmidptangle-90,% + at=\snk@outinmidptname% + } + } + \sankeynode[debug=false]{% + name={snk@outinmidpt-0}, + quantity=\sankeygetnodeqty{##2}, + angle=\sankeygetnodeorient{##2},% + at={##2}% + } + \sankeynode[debug=false]{% + name={snk@outinmidpt-\snk@stepoutin}, + quantity={\sankeygetnodeqty{##3}}, + angle={\sankeygetnodeorient{##3}},% + at={##3}% } - \sankeynodenodebug{quantity=\sankeygetnodeqty{\sn},angle=\sankeygetnodeorient{\sn},name={sankeyoutinmidpt 0},at={\sn}} - \sankeynodenodebug{quantity={\sankeygetnodeqty{\en}},angle={\sankeygetnodeorient{\en}},name={sankeyoutinmidpt \sankeystepoutin},at={\en}} - - %\typeout{*********************} \path[/sankey/fill,looseness=1] - (sankeyoutinmidpt 0.left) - \foreach \curpt[remember=\curpt as \prevpt (initially 0)] in {1,...,\sankeystepoutin}{ - to[out=\sankeygetnodeorient{sankeyoutinmidpt \prevpt},in=\sankeygetnodeorient{sankeyoutinmidpt \curpt}+180] - (sankeyoutinmidpt \curpt.left) + (snk@outinmidpt-0.left) + \foreach \snk@curpt + [remember=\snk@curpt as \snk@prevpt (initially 0)] + in {1,...,\snk@stepoutin}{ + to[out=\sankeygetnodeorient{snk@outinmidpt-\snk@prevpt}, + in=\sankeygetnodeorient{snk@outinmidpt-\snk@curpt}+180] + (snk@outinmidpt-\snk@curpt.left) } -- - (sankeyoutinmidpt \sankeystepoutin.right) - \foreach \curpt[remember=\curpt as \prevpt (initially \sankeystepoutin)] in {\laststep,...,0}{ - to[out=\sankeygetnodeorient{sankeyoutinmidpt \prevpt}+180,in=\sankeygetnodeorient{sankeyoutinmidpt \curpt}] - (sankeyoutinmidpt \curpt.right) + (snk@outinmidpt-\snk@stepoutin.right) + \foreach \snk@curpt + [remember=\snk@curpt as \snk@prevpt (initially \snk@stepoutin)] + in {\snk@laststep,...,0}{ + to[out=\sankeygetnodeorient{snk@outinmidpt-\snk@prevpt}+180, + in=\sankeygetnodeorient{snk@outinmidpt-\snk@curpt}] + (snk@outinmidpt-\snk@curpt.right) } -- cycle; - \path[/sankey/draw,looseness=1] - (sankeyoutinmidpt 0.left) - \foreach \curpt[remember=\curpt as \prevpt (initially 0)] in {1,...,\sankeystepoutin}{ - to[out=\sankeygetnodeorient{sankeyoutinmidpt \prevpt},in=\sankeygetnodeorient{sankeyoutinmidpt \curpt}+180] - (sankeyoutinmidpt \curpt.left) - } - % - (sankeyoutinmidpt \sankeystepoutin.right) - \foreach \curpt[remember=\curpt as \prevpt (initially \sankeystepoutin)] in {\laststep,...,0}{ - to[out=\sankeygetnodeorient{sankeyoutinmidpt \prevpt}+180,in=\sankeygetnodeorient{sankeyoutinmidpt \curpt}] - (sankeyoutinmidpt \curpt.right) + (snk@outinmidpt-0.left) + \foreach \snk@curpt + [remember=\snk@curpt as \snk@prevpt (initially 0)] + in {1,...,\snk@stepoutin}{ + to[out=\sankeygetnodeorient{snk@outinmidpt-\snk@prevpt}, + in=\sankeygetnodeorient{snk@outinmidpt-\snk@curpt}+180] + (snk@outinmidpt-\snk@curpt.left) } - ; - + (snk@outinmidpt-\snk@stepoutin.right) + \foreach \snk@curpt + [remember=\snk@curpt as \snk@prevpt (initially \snk@stepoutin)] + in {\snk@laststep,...,0}{ + to[out=\sankeygetnodeorient{snk@outinmidpt-\snk@prevpt}+180, + in=\sankeygetnodeorient{snk@outinmidpt-\snk@curpt}] + (snk@outinmidpt-\snk@curpt.right) + }; \endgroup } - \NewDocumentCommand\sankeynodealias{mm}{%name, alias - \path [late options={name=##1,alias=##2}]; - \sankeysetnodeqty{##2}{\sankeygetnodeqty{##1}} - \sankeysetnodeorient{##2}{\sankeygetnodeorient{##1}} + \snk@errorifnotdefined{##1} + \path[late options={name=##1,alias=##2}]; + \snk@setnodeqty{##2}{\sankeygetnodeqty{##1}} + \snk@setnodeorient{##2}{\sankeygetnodeorient{##1}} } - - \newcommand\sankeynode[2][]{ + \NewDocumentCommand\sankeynode{O{}m}{% options, node parameters \begingroup \sankeyset{##1} - \sankeyset{node parameters,##2} - %\typeout{sankeynode: '\name' at(\pos) angle(\orient) qty(\qty)} - \sankeymakenode{} + \sankeyset{node parameters,@initial parameters,/sankey/every node,##2} + \snk@makenode{} + \snk@makeforkednode{} + \iftoggle{sankey node start}{\snk@filldrawstart}{} + \iftoggle{sankey node end}{\snk@filldrawend}{} + \snk@show@debug{\name} \endgroup } - - \def\sankeyfilldrawstart{ - \begin{scope}[shift={(\name)},rotate=\orient] - \path[/sankey/fill] \sankeygetstartfill{\sankeystartstyle}; - \path[/sankey/draw] \sankeygetstartdraw{\sankeystartstyle}; - \end{scope} - } - - \NewDocumentCommand\sankeystart{O{}m}{ + \NewDocumentCommand\sankeystart{O{}m}{% options, name + \snk@errorifnotdefined{##2} \begingroup \sankeyset{##1} \edef\name{##2} \edef\orient{\sankeygetnodeorient{##2}} \edef\qty{\sankeygetnodeqty{##2}} - \sankeyfilldrawstart + \snk@filldrawstart \endgroup } - - \NewDocumentCommand\sankeynodestart{O{}m}{ - \begingroup - %\typeout{sankeynodestart: ##2} - \sankeyset{##1} - \sankeyset{node parameters,##2} - %\typeout{sankeynodestart: '\name' at(\pos) angle(\orient) qty(\qty)} - \sankeymakenode{} - %\typeout{sankeynodestart: sankeynode ok} - %\typeout{sankeynodestart: '\name' at(\pos) angle(\orient) qty(\qty)} - \sankeyfilldrawstart - \endgroup + \NewDocumentCommand\sankeynodestart{O{}m}{% option, node parameters + \sankeynode[##1]{start,##2} } - - \def\sankeyfilldrawend{ - \begin{scope}[shift={(\name)},rotate=\sankeygetnodeorient{\name}] - \path[/sankey/fill] \sankeygetendfill{\sankeyendstyle}; - \path[/sankey/draw] \sankeygetenddraw{\sankeyendstyle}; - \end{scope} - } - - \NewDocumentCommand\sankeyend{O{}m}{%name + \NewDocumentCommand\sankeyend{O{}m}{%options, name + \snk@errorifnotdefined{##2} \begingroup \sankeyset{##1} \edef\name{##2} \edef\orient{\sankeygetnodeorient{##2}} \edef\qty{\sankeygetnodeqty{##2}} - \sankeyfilldrawend + \snk@filldrawend \endgroup } - - \NewDocumentCommand\sankeynodeend{O{}m}{ - \begingroup - %\typeout{sankeynodestart: ##2} - \sankeyset{##1} - \sankeyset{node parameters,##2} - %\typeout{sankeynodestart: '\name' at(\pos) angle(\orient) qty(\qty)} - \sankeymakenode{} - %\typeout{sankeynodestart: sankeynode ok} - %\typeout{sankeynodestart: '\name' at(\pos) angle(\orient) qty(\qty)} - \sankeyfilldrawend - \endgroup + \NewDocumentCommand\sankeynodeend{O{}m}{% options, node parameters + \sankeynode[##1]{end,##2} } - - - - \NewDocumentCommand\sankeyadvance{sO{}mm}{% *(reverse), options, name, distance + \NewDocumentCommand\sankeyadvance{sO{}mm}{% + %params: *(reverse), options, name, distance + \snk@errorifnotdefined{##3} \begingroup \sankeyset{##2} - \def\newname{##3} - \def\oldname{##3-old} - \sankeynodealias{\newname}{\oldname} - % \typeout{*** sankeyadvance: ok (\oldname => \newname)} + \edef\name{##3} + \edef\snk@oldname{##3-old} + \sankeynodealias{\name}{\snk@oldname} \IfBooleanTF{##1}{ - % reverse advance + % move backward \sankeynode{ - at={$(\oldname.center)!##4!90:(\oldname.left)$}, - angle=\sankeygetnodeorient{\oldname}, - quantity=\sankeygetnodeqty{\oldname}, - name=\newname, + at={$(\snk@oldname.center)!##4!90:(\snk@oldname.left)$}, + angle=\sankeygetnodeorient{\snk@oldname}, + quantity=\sankeygetnodeqty{\snk@oldname}, + name=\name, } \path[/sankey/fill] - (\newname.left) -- (\oldname.left) - -- - (\oldname.right) -- (\newname.right) - -- cycle; + (\name.left) -- (\snk@oldname.left) + -- (\snk@oldname.right) -- (\name.right) -- cycle; \path[/sankey/draw] - (\newname.left) -- (\oldname.left) - (\oldname.right) -- (\newname.right); - \endgroup + (\name.left) -- (\snk@oldname.left) + (\snk@oldname.right) -- (\name.right); }{ - % advance + % move forward \sankeynode{ - at={$(\oldname.center)!##4!-90:(\oldname.left)$}, - angle=\sankeygetnodeorient{\oldname}, - quantity=\sankeygetnodeqty{\oldname}, - name=\newname, + at={$(\snk@oldname.center)!##4!-90:(\snk@oldname.left)$}, + angle=\sankeygetnodeorient{\snk@oldname}, + quantity=\sankeygetnodeqty{\snk@oldname}, + name=\name, } \path[/sankey/fill] - (\oldname.left) -- (\newname.left) - -- - (\newname.right) -- (\oldname.right) - -- cycle; + (\snk@oldname.left) -- (\name.left) + -- (\name.right) -- (\snk@oldname.right) -- cycle; \path[/sankey/draw] - (\oldname.left) -- (\newname.left) - (\newname.right) -- (\oldname.right); - \endgroup + (\snk@oldname.left) -- (\name.left) + (\name.right) -- (\snk@oldname.right); } + \snk@show@debug{\name} + \endgroup } - - \NewDocumentCommand\sankeyturn{sO{}mm}{% *(reverse), options, name, angle + \NewDocumentCommand\sankeyturnright{sO{}mm}{ + % *(reverse), options, name, angle + \snk@errorifnotdefined{##3} \begingroup - \sankeyset{##2} - \def\name{##3} - \def\oldname{##3-old} - \sankeynodealias{\name}{\oldname} - \pgfmathsetmacro\qty{\sankeygetnodeqty{\oldname}} - \pgfmathsetmacro\oldangle{\sankeygetnodeorient{\oldname}} - \IfBooleanTF{##1}{ - % turn in reverse - \pgfmathsetmacro\orient{\oldangle-##4} - % \typeout{TURN: \oldangle=>\orient} - \ifnumgreater{##4}{0}{% anti-clockwise turn - \path let - \p1=(##3.left), \p2=(##3.right), - % center of rotation - \p{c}=($(\p1)!-\sankeyminradius!(\p2)$), - % starting position - \p{s}=(##3.center), - % ending position - \p{e}=($(\p{c})!1!-##4:(\p{s})$) - in \pgfextra{ - \begin{pgfinterruptpath} - % \typeout{acw turn:\qty:\orient} - \def\pos{\p{e}} - \sankeymakenode{} - \sankeyarc{\name}{\oldname} - \end{pgfinterruptpath} - }; - }{ % clockwise turn - \path let - \p1=(##3.right), \p2=(##3.left), - % center of rotation - \p{c}=($(\p1)!-\sankeyminradius!(\p2)$), - % starting position - \p{s}=(##3.center), - % ending position - \p{e}=($(\p{c})!1!-##4:(\p{s})$) - in \pgfextra{ - % \typeout{cw turn:\qty:\orient} - \begin{pgfinterruptpath} - \def\pos{\p{e}} - \sankeymakenode{} - \sankeyarc{\name}{\oldname} - \end{pgfinterruptpath} - }; - } + \IfBooleanTF{##1} + {\edef\snk@angle{\fpeval{-1*##4}}} + {\edef\snk@angle{\fpeval{1*##4}}} + \edef\snk@anglesign{\fpeval{sign(\snk@angle)}} + \ifnumgreater{\snk@anglesign}{-1}{ + \sankeyset{##2} + \edef\name{##3} + \edef\snk@oldname{##3-old} + \sankeynodealias{\name}{\snk@oldname} + \edef\qty{\sankeygetnodeqty{\name}} + \edef\orient{\snk@normalize@angle{\sankeygetnodeorient{\name}-\snk@angle}} + \snk@getpos\snk@c{$(\name.right)!-\snk@minradius!(\name.left)$} + \snk@getpos\pos{$(\snk@c)!1!-\snk@angle:(\name.center)$} + \snk@makenode{} + % fill the region + \path[/sankey/fill] let + \p1=(\snk@oldname.left),\p2=(\snk@oldname.right), + \p3=(\name.left),\p4=(\name.right), + \n1={\sankeyqtytolen{\qty}}, + \n{maxr}={\snk@minradius+\n1}, + \n{minr}={\snk@minradius} + in + (\p1) arc(\orient+\snk@angle+90:\orient+90:\n{maxr}) -- (\p3) -- + (\p4) arc(\orient+90:\orient+\snk@angle+90:\n{minr}) -- (\p2) -- cycle; + % draw left and right borders + \path[/sankey/draw] let + \p1=(\snk@oldname.left),\p2=(\snk@oldname.right), + \p3=(\name.left),\p4=(\name.right), + \n1={\sankeyqtytolen{\qty}}, + \n{maxr}={\snk@minradius+\n1}, + \n{minr}={\snk@minradius} + in + (\p1) arc(\orient+\snk@angle+90:\orient+90:\n{maxr}) + (\p4) arc(\orient+90:\orient+\snk@angle+90:\n{minr}); + \snk@show@debug{\name} }{ - % turn - \pgfmathsetmacro\orient{\oldangle+##4} - % \typeout{TURN: \oldangle=>\orient} - \ifnumgreater{##4}{0}{% anti-clockwise turn - \path let - \p1=(##3.left), \p2=(##3.right), - % center of rotation - \p{c}=($(\p1)!-\sankeyminradius!(\p2)$), - % starting position - \p{s}=(##3.center), - % ending position - \p{e}=($(\p{c})!1!##4:(\p{s})$) - in \pgfextra{ - \begin{pgfinterruptpath} - % \typeout{acw turn:\qty:\orient} - \def\pos{\p{e}} - \sankeymakenode{} - \sankeyarc{\oldname}{\name} - \end{pgfinterruptpath} - }; - }{ % clockwise turn - \path let - \p1=(##3.right), \p2=(##3.left), - % center of rotation - \p{c}=($(\p1)!-\sankeyminradius!(\p2)$), - % starting position - \p{s}=(##3.center), - % ending position - \p{e}=($(\p{c})!1!##4:(\p{s})$) - in \pgfextra{ - % \typeout{cw turn:\qty:\orient} - \begin{pgfinterruptpath} - \def\pos{\p{e}} - \sankeymakenode{} - \sankeyarc{\oldname}{\name} - \end{pgfinterruptpath} - }; - } + \sankeyturnrightbackward[##2]{##3}{-1*\snk@angle} } \endgroup } - - \NewDocumentCommand\sankeyfork{mm}{%name,list of forks - \def\listofforks{##2} - \xdef\sankeytot{0} - \xdef\sankeycalculus{0} - \pgfmathsetmacro\iqty{\sankeygetnodeqty{##1}} - \pgfmathsetmacro\iorient{\sankeygetnodeorient{##1}} - \pgfmathsetmacro\orient{\iorient} - %\typeout{iname:##1, iqty:\iqty,iorient:\iorient} - \foreach \qty/\name[count=\c] in \listofforks { - %\typeout{sankeyfork foreach: qty(\qty) name(\name) count(\c)} - \path - let - \p1=(##1.left),\p2=(##1.right), - \p{start}=($(\p1)!\fpeval{\sankeytot/\iqty}!(\p2)$), - \n{nexttot}={\fpeval{\sankeytot+\qty}}, - \p{end}=($(\p1)!\fpeval{\n{nexttot}/\iqty}!(\p2)$), - \p{mid}=($(\p{start})!.5!(\p{end})$) - in \pgfextra{ - %\typeout{new fork:\name} - %\typeout{qty:\qty,name:\name,count:\c,pos=\p{mid}} - \xdef\sankeytot{\n{nexttot}} - \xdef\sankeycalculus{\fpeval{\sankeycalculus+\qty}} - \begin{pgfinterruptpath} - \def\pos{\p{mid}} - \sankeymakenode{} - \end{pgfinterruptpath} - }; + \NewDocumentCommand\sankeyturnrightbackward{sO{}mm}{ + % *(reverse), options, name, angle + \snk@errorifnotdefined{##3} + \begingroup + \IfBooleanTF{##1} + {\edef\snk@angle{\fpeval{-1*##4}}} + {\edef\snk@angle{\fpeval{1*##4}}} + \edef\snk@anglesign{\fpeval{sign(\snk@angle)}} + \ifnumgreater{\snk@anglesign}{-1}{ + \sankeyset{##2} + \edef\name{##3} + \edef\snk@oldname{##3-old} + \sankeynodealias{\name}{\snk@oldname} + \edef\qty{\sankeygetnodeqty{\name}} + \edef\orient{\snk@normalize@angle{\sankeygetnodeorient{\name}+\snk@angle}} + \snk@getpos\snk@c{$(\name.right)!-\snk@minradius!(\name.left)$} + \snk@getpos\pos{$(\snk@c)!1!\snk@angle:(\name.center)$} + \snk@makenode{} + % fill the region + \path[/sankey/fill] let + \p1=(\name.left),\p2=(\name.right), + \p3=(\snk@oldname.left),\p4=(\snk@oldname.right), + \n1={\sankeyqtytolen{\qty}}, + \n{maxr}={\snk@minradius+\n1}, \n{minr}={\snk@minradius} + in + (\p1) arc(\orient+90:\orient-\snk@angle+90:\n{maxr}) -- (\p3) -- + (\p4) arc(\orient-\snk@angle+90:\orient+90:\n{minr}) -- (\p2) -- cycle; + % draw left and right borders + \path[/sankey/draw] let + \p1=(\name.left),\p2=(\name.right), + \p3=(\snk@oldname.left),\p4=(\snk@oldname.right), + \n1={\sankeyqtytolen{\qty}}, + \n{maxr}={\snk@minradius+\n1}, \n{minr}={\snk@minradius} + in + (\p1) arc(\orient+90:\orient-\snk@angle+90:\n{maxr}) + (\p4) arc(\orient-\snk@angle+90:\orient+90:\n{minr}); + \snk@show@debug{\name} + }{ + \sankeyturnright[##2]{##3}{-1*\snk@angle} } - \edef\diff{\fpeval{abs(\iqty-\sankeytot)}} - %\typeout{sankeyfork diff: \diff} - %\pgfmathsetmacro{\diff}{abs(\iqty-\sankeytot)} - %\pgfmathtruncatemacro{\finish}{\diff<0.01?1:0} - \ifnumequal{\diff}{0}{}{ - \PackageWarning{sankey}{^^J*** Warning: bad sankey fork: \iqty\space!=\space\sankeycalculus(=\sankeytot)^^J##2} + \endgroup + } + \NewDocumentCommand\sankeyturnleft{sO{}mm}{ + % *(reverse), options, name, angle + \snk@errorifnotdefined{##3} + \begingroup + \IfBooleanTF{##1} + {\edef\snk@angle{\fpeval{-1*##4}}} + {\edef\snk@angle{\fpeval{1*##4}}} + \edef\snk@anglesign{\fpeval{sign(\snk@angle)}} + \ifnumgreater{\snk@anglesign}{-1}{ + \sankeyset{##2} + \edef\name{##3} + \edef\snk@oldname{##3-old} + \sankeynodealias{\name}{\snk@oldname} + \edef\qty{\sankeygetnodeqty{\name}} + \edef\orient{\snk@normalize@angle{\sankeygetnodeorient{\name}+\snk@angle}} + \snk@getpos\snk@c{$(\name.left)!-\snk@minradius!(\name.right)$} + \snk@getpos\pos{$(\snk@c)!1!\snk@angle:(\name.center)$} + \snk@makenode{} + % fill the region + \path[/sankey/fill] let + \p1=(\snk@oldname.left),\p2=(\snk@oldname.right), + \p3=(\name.left),\p4=(\name.right), + \n1={\sankeyqtytolen{\qty}}, + \n{maxr}={\snk@minradius+\n1}, \n{minr}={\snk@minradius} + in + (\p1) arc(\orient-\snk@angle-90:\orient-90:\n{minr}) -- (\p3) -- + (\p4) arc(\orient-90:\orient-\snk@angle-90:\n{maxr}) -- (\p2) -- cycle; + % draw left and right borders + \path[/sankey/draw] let + \p1=(\snk@oldname.left),\p2=(\snk@oldname.right), + \p3=(\name.left),\p4=(\name.right), + \n1={\sankeyqtytolen{\qty}}, + \n{maxr}={\snk@minradius+\n1}, \n{minr}={\snk@minradius} + in + (\p1) arc(\orient-\snk@angle-90:\orient-90:\n{minr}) + (\p4) arc(\orient-90:\orient-\snk@angle-90:\n{maxr}); + \snk@show@debug{\name} + }{ + \sankeyturnleftbackward[##2]{##3}{-1*\snk@angle} } + \endgroup } - - \def\sankeyqtytolen##1{\fpeval{(##1)/\sankeytotalqty*\sankeytotallen}} - + \NewDocumentCommand\sankeyturnleftbackward{sO{}mm}{ + % *(reverse), options, name, angle + \snk@errorifnotdefined{##3} + \begingroup + \IfBooleanTF{##1} + {\edef\snk@angle{\fpeval{-1*##4}}} + {\edef\snk@angle{\fpeval{1*##4}}} + \edef\snk@anglesign{\fpeval{sign(\snk@angle)}} + \ifnumgreater{\snk@anglesign}{-1}{ + \sankeyset{##2} + \edef\name{##3} + \edef\snk@oldname{##3-old} + \sankeynodealias{\name}{\snk@oldname} + \edef\qty{\sankeygetnodeqty{\name}} + \edef\orient{\snk@normalize@angle{\sankeygetnodeorient{\name}-\snk@angle}} + \snk@getpos\snk@c{$(\name.left)!-\snk@minradius!(\name.right)$} + \snk@getpos\pos{$(\snk@c)!1!-\snk@angle:(\name.center)$} + \snk@makenode{} + % fill the region + \path[/sankey/fill] let + \p1=(\name.left),\p2=(\name.right), + \p3=(\snk@oldname.left),\p4=(\snk@oldname.right), + \n1={\sankeyqtytolen{\qty}}, + \n{maxr}={\snk@minradius+\n1}, \n{minr}={\snk@minradius} + in + (\p1) arc(\orient-90:\orient+\snk@angle-90:\n{minr}) -- (\p3) -- + (\p4) arc(\orient+\snk@angle-90:\orient-90:\n{maxr}) -- (\p2) -- cycle; + % draw left and right borders + \path[/sankey/draw] let + \p1=(\name.left),\p2=(\name.right), + \p3=(\snk@oldname.left),\p4=(\snk@oldname.right), + \n1={\sankeyqtytolen{\qty}}, + \n{maxr}={\snk@minradius+\n1}, \n{minr}={\snk@minradius} + in + (\p1) arc(\orient-90:\orient+\snk@angle-90:\n{minr}) + (\p4) arc(\orient+\snk@angle-90:\orient-90:\n{maxr}); + \snk@show@debug{\name} + }{ + \sankeyturnleft[##2]{##3}{-1*\snk@angle} + } + \endgroup + } + \NewDocumentCommand\sankeyturn{sO{}mm}{% + % *(reverse), options, name, angle + \snk@errorifnotdefined{##3} + \begingroup + \edef\snk@anglesign{\fpeval{sign(##4)}} + \IfBooleanTF{##1}{ + \ifnumgreater{\snk@anglesign}{-1} + {\sankeyturnleftbackward[##2]{##3}{##4}} + {\sankeyturnrightbackward[##2]{##3}{-1*##4}} + }{ + \ifnumgreater{\snk@anglesign}{-1} + {\sankeyturnleft[##2]{##3}{##4}} + {\sankeyturnright[##2]{##3}{-1*##4}} + } + \endgroup + } + \NewDocumentCommand\sankeyfork{O{}mm}{%options, name, list of forks + \snk@errorifnotdefined{##2} + \begingroup + \sankeyset{##1} + \sankeynode[debug=false]{as={##2},forked={##3}} + \foreach \qty/\snk@subnodename in {##3}{\sankeynode{as={\snk@subnodename}}} + \endgroup + } + \def\sankeyqtytolen##1{\fpeval{(##1)/\snk@totalqty*\snk@totallen}} \sankeyset{ - % % default values, - % /tikz/declare function={ - % % sankeyqtytolen(\qty)=\qty/\sankeytotalqty*\sankeytotallen; - % % sankeylentoqty(\len)=\len/\sankeytotallen*\sankeytotalqty; - % },% - default parameters,% + @initial options, + every diagram, % user values #1} - - %\typeout{sankeytotallen: \sankeytotallen} - - #2 % body of sankeydiagram environment } - - +{} % empty but mandatory ! :-) \sankeyset{ - % none style new start style={none}{}{}, new end style={none}{}{}, - % simple style +} +\sankeyset{ new start style={simple}{ - (\name.left) -- ([xshift=-.5\pgflinewidth]\name.left) -- ([xshift=-.5\pgflinewidth]\name.right) -- (\name.right) -- cycle + (\name.left) -- ([xshift=-.5\pgflinewidth]\name.left) + -- ([xshift=-.5\pgflinewidth]\name.right) -- (\name.right) -- cycle }{ - (\name.left) -- ([xshift=-.5\pgflinewidth]\name.left) -- ([xshift=-.5\pgflinewidth]\name.right) -- (\name.right) + (\name.left) -- ([xshift=-.5\pgflinewidth]\name.left) + -- ([xshift=-.5\pgflinewidth]\name.right) -- (\name.right) }, new end style={simple}{ - (\name.left) -- ([xshift=2mm]\name.center) -- (\name.right) -- cycle + (\name.left) -- ([xshift=2mm]\name.center) + -- (\name.right) -- cycle }{ - (\name.left) -- ([xshift=2mm]\name.center) -- (\name.right) + (\name.left) -- ([xshift=2mm]\name.center) -- (\name.right) }, - % arrow style +} +\sankeyset{ new start style={arrow}{ - (\name.left) -- ++(-10pt,0) - -- ([xshift=-10pt/6]\name.center) - -- ([xshift=-10pt]\name.right) - -- (\name.right) -- cycle + (\name.left) -- ++(-10pt,0) -- ([xshift=-10pt/6]\name.center) + -- ([xshift=-10pt]\name.right) -- (\name.right) -- cycle }{ - (\name.left) -- ++(-10pt,0) - -- ([xshift=-10pt/6]\name.center) - -- ([xshift=-10pt]\name.right) - -- (\name.right) + (\name.left) -- ++(-10pt,0) -- ([xshift=-10pt/6]\name.center) + -- ([xshift=-10pt]\name.right) -- (\name.right) }, new end style={arrow}{ (\name.left) -- ([yshift=1mm]\name.left) - -- ([xshift=10pt]\name.center) - -- ([yshift=-1mm]\name.right) -- (\name.right) -- cycle + -- ([xshift=10pt]\name.center) -- ([yshift=-1mm]\name.right) + -- (\name.right) -- cycle }{ (\name.left) -- ([yshift=1mm]\name.left) - -- ([xshift=10pt]\name.center) - -- ([yshift=-1mm]\name.right) -- (\name.right) + -- ([xshift=10pt]\name.center) -- ([yshift=-1mm]\name.right) + -- (\name.right) }, -}
\ No newline at end of file +} +\endinput +%% +%% End of file `sankey.sty'. diff --git a/Master/texmf-dist/tex/latex/sankey/tikzlibrarydubins.code.tex b/Master/texmf-dist/tex/latex/sankey/tikzlibrarydubins.code.tex index da1dc120dca..291bcd771fe 100644 --- a/Master/texmf-dist/tex/latex/sankey/tikzlibrarydubins.code.tex +++ b/Master/texmf-dist/tex/latex/sankey/tikzlibrarydubins.code.tex @@ -1,15 +1,40 @@ -% Copyright (C) 2016-2021 by Paul Gaborit -% -% This file may be distributed and/or modified -% -% 1. under the LaTeX Project Public License and/or -% -% 2. under the GNU Public License. +%% +%% This is file `tikzlibrarydubins.code.tex', +%% generated with the docstrip utility. +%% +%% The original source files were: +%% +%% sankey.dtx (with options: `tikzlibrarydubins.code.tex') +%% +%% This is a generated file. +%% +%% Copyright (C) 2016, 2021 by Paul Gaborit +%% +%% This work may be distributed and/or modified under the conditions of the +%% LaTeX Project Public License, either version 1.3 of this license or (at +%% your option) any later version. The latest version of this license is +%% in +%% +%% <http://www.latex-project.org/lppl.txt> +%% +%% and version 1.3 or later is part of all distributions of LaTeX version +%% 2005/12/01 or later. +%% +%% This work has the LPPL maintenance status “maintained”. +%% +%% The Current Maintainer of this work is Paul Gaborit. +%% +%% This work consists of the files sankey.dtx, sankey.ins and the derived +%% files sankey.sty, tikzlibrarydubins.code.tex, sankey-doc-preamble.sty, +%% sankey-example1.tex, sankey-example2.tex, sankey-example3.tex, +%% sankey-example3-variation.tex, sankey-example4.tex, +%% sankey-example-energy.tex +%% +\def\tikzlibrarydubins@version{v3.0} +\def\tikzlibrarydubins@date{2021/03/14} \usetikzlibrary{calc} - \RequirePackage{etoolbox} -\RequirePackage{etextools} \RequirePackage{xfp} \newbool{dubinspathreverse} @@ -19,29 +44,28 @@ \ifnumequal{\pgfmathresult}{1}% } -\def\anglebetween#1#2#3{%macro, s, t - \path let - \p{s}=(#2), \p{t}=(#3), - \n{angle}={atan2(\y{t}-\y{s},\x{t}-\x{s})} - in \pgfextra { - \pgfmathsetmacro#1{\n{angle}} - \aftergroup@def#1 - }; +\def\dbp@getxy#1#2#3{% + \tikz@scan@one@point\pgfutil@firstofone(#3)\relax% + \edef#1{\the\pgf@x}% + \edef#2{\the\pgf@y}% } -\def\distancebetween#1#2#3{%macro, s, t - \path let - \p{s}=(#2), \p{t}=(#3), - %\n{dist}={veclen(\x{t}-\x{s},\y{t}-\y{s}))} - \n{dist}={\fpeval{sqrt((\x{t}-\x{s})*(\x{t}-\x{s})+(\y{t}-\y{s})*(\y{t}-\y{s}))}} - in \pgfextra { - %\typeout{n{dist}:\n{dist}} - \pgfmathsetmacro#1{\n{dist}} - \aftergroup@def#1 - }; +\def\dbp@anglebetween#1#2#3{%macro, s, t + \dbp@getxy\dbp@ax\dbp@ay{#2} + \dbp@getxy\dbp@bx\dbp@by{#3} + \pgfmathsetmacro#1{atan2(\dbp@by-\dbp@ay,\dbp@bx-\dbp@ax)} } -\newcommand\dubinspath@rsr{% s, sa, t, ta, as, len, at, r +\def\dbp@distancebetween#1#2#3{%macro, s, t + \dbp@getxy\dbp@ax\dbp@ay{#2} + \dbp@getxy\dbp@bx\dbp@by{#3} + \edef#1{\fpeval{sqrt(% + (\dbp@bx-\dbp@ax)*(\dbp@bx-\dbp@ax)% + +(\dbp@by-\dbp@ay)*(\dbp@by-\dbp@ay)% + )}}% +} + +\newcommand\dbp@rsr{% s, sa, t, ta, as, len, at, r let \p{tr}=([shift={(\dbp@angb-90:\dbp@radius pt)}]\dbp@b), \n1={\dbp@anga+90}, @@ -53,7 +77,7 @@ arc(\n3:\n2:\dbp@rradius pt) } -\newcommand\dubinspath@lsl{% s, sa, t, ta, as, len, at, r +\newcommand\dbp@lsl{% s, sa, t, ta, as, len, at, r let \p{tl}=([shift={(\dbp@angb+90:\dbp@radius pt)}]\dbp@b), \n1={\dbp@anga-90},\n2={\n1+\dbp@firstangle}, @@ -64,7 +88,7 @@ arc(\n4:\n3:\dbp@lradius pt) } -\newcommand\dubinspath@rsl{% s, sa, t, ta, as, len, at, r +\newcommand\dbp@rsl{% s, sa, t, ta, as, len, at, r let \p{tl}=([shift={(\dbp@angb+90:\dbp@radius pt)}]\dbp@b), \n1={\dbp@anga+90},\n2={\n1-\dbp@firstangle}, @@ -75,7 +99,7 @@ arc(\n4:\n3:\dbp@lradius pt) } -\newcommand\dubinspath@lsr{% s, sa, t, ta, as, len, at, r +\newcommand\dbp@lsr{% s, sa, t, ta, as, len, at, r let \p{tr}=([shift={(\dbp@angb-90:\dbp@radius pt)}]\dbp@b), \n1={\dbp@anga-90},\n2={\n1+\dbp@firstangle}, @@ -86,7 +110,7 @@ arc(\n4:\n3:\dbp@rradius pt) } -\newcommand\dubinspath@lrl{% s, sa, t, ta, as, ai, at, r +\newcommand\dbp@lrl{% s, sa, t, ta, as, ai, at, r let \n1={\dbp@anga-90},\n2={\n1+\dbp@firstangle}, \n3={\dbp@angb-90},\n4={\n3-\dbp@lastangle} @@ -96,7 +120,7 @@ arc(\n4:\n3:\dbp@lradius pt) } -\newcommand\dubinspath@rlr{% s, sa, t, ta, as, ai, at, r +\newcommand\dbp@rlr{% s, sa, t, ta, as, ai, at, r let \n1={\dbp@anga+90},\n2={\n1-\dbp@firstangle}, \n3={\dbp@angb+90},\n4={\n3+\dbp@lastangle} @@ -105,77 +129,68 @@ arc(\n2+180:\n2+180+\dbp@midparam:\dbp@lradius pt) arc(\n4:\n3:\dbp@rradius pt) } -\newcommand\dubinspath@rev@lsl{\dubinspath@rsr} -\newcommand\dubinspath@rev@rsr{\dubinspath@lsl} -\newcommand\dubinspath@rev@lsr{\dubinspath@lsr} -\newcommand\dubinspath@rev@rsl{\dubinspath@rsl} -\newcommand\dubinspath@rev@lrl{\dubinspath@rlr} -\newcommand\dubinspath@rev@rlr{\dubinspath@lrl} - +\newcommand\dbp@rev@lsl{\dbp@rsr} +\newcommand\dbp@rev@rsr{\dbp@lsl} +\newcommand\dbp@rev@lsr{\dbp@lsr} +\newcommand\dbp@rev@rsl{\dbp@rsl} +\newcommand\dbp@rev@lrl{\dbp@rlr} +\newcommand\dbp@rev@rlr{\dbp@lrl} \newcommand\dubinspath[1]{% \pgfextra{ \dubinspathset{#1} \ifbool{dubinspathreverse}{ - \edef\newa{\dbp@b} - \edef\newb{\dbp@a} - \pgfmathsetmacro\newanga{180+\dbp@angb} - \pgfmathsetmacro\newangb{180+\dbp@anga} - \edef\newfirstangle{\dbp@lastangle} - \edef\newlastangle{\dbp@firstangle} - \edef\newmethod{rev@\dbp@method} - \edef\newlradius{\dbp@rradius} - \edef\newrradius{\dbp@lradius} + \edef\dbp@newa{\dbp@b} + \edef\dbp@newb{\dbp@a} + \pgfmathsetmacro\dbp@newanga{180+\dbp@angb} + \pgfmathsetmacro\dbp@newangb{180+\dbp@anga} + \edef\dbp@newfirstangle{\dbp@lastangle} + \edef\dbp@newlastangle{\dbp@firstangle} + \edef\dbp@newmethod{rev@\dbp@method} + \edef\dbp@newlradius{\dbp@rradius} + \edef\dbp@newrradius{\dbp@lradius} \dubinspathset{ - start point=\newa, - end point=\newb, - start angle=\newanga, - end angle=\newangb, - first angle=\newfirstangle, - last angle=\newlastangle, - left and right minimum radii=\newlradius pt and \newrradius pt, - method=\newmethod, + start point=\dbp@newa, + end point=\dbp@newb, + start angle=\dbp@newanga, + end angle=\dbp@newangb, + first angle=\dbp@newfirstangle, + last angle=\dbp@newlastangle, + left and right minimum radii=\dbp@newlradius pt and \dbp@newrradius pt, + method=\dbp@newmethod, } }{} - %\typeout{dbp@lradius:\dbp@lradius} - %\typeout{dbp@rradius:\dbp@rradius} } - \csname dubinspath@\dbp@method\endcsname% + \csname dbp@\dbp@method\endcsname% } +%% solution -% solution -% \xdef\dubinspathmethod{} % type of dubins path -% \xdef\dubinspathlength{} % lenght (pt) -% \xdef\dubinspathfirstangle{} % first angle -% \xdef\dubinspathmiddleparam{} % intermediate angle or straight distance -% \xdef\dubinspathlastangle{} % last angle - -\def\dubinspathstore#1#2{% - \expandafter\xdef\csname dubinspath@store@#1@#2\endcsname% - {\csname dubinspath#2\endcsname}% +\def\dbp@store#1#2{% + \expandafter\xdef\csname dbp@store@#1@#2\endcsname% + {\csname dbp@#2\endcsname}% } -\def\dubinspathget#1#2{% - \csname dubinspath@store@#1@#2\endcsname% +\def\dbp@get#1#2{% + \csname dbp@store@#1@#2\endcsname% } -% -\def\dubinspathsetparams#1#2#3#4#5{% method, length, fisrt angle, middle param, last angle - \edef\dubinspathmethod{#1} - \edef\dubinspathlength{#2} - \edef\dubinspathfirstangle{#3} - \edef\dubinspathmiddleparam{#4} - \edef\dubinspathlastangle{#5} +\def\dbp@setparams#1#2#3#4#5{% + % method, length, fisrt angle, middle param, last angle + \edef\dbp@method{#1} + \edef\dbp@length{#2} + \edef\dbp@firstangle{#3} + \edef\dbp@middleparam{#4} + \edef\dbp@lastangle{#5} \ifdef{\dbp@storename}{ \foreach \p in {method,length,firstangle,middleparam,lastangle}{ - \dubinspathstore{\dbp@storename}{\p} + \dbp@store{\dbp@storename}{\p} } }{} } -\def\dubinspathupdateparams#1#2#3#4#5{ - \ifpgfmathcond{#2<\dubinspathlength}{ - \dubinspathsetparams{#1}{#2}{#3}{#4}{#5} +\def\dbp@updateparams#1#2#3#4#5{ + \ifpgfmathcond{#2<\dbp@length}{ + \dbp@setparams{#1}{#2}{#3}{#4}{#5} }{} } @@ -188,10 +203,10 @@ end angle/.store in=\dbp@angb, store/.store in=\dbp@storename, use store/.style={ - method=\dubinspathget{#1}{method}, - first angle=\dubinspathget{#1}{firstangle}, - last angle=\dubinspathget{#1}{lastangle}, - middle param=\dubinspathget{#1}{middleparam}, + method=\dbp@get{#1}{method}, + first angle=\dbp@get{#1}{firstangle}, + last angle=\dbp@get{#1}{lastangle}, + middle param=\dbp@get{#1}{middleparam}, }, minimum radius/.code={ \pgfmathsetmacro\dbp@radius{#1} @@ -217,145 +232,155 @@ \dubinspathset{#1} \tikzset{ declare function={ - angtodist(\a,\r)={abs(\a)*.01745329*\r}; - modangr(\a,\b)={ - (Mod(\a,360)<Mod(\b,360)?Mod(\a,360):Mod(\a,360)-360)+\b-Mod(\b,360) + angtodist(\dbp@a,\dbp@r)={abs(\dbp@a)*.01745329*\dbp@r}; + modangr(\dbp@a,\dbp@b)={ + ( + Mod(\dbp@a,360)<Mod(\dbp@b,360) + ? + Mod(\dbp@a,360) + : + Mod(\dbp@a,360)-360)+\dbp@b-Mod(\dbp@b,360 + ) }; - modangl(\a,\b)={ - (Mod(\a,360)<Mod(\b,360)?Mod(\a,360)+360:Mod(\a,360))+(\b)-Mod(\b,360) + modangl(\dbp@a,\dbp@b)={ + ( + Mod(\dbp@a,360)<Mod(\dbp@b,360) + ? + Mod(\dbp@a,360)+360 + : + Mod(\dbp@a,360))+(\dbp@b)-Mod(\dbp@b,360) }; }, } - - \pgfmathsetmacro\radius{\dbp@rradius} - \pgfmathsetmacro\anga{mod((\dbp@anga)+180,360)-180} - \pgfmathsetmacro\angb{mod((\dbp@angb)+180,360)-180} - %\typeout{radius:\radius,anga:\anga,angb:\angb} + + \pgfmathsetmacro\dbp@radius{\dbp@rradius} + \pgfmathsetmacro\dbp@anga{mod((\dbp@anga)+180,360)-180} + \pgfmathsetmacro\dbp@angb{mod((\dbp@angb)+180,360)-180} \path let \p{a}=(\dbp@a), \p{b}=(\dbp@b), - \p{ar}=($(\p{a}) + (\anga-90:\radius pt)$), - \p{al}=($(\p{a}) + (\anga+90:\radius pt)$), - \p{br}=($(\p{b}) + (\angb-90:\radius pt)$), - \p{bl}=($(\p{b}) + (\angb+90:\radius pt)$) + \p{ar}=($(\p{a}) + (\dbp@anga-90:\dbp@radius pt)$), + \p{al}=($(\p{a}) + (\dbp@anga+90:\dbp@radius pt)$), + \p{br}=($(\p{b}) + (\dbp@angb-90:\dbp@radius pt)$), + \p{bl}=($(\p{b}) + (\dbp@angb+90:\dbp@radius pt)$) in \pgfextra{ \pgfinterruptpath - % RSR (ar et br) - %\typeout{RSR begin} - \anglebetween\rsrarbr{\p{ar}}{\p{br}} - \distancebetween\rsrdarbr{\p{ar}}{\p{br}} - \pgfmathsetmacro\rsrangone{Mod(\anga-\rsrarbr,360)} - \pgfmathsetmacro\rsrangtwo{Mod(\rsrarbr-\angb,360)} - \pgfmathsetmacro\rsrlen{\rsrdarbr} - \pgfmathsetmacro\rsrdist{ - angtodist(\rsrangone,\radius) - +\rsrlen - +angtodist(\rsrangtwo,\radius) + % RSR (ar and br) + \dbp@anglebetween\dbp@rsrarbr{\p{ar}}{\p{br}} + \dbp@distancebetween\dbp@rsrdarbr{\p{ar}}{\p{br}} + \pgfmathsetmacro\dbp@rsrangone{Mod(\dbp@anga-\dbp@rsrarbr,360)} + \pgfmathsetmacro\dbp@rsrangtwo{Mod(\dbp@rsrarbr-\dbp@angb,360)} + \pgfmathsetmacro\dbp@rsrlen{\dbp@rsrdarbr} + \pgfmathsetmacro\dbp@rsrdist{ + angtodist(\dbp@rsrangone,\dbp@radius) + +\dbp@rsrlen + +angtodist(\dbp@rsrangtwo,\dbp@radius) } - \dubinspathsetparams{rsr}{\rsrdist}{\rsrangone}{\rsrlen}{\rsrangtwo} - - % LSL (al et bl) - %\typeout{LSL begin} - \anglebetween\lslalbl{\p{al}}{\p{bl}} - \distancebetween\lsldalbl{\p{al}}{\p{bl}} - \pgfmathsetmacro{\lslangone}{mod(\lslalbl-\anga+720,360)} - \pgfmathsetmacro{\lslangtwo}{mod(\angb-\lslalbl+720,360)} - \pgfmathsetmacro\lsllen{\lsldalbl} - \pgfmathsetmacro\lsldist{ - angtodist(\lslangone,\radius) - +\lsllen - +angtodist(\lslangtwo,\radius) + \dbp@setparams{rsr}{\dbp@rsrdist}{\dbp@rsrangone}{\dbp@rsrlen}{\dbp@rsrangtwo} + + % LSL (al and bl) + \dbp@anglebetween\dbp@lslalbl{\p{al}}{\p{bl}} + \dbp@distancebetween\dbp@lsldalbl{\p{al}}{\p{bl}} + \pgfmathsetmacro{\dbp@lslangone}{mod(\dbp@lslalbl-\dbp@anga+720,360)} + \pgfmathsetmacro{\dbp@lslangtwo}{mod(\dbp@angb-\dbp@lslalbl+720,360)} + \pgfmathsetmacro\dbp@lsllen{\dbp@lsldalbl} + \pgfmathsetmacro\dbp@lsldist{ + angtodist(\dbp@lslangone,\dbp@radius) + +\dbp@lsllen + +angtodist(\dbp@lslangtwo,\dbp@radius) } - \dubinspathupdateparams{lsl}{\lsldist}{\lslangone}{\lsllen}{\lslangtwo} - - % RSL (ar et bl) - %\typeout{RSL begin} - \distancebetween\rsldarbl{\p{ar}}{\p{bl}} - \pgfmathtruncatemacro\rslok{(\rsldarbl>=2*\radius)?1:0} - \ifnumequal{\rslok}{1}{ - \anglebetween\rslarbl{\p{ar}}{\p{bl}} - \pgfmathsetmacro\rslanglesup{ - asin(\radius/\rsldarbl*2)} - \pgfmathsetmacro\rslangone{Mod(\anga-\rslarbl+\rslanglesup,360)} - \pgfmathsetmacro\rslangtwo{Mod(\angb-\rslarbl+\rslanglesup,360)} - \pgfmathsetmacro\rsllen{veclen(\rsldarbl,\radius)} - \pgfmathsetmacro\rsldist{ - angtodist(\rslangone,\radius) - +\rsllen - +angtodist(\rslangtwo,\radius) + \dbp@updateparams% + {lsl}{\dbp@lsldist}{\dbp@lslangone}{\dbp@lsllen}{\dbp@lslangtwo} + + % RSL (ar and bl) + \dbp@distancebetween\dbp@rsldarbl{\p{ar}}{\p{bl}} + \pgfmathtruncatemacro\dbp@rslok{(\dbp@rsldarbl>=2*\dbp@radius)?1:0} + \ifnumequal{\dbp@rslok}{1}{ + \dbp@anglebetween\dbp@rslarbl{\p{ar}}{\p{bl}} + \pgfmathsetmacro\dbp@rslanglesup{ + asin(\dbp@radius/\dbp@rsldarbl*2)} + \pgfmathsetmacro\dbp@rslangone + {Mod(\dbp@anga-\dbp@rslarbl+\dbp@rslanglesup,360)} + \pgfmathsetmacro\dbp@rslangtwo + {Mod(\dbp@angb-\dbp@rslarbl+\dbp@rslanglesup,360)} + \pgfmathsetmacro\dbp@rsllen{veclen(\dbp@rsldarbl,\dbp@radius)} + \pgfmathsetmacro\dbp@rsldist{ + angtodist(\dbp@rslangone,\dbp@radius) + +\dbp@rsllen + +angtodist(\dbp@rslangtwo,\dbp@radius) } - \dubinspathupdateparams{rsl}{\rsldist}{\rslangone}{\rsllen}{\rslangtwo} + \dbp@updateparams% + {rsl}{\dbp@rsldist}{\dbp@rslangone}{\dbp@rsllen}{\dbp@rslangtwo} }{} - % LSR (al et br) - %\typeout{LSR begin} - \distancebetween\lsrdalbr{\p{al}}{\p{br}} - \pgfmathtruncatemacro\lsrok{(\lsrdalbr>=2*\radius)?1:0} - \ifnumequal{\lsrok}{1}{ - \anglebetween\lsralbr{\p{al}}{\p{br}} - \pgfmathsetmacro\lsranglesup{ - asin(\radius/\lsrdalbr*2)} - \pgfmathsetmacro\lsrangone{Mod(\lsralbr+\lsranglesup-\anga,360)} - \pgfmathsetmacro\lsrangtwo{Mod(\lsralbr+\lsranglesup-\angb,360)} - \pgfmathsetmacro\lsrlen{veclen(\lsrdalbr,\radius)} - \pgfmathsetmacro\lsrdist{ - angtodist(\lsrangone,\radius) - +\lsrlen - +angtodist(\lsrangtwo,\radius) + % LSR (al and br) + \dbp@distancebetween\dbp@lsrdalbr{\p{al}}{\p{br}} + \pgfmathtruncatemacro\dbp@lsrok{(\dbp@lsrdalbr>=2*\dbp@radius)?1:0} + \ifnumequal{\dbp@lsrok}{1}{ + \dbp@anglebetween\dbp@lsralbr{\p{al}}{\p{br}} + \pgfmathsetmacro\dbp@lsranglesup{ + asin(\dbp@radius/\dbp@lsrdalbr*2)} + \pgfmathsetmacro\dbp@lsrangone + {Mod(\dbp@lsralbr+\dbp@lsranglesup-\dbp@anga,360)} + \pgfmathsetmacro\dbp@lsrangtwo + {Mod(\dbp@lsralbr+\dbp@lsranglesup-\dbp@angb,360)} + \pgfmathsetmacro\dbp@lsrlen{veclen(\dbp@lsrdalbr,\dbp@radius)} + \pgfmathsetmacro\dbp@lsrdist{ + angtodist(\dbp@lsrangone,\dbp@radius) + +\dbp@lsrlen + +angtodist(\dbp@lsrangtwo,\dbp@radius) } - \dubinspathupdateparams{lsr}{\lsrdist}{\lsrangone}{\lsrlen}{\lsrangtwo} + \dbp@updateparams% + {lsr}{\dbp@lsrdist}{\dbp@lsrangone}{\dbp@lsrlen}{\dbp@lsrangtwo} }{} - - % LRL (al et bl) - %\typeout{LRL begin} - \distancebetween\lrldalbl{\p{al}}{\p{bl}} - \pgfmathtruncatemacro\lrlok{(\lrldalbl<=4*\radius)?1:0} - \ifnumequal{\lrlok}{1}{ - % \debug{LRL} - \anglebetween\lrlalbl{\p{al}}{\p{bl}} - \pgfmathsetmacro\lrlangsup{acos(\lrldalbl/\radius/4)} - \pgfmathsetmacro\lrlangone{ - modangl(\lrlalbl+\lrlangsup,\anga-90)-(\anga-90)} - \pgfmathsetmacro\lrlangtwo{% - (\angb-90)-modangr(\lrlalbl+180-\lrlangsup,\angb-90)} - \pgfmathsetmacro\lrlangthree{360-2*(90-\lrlangsup)} - \pgfmathsetmacro\lrldist{ - angtodist(\lrlangone,\radius) - +angtodist(\lrlangthree,\radius) - +angtodist(\lrlangtwo,\radius) + + % LRL (al and bl) + \dbp@distancebetween\dbp@lrldalbl{\p{al}}{\p{bl}} + \pgfmathtruncatemacro\dbp@lrlok{(\dbp@lrldalbl<=4*\dbp@radius)?1:0} + \ifnumequal{\dbp@lrlok}{1}{ + \dbp@anglebetween\dbp@lrlalbl{\p{al}}{\p{bl}} + \pgfmathsetmacro\dbp@lrlangsup{acos(\dbp@lrldalbl/\dbp@radius/4)} + \pgfmathsetmacro\dbp@lrlangone{ + modangl(\dbp@lrlalbl+\dbp@lrlangsup,\dbp@anga-90)-(\dbp@anga-90)} + \pgfmathsetmacro\dbp@lrlangtwo{% + (\dbp@angb-90)-modangr(\dbp@lrlalbl+180-\dbp@lrlangsup,\dbp@angb-90)} + \pgfmathsetmacro\dbp@lrlangthree{360-2*(90-\dbp@lrlangsup)} + \pgfmathsetmacro\dbp@lrldist{ + angtodist(\dbp@lrlangone,\dbp@radius) + +angtodist(\dbp@lrlangthree,\dbp@radius) + +angtodist(\dbp@lrlangtwo,\dbp@radius) } - \dubinspathupdateparams{lrl}{\lrldist}{\lrlangone}{\lrlangthree}{\lrlangtwo} + \dbp@updateparams% + {lrl}{\dbp@lrldist}{\dbp@lrlangone}{\dbp@lrlangthree}{\dbp@lrlangtwo} }{} - % RLR (ar et br) - %\typeout{RLR begin} - \distancebetween\rlrdarbr{\p{ar}}{\p{br}} - \pgfmathtruncatemacro\rlrok{(\rlrdarbr<=4*\radius)?1:0} - \ifnumequal{\rlrok}{1}{ - \anglebetween\rlrarbr{\p{ar}}{\p{br}} - \pgfmathsetmacro\rlrangsup{acos(\rlrdarbr/\radius/4)} - \pgfmathsetmacro\rlrangone{ - (\anga+90)-modangr(\rlrarbr-\rlrangsup,\anga+90)} - \pgfmathsetmacro\rlrangtwo{% - modangl(\rlrarbr+180+\rlrangsup,\angb+90)-(\angb+90)} - \pgfmathsetmacro\rlrangthree{360-2*(90-\rlrangsup)} - \pgfmathsetmacro\rlrdist{ - angtodist(\rlrangone,\radius) - +angtodist(\rlrangthree,\radius) - +angtodist(\rlrangtwo,\radius) + % RLR (ar and br) + \dbp@distancebetween\dbp@rlrdarbr{\p{ar}}{\p{br}} + \pgfmathtruncatemacro\dbp@rlrok{(\dbp@rlrdarbr<=4*\dbp@radius)?1:0} + \ifnumequal{\dbp@rlrok}{1}{ + \dbp@anglebetween\dbp@rlrarbr{\p{ar}}{\p{br}} + \pgfmathsetmacro\dbp@rlrangsup{acos(\dbp@rlrdarbr/\dbp@radius/4)} + \pgfmathsetmacro\dbp@rlrangone{ + (\dbp@anga+90)-modangr(\dbp@rlrarbr-\dbp@rlrangsup,\dbp@anga+90)} + \pgfmathsetmacro\dbp@rlrangtwo{% + modangl(\dbp@rlrarbr+180+\dbp@rlrangsup,\dbp@angb+90)-(\dbp@angb+90)} + \pgfmathsetmacro\dbp@rlrangthree{360-2*(90-\dbp@rlrangsup)} + \pgfmathsetmacro\dbp@rlrdist{ + angtodist(\dbp@rlrangone,\dbp@radius) + +angtodist(\dbp@rlrangthree,\dbp@radius) + +angtodist(\dbp@rlrangtwo,\dbp@radius) } - \dubinspathupdateparams{rlr}{\rlrdist}{\rlrangone}{\rlrangthree}{\rlrangtwo} + \dbp@updateparams% + {rlr}{\dbp@rlrdist}{\dbp@rlrangone}{\dbp@rlrangthree}{\dbp@rlrangtwo} }{} \endpgfinterruptpath }; \endgroup } - -%%% Local Variables: -%%% mode: latex -%%% TeX-master: t -%%% End: +\endinput +%% +%% End of file `tikzlibrarydubins.code.tex'. |