% 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]

\RequirePackage{xparse}
\RequirePackage{xfp}
\RequirePackage{tikz}
\usetikzlibrary{calc,decorations.markings,dubins}
\usepackage{etoolbox}

% 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\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'}%
  }%
}

\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]
  \anchor{left}{\pgf@process{\northeast}}
  \anchor{right}{\pgf@process{\southwest}}
}

% pgfkeys family 'sankey'
\pgfkeys{/sankey/.is family}

\NewDocumentCommand\sankeyset{m}{\pgfkeys{sankey,#1}}

\sankeyset{
  ratio length/.code={
    \pgfmathsetmacro\sankeytotallen{#1}
    \edef\sankeytotallen{\sankeytotallen 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,
  minimum radius/.value required,
  outin steps/.estore in=\sankeystepoutin,
  outon steps/.value required,
  %
  debug/.is choice,
  debug/true/.code={\toggletrue{sankey debug}},
  debug/false/.code={\togglefalse{sankey debug}},
  debug/.default=true,
  %
  start style/.is choice,
  %
  end style/.is choice,
  % default values
  default parameters/.style={
    % default values
    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}%
    },
    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,
  },
}

% 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={},
  },
  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,
  },
}

\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}}}
  },
}

% 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
  }

  \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
  }

  \newcommand\sankeymakenode{
    \begingroup
    \sankeymakenodenodebug{}
    \iftoggle{sankey debug}{
      \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}
        \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}};
      \end{pgfonlayer}
    }{}
    \endgroup
  }
  
  \newcommand\sankeynodenodebug[1]{
    \begingroup
    \sankeyset{node parameters,##1}
    %\typeout{sankeynodenodebug: '\name' at(\pos) angle(\orient) qty(\qty)}
    \sankeymakenodenodebug{}
    \endgroup
  }

  % ============================================================
  % user commands
  % ============================================================
  
  \NewDocumentCommand\sankeydubins{O{}mm}{% options, sn, en
    \begingroup
    \sankeyset{##1}
    \pgfmathsetmacro\startangle{\sankeygetnodeorient{##2}}
    \pgfmathsetmacro\endangle{\sankeygetnodeorient{##3}}
    \edef\sqty{\sankeygetnodeqty{##2}}
    \edef\eqty{\sankeygetnodeqty{##3}}
    \ifdefstrequal{\sqty}{\eqty}{}{
      \PackageError{sankey}%
      {^^J*** \string\sankeyoutin: quantities differ between ##2 (\sqty) and ##3 (\eqty)^^J}%
      {The quantities of the two Sankey nodes must be equal.}
    }
    \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,
      },
    }
    \dubinspathcalc{sankey,store=sankey}
    
    \dubinspathset{
      left border/.style={
        sankey, use store=sankey,
        left and right minimum radii=
        {\sankeyminradius} and {\sankeyminradius + \width pt},
      },
      right border/.style={
        sankey, use store=sankey,
        left and right minimum radii=
        {\sankeyminradius + \width pt} and {\sankeyminradius},
      },
    }
    
    \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}
    };
    \endgroup
  }
  

  \NewDocumentCommand\sankeyoutin{O{}mm}{% options, sn, en
    \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={
      markings,
      mark=between positions \mystep and \mybound step \mystep with {
        \def\sankeyoutinmidptname{sankeyoutinmidpt \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)
        ;
      }
    }](\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}
    }
    \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)
    }
    --
    (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)
    }
    -- 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)
    }
    ;
    
    \endgroup
  }
  
  \NewDocumentCommand\sankeynodealias{mm}{%name, alias
    \path [late options={name=##1,alias=##2}];
    \sankeysetnodeqty{##2}{\sankeygetnodeqty{##1}}
    \sankeysetnodeorient{##2}{\sankeygetnodeorient{##1}}
  }

  \newcommand\sankeynode[2][]{
    \begingroup
    \sankeyset{##1}
    \sankeyset{node parameters,##2}
    %\typeout{sankeynode: '\name' at(\pos) angle(\orient) qty(\qty)}
    \sankeymakenode{}
    \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}{
    \begingroup
    \sankeyset{##1}
    \edef\name{##2}
    \edef\orient{\sankeygetnodeorient{##2}}
    \edef\qty{\sankeygetnodeqty{##2}}
    \sankeyfilldrawstart
    \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
  }

  \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
    \begingroup
    \sankeyset{##1}
    \edef\name{##2}
    \edef\orient{\sankeygetnodeorient{##2}}
    \edef\qty{\sankeygetnodeqty{##2}}
    \sankeyfilldrawend
    \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\sankeyadvance{sO{}mm}{% *(reverse), options, name, distance
    \begingroup
    \sankeyset{##2}
    \def\newname{##3}
    \def\oldname{##3-old}
    \sankeynodealias{\newname}{\oldname}
    % \typeout{*** sankeyadvance: ok (\oldname => \newname)}
    \IfBooleanTF{##1}{
      % reverse advance
      \sankeynode{
        at={$(\oldname.center)!##4!90:(\oldname.left)$},
        angle=\sankeygetnodeorient{\oldname},
        quantity=\sankeygetnodeqty{\oldname},
        name=\newname,
      }
      \path[/sankey/fill]
      (\newname.left) -- (\oldname.left)
      --
      (\oldname.right) -- (\newname.right)
      -- cycle;
      \path[/sankey/draw]
      (\newname.left) -- (\oldname.left)
      (\oldname.right) -- (\newname.right);
      \endgroup
    }{
      % advance
      \sankeynode{
        at={$(\oldname.center)!##4!-90:(\oldname.left)$},
        angle=\sankeygetnodeorient{\oldname},
        quantity=\sankeygetnodeqty{\oldname},
        name=\newname,
      }
      \path[/sankey/fill]
      (\oldname.left) -- (\newname.left)
      --
      (\newname.right) -- (\oldname.right)
      -- cycle;
      \path[/sankey/draw]
      (\oldname.left) -- (\newname.left)
      (\newname.right) -- (\oldname.right);
      \endgroup
    }
  }
  
  \NewDocumentCommand\sankeyturn{sO{}mm}{% *(reverse), options, name, angle
    \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}
        };
      }
    }{
      % 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}
        };
      }
    }
    \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}
      };
    }
    \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}
    }
  }
  
  \def\sankeyqtytolen##1{\fpeval{(##1)/\sankeytotalqty*\sankeytotallen}}
  
  \sankeyset{
    % % default values,
    % /tikz/declare function={
    %   % sankeyqtytolen(\qty)=\qty/\sankeytotalqty*\sankeytotallen;
    %   % sankeylentoqty(\len)=\len/\sankeytotallen*\sankeytotalqty;
    % },%
    default parameters,%
    % user values
    #1}

  %\typeout{sankeytotallen: \sankeytotallen}
  
  #2 % body of sankeydiagram environment 
}


\sankeyset{
  % none style
  new start style={none}{}{},
  new end style={none}{}{},
  % simple style
  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)
  },
  new end style={simple}{
    (\name.left) -- ([xshift=2mm]\name.center) -- (\name.right) -- cycle
  }{
    (\name.left) -- ([xshift=2mm]\name.center) -- (\name.right)
  },
  % arrow style
  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)
  },
  new end style={arrow}{
    (\name.left) -- ([yshift=1mm]\name.left)
    -- ([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)
  },
}