%% file: tzplot.sty
%%
%% tzplot
%%
%% (C) Copyright 2017-2021 In-Sung Cho <ischo at ktug.org>
%%
%% This work may be distributed and/or modified
%% under the conditions of the LaTeX Project Public License,
%% either version 1.3c of this license or (at your option) any later version.
%% The latest version of this license is in
%%  http://www.latex-project.org/lppl.txt.
%%
%% -------------------------------------------------
\ProvidesPackage{tzplot-v1.0}[2021/02/28 v1.0 Plot Graphs with TikZ Abbreviations]

% expl3,xparse: LPPL
% tikz: LPPL and/or GNU GPL
\RequirePackage{expl3,xparse}
\RequirePackage{tikz}

\usetikzlibrary{
calc,backgrounds,positioning,intersections,
arrows,shapes,patterns,
plotmarks, % for \tzplot[mark]
decorations.pathreplacing, % for tzshowcontrols/show path construction, tzbrace
calligraphy, % for calligraphic brace (load after decorations.pathreplacing)
}


%% backgrounds
\pgfdeclarelayer{background}
\pgfdeclarelayer{behind}
\pgfdeclarelayer{above}
\pgfdeclarelayer{foreground}

\pgfsetlayers{background,behind,main,above,foreground}
%% usage: \begin{pgfonlayer}{foreground} ... \end{pgfonlayer}


%%%%% defaults
\def\tz@default@radius{1.2pt}                          % fixed
\def\tz@initial@radius{\tz@default@radius}             % changeable
\NewDocumentCommand\settzdotradius{m}{\renewcommand\tz@initial@radius{#1}}
\newcommand\tzdotradius{\tz@initial@radius}

% circle dot (using radius)
\def\tz@default@Cdot@radius{1.2pt}                     % fixed
\def\tz@initial@Cdot@radius{\tz@default@Cdot@radius}   % changeable
\NewDocumentCommand\settzcdotradius{m}{\renewcommand\tz@initial@Cdot@radius{#1}}
\newcommand\tzCdotradius{\tz@initial@Cdot@radius}

% node dot (using minimum size)
\def\tz@default@dot@size{2.4pt}                        % fixed
\def\tz@initial@dot@size{\tz@default@dot@size}         % changeable
\NewDocumentCommand\settzdotsize{m}{\renewcommand\tz@initial@dot@size{#1}}
\newcommand\tzdotsize{\tz@initial@dot@size}

% mark (using mark size, which is a radius)            % tikz initial = 2pt
\def\tz@default@mark@size{2pt}                         % fixed 
\def\tz@initial@mark@size{\tz@default@mark@size}       % changeable
\NewDocumentCommand\settzmarksize{m}{\renewcommand\tz@initial@mark@size{#1}}
\newcommand\tzmarksize{\tz@initial@mark@size}

% opacity
\def\tz@default@fill@opacity{0.3}                      % fixed
\def\tz@initial@fill@opacity{\tz@default@fill@opacity} % changeable
\NewDocumentCommand\settzfillopacity{m}{\renewcommand\tz@initial@fill@opacity{#1}}
\newcommand\tzfillopacity{\tz@initial@fill@opacity}

% fillcolor
\def\tz@default@fill@color{black!50}                    % fixed
\def\tz@initial@fill@color{\tz@default@fill@color}      % changeable
\NewDocumentCommand\settzfillcolor{mg}
{%
  \renewcommand\tz@initial@fill@color{#1}
  \IfValueT {#2} {\renewcommand\tz@initial@fill@opacity{#2}}
}
\newcommand\tzfillcolor{\tz@initial@fill@color}

% link style
\def\tz@default@link@style{to}                         % fixed
\def\tz@initial@link@style{\tz@default@link@style}     % changeable
\NewDocumentCommand\settzlinkstyle{m}{\renewcommand\tz@initial@link@style{#1}}
\newcommand\tzlinkstyle{\tz@initial@link@style}

% path style
\def\tz@default@path@style{to}                         % fixed
\def\tz@initial@path@style{\tz@default@path@style}     % changeable
\NewDocumentCommand\settzpathstyle{m}{\renewcommand\tz@initial@path@style{#1}}
\newcommand\tzpathstyle{\tz@initial@path@style}

% tangent epsilon

\def\tz@default@tangent@epsilonL{.01}
\def\tz@default@tangent@epsilonR{.01}
\def\tz@initial@tangent@epsilonL{\tz@default@tangent@epsilonL}
\def\tz@initial@tangent@epsilonR{\tz@default@tangent@epsilonL}
\NewDocumentCommand\settztangentepsilon{mg}
{%
  \renewcommand\tz@initial@tangent@epsilonL{#1}
  \IfNoValueTF {#2}
  {\renewcommand\tz@initial@tangent@epsilonR{#1}}
  {\renewcommand\tz@initial@tangent@epsilonR{#2}}
}
\newcommand\tztangentepsilonL{\tz@initial@tangent@epsilonL}
\newcommand\tztangentepsilonR{\tz@initial@tangent@epsilonR}
\let\tztangentatepsilonL\tztangentepsilonL
\let\tztangentatepsilonR\tztangentepsilonR

% tzpath layer %% (NOT USED!!!) (to be considered later)
\def\tz@default@tzpath@layer{main}                     % fixed
\def\tz@initial@tzpath@layer{\tz@default@tzpath@layer} % changeable
\NewDocumentCommand\settzpathlayer{m}{\renewcommand\tz@initial@tzpath@layer{#1}}
\newcommand\tzpathlayer{\tz@initial@tzpath@layer}

% tangent layer
\def\tz@default@tangent@layer{behind}                    % fixed
\def\tz@initial@tangent@layer{\tz@default@tangent@layer} % changeable
\NewDocumentCommand\settztangentlayer{m}{\renewcommand\tz@initial@tangent@layer{#1}}
\newcommand\tztangentlayer{\tz@initial@tangent@layer}
\let\tztangentatlayer\tztangentlayer

% secant layer
\def\tz@default@secant@layer{behind}                    % fixed
\def\tz@initial@secant@layer{\tz@default@secant@layer} % changeable
\NewDocumentCommand\settzsecantlayer{m}{\renewcommand\tz@initial@secant@layer{#1}}
\newcommand\tzsecantlayer{\tz@initial@secant@layer}
\let\tzsecantatlayer\tzsecantlayer

%%%%% TikZ alias styles

\tikzset{
  a/.style={above=#1},
  b/.style={below=#1},
  c/.style={centered=#1},
  l/.style={left=#1},
  r/.style={right=#1},
  al/.style={above left=#1},
  ar/.style={above right=#1},
  bl/.style={below left=#1},
  br/.style={below right=#1},
}

%%%%% tzplot styles

\tikzset{>=stealth} % to revert use {>=to}

%% tzdot (for node dot style)
\tikzset{
  tzdot/.style=
    {draw,solid,thin,circle,inner sep=0pt,minimum size=#1},
  tzdot/.default=\tzdotsize
}

%% tzdot options (for node dot style)
\tikzset{
  tzdot options/.style={tzdot=\tzdotsize,#1}
}

%% tzmark
\tikzset{
  tzmark/.style=
    {mark options={solid,thin},mark size=#1},
  tzmark/.default=\tzmarksize
}

%% tznode (NOT USED!) -- user choice
\tikzset{
  tznode/.style=
    {solid,thin,circle,inner sep=0pt,minimum size=#1},
  tznode/.default=0pt
}

%% tzdotted
\tikzset{%
  tzdotted/.style={%
    dotted=none,
    line cap=round,
    dash pattern=on 0pt off 1cm/(#1)
  },
  tzdotted/.default=10
}

%% tzdashed
\tikzset{
  tzdashed/.style={%
    dashed=none,
    dash pattern=on 5mm/(#1) off 5mm/(#1)
  },
  tzdashed/.default=10
}

%% tzhelplines
\tikzset{%
  tzhelplines/.style={help lines,-,tzdotted}
}

%% tzshorten
\tikzset{%
  tzshorten/.style 2 args ={shorten <=#1, shorten >=#2},
  tzshoretn/.default={2pt}{2pt}
}

%% tzextend (negative tzshorten)
\tikzset{%
  tzextend/.style 2 args ={shorten <=-#1, shorten >=-#2},
  tzextend/.default={2pt}{2pt}
}


%% tzshowcontrols  % (for \tzbezier: tikz manual p.645)
\tikzset{%
  tzshowcontrols/.style={%
    postaction={%
      decoration={%
        show path construction,
        curveto code={%
          \draw [dotted,#1] 
                (\tikzinputsegmentfirst)
             -- (\tikzinputsegmentsupporta)
             -- (\tikzinputsegmentsupportb)
             -- (\tikzinputsegmentlast);
        }
      },
      decorate
    }
  }
}

%=====================================================
%%=====================================================
%%=====================================================
\ExplSyntaxOn
%%=====================================================
%%=====================================================


%%%%% help lines
\NewDocumentCommand\tzhelplines{ s O{} r() d() }
{
  \IfBooleanTF { #1 }
  {
    \IfNoValueTF { #4 }
    { \draw [ tzhelplines , use~as~bounding~box , #2 ] (0,0) grid (#3); }
    { \draw [ tzhelplines , use~as~bounding~box , #2 ] (#3)  grid (#4); }
  }
  {
    \IfNoValueTF { #4 }
    { \draw [ tzhelplines , #2 ] (0,0) grid (#3); }
    { \draw [ tzhelplines , #2 ] (#3)  grid (#4); }
  }
}


%%%%% \tzbbox
\NewDocumentCommand\tzbbox{ r() d() }
{
  \IfNoValueTF { #2 }
  {
    \useasboundingbox (0,0) rectangle (#1);
  }
  {
    \useasboundingbox (#1)  rectangle (#2);
  }
}

%%%%% \tzgetxyval
\NewDocumentCommand\tzgetxyval{ r() m m }
{
  \tikz@scan@one@point\pgfutil@firstofone(#1)\relax%
  \pgfmathparse{\the\pgf@x/28.45274}% convert pt to cm
  \edef#2{\pgfmathresult}%
  \pgfmathparse{\the\pgf@y/28.45274}% convert pt to cm
  \edef#3{\pgfmathresult}%
}

%%% --- end of \tzgetxyval

%%%%%% \tzgetxyval (experimental)
%%%%%% seems not working
%\NewDocumentCommand\tzgetxyval{ g r() m m }
%{
%  \IfNoValueTF { #1 }
%  {
%    \def\tzptToDim{28.45274} % cm: default
%  }
%  {
%    \str_case:nnTF { #1 } 
%    {
%      {pt} { \def\tzptToDim{1} }
%      {mm} { \def\tzptToDim{2.845274} }
%      {cm} { \def\tzptToDim{28.45274} }
%      {bp} { \def\tzptToDim{1.00374} }
%      {dd} { \def\tzptToDim{1.07} }
%      {pc} { \def\tzptToDim{12} }
%      {in} { \def\tzptToDim{72.26999} }
%    }
%    {
%      \def\tzptToDim{1} % default unit in tikz
%    }
%  }
%  \tikz@scan@one@point\pgfutil@firstofone(#2)\relax%
%  \pgfmathparse{\the\pgf@x/\tzptToDim}% convert pt to dim
%  \edef#3{\pgfmathresult}%
%  \pgfmathparse{\the\pgf@y/\tzptToDim}% convert pt to dim
%  \edef#4{\pgfmathresult}%
%}
%
%%%% --- end of \tzgetxyval


%%%%% Dots

%%% Node Dots %%% (basic: using minimum size)

%%% \tzdot
%%% *[opt]<shift>(coor){text}[pos,opt](size)

\bool_new:N \l_tzdot_shift_coor_bool

\NewDocumentCommand\tzdot{ s O{} d<> r() +G{} O{} D(){\tz@initial@dot@size} }
{
  \tl_clear:N \l_tzdot_cmd_tl

  \IfValueT { #7 }
  { \renewcommand\tzdotsize{ #7 } }

  \IfValueTF { #3 }
  {
    \tl_set:Nn \l_tzdot_shift_coor_tl { #3 }
    \bool_set_true:N \l_tzdot_shift_coor_bool
  }
  {
    \tl_clear:N \l_tzdot_shift_coor_tl
    \bool_set_false:N \l_tzdot_shift_coor_bool
  }

  \bool_if:NTF \l_tzdot_shift_coor_bool
  {
    \tl_put_right:Nx \l_tzdot_cmd_tl
    {
      ( [ shift = { (\l_tzdot_shift_coor_tl) } ]#4 ) node
    }
  }
  { \tl_put_right:Nn \l_tzdot_cmd_tl { (#4) node } }

  \IfBooleanTF { #1 }
  {
    \tl_put_right:Nn \l_tzdot_cmd_tl
      { [ tzdot , fill , }
  }
  {
    \tl_put_right:Nn \l_tzdot_cmd_tl
      { [ tzdot , }
  }
  \tl_put_right:Nx \l_tzdot_cmd_tl
    {
      label = { \exp_not:n { #6 } \c_colon_str \exp_not:n { #5 } } ,
    }
  \tl_put_right:Nn \l_tzdot_cmd_tl
    {
      minimum~size = \tzdotsize , #2 ] {}
    }
  \exp_last_unbraced:Nf \path \l_tzdot_cmd_tl ;
}

%%% --- end of \tzdot


%%% multiple dots
%%% coding CAUTION! : _tzdot_ changed to _tzdots_

%%% \tzdots
%%% repeat pattern: (coor){label}[pos]

\tl_new:N \l_tzdots_opt_tl
\tl_new:N \l_tzdots_cmd_tl
\bool_new:N \l_tzdots_shift_coor_bool

\NewDocumentCommand\tzdots{ s O{} d<> }
{
  \tl_clear:N \l_tzdots_cmd_tl

  \IfBooleanTF { #1 }
  { \tl_set:Nn \l_tzdots_STYLE_fill_tl { fill } }
  { \tl_set:Nn \l_tzdots_STYLE_fill_tl { fill = none } }

  \tl_if_empty:nTF { #2 }
  { \tl_set:Nn \l_tzdots_opt_tl { tzdot } }
  { \tl_set:Nn \l_tzdots_opt_tl { tzdot , #2 } }

  \IfValueTF { #3 }
  {
    \tl_set:Nn \l_tzdots_shift_coor_tl { #3 }
    \bool_set_true:N \l_tzdots_shift_coor_bool
  }
  {
    \tl_clear:N \l_tzdots_shift_coor_tl
    \bool_set_false:N \l_tzdots_shift_coor_bool
  }

  \tzdots_check_token:n
}

\cs_new:Npn \tzdots_check_token:n #1
{
%  \token_if_eq_charcode:NNTF #1 (
%  { \tzdots_sub_fn #1 }
%  { \tzdots_stop_action }
  \str_case:nnF { #1 }
  {
    { ( } { \tzdots_sub_fn #1 }
    { ; } { \tzdots_late_opt_fn }
  }
  {
    \tzdots_stop_action
  }
}


\NewDocumentCommand\tzdots_sub_fn { r() +G{} O{} }
{
  \bool_if:NTF \l_tzdots_shift_coor_bool
  {
    \tl_put_right:Nx \l_tzdots_cmd_tl
    {% if shift
      ( [ shift = { (\l_tzdots_shift_coor_tl) } ]#1 ) 
    }
  }
  { \tl_put_right:Nn \l_tzdots_cmd_tl { (#1) } }
  
  \tl_put_right:Nx \l_tzdots_cmd_tl
  {
    node
    [
      \l_tzdots_STYLE_fill_tl , 
      minimum~size = \exp_not:n { \tzdotsize } ,
      label = { \exp_not:n { #3 } \c_colon_str \exp_not:n { #2 } } ,
  }
  \tl_put_right:No \l_tzdots_cmd_tl   % expand `once'
  {
      \l_tzdots_opt_tl
    ] {}
  }
  \tzdots_check_token:n
}

\NewDocumentCommand\tzdots_late_opt_fn { D(){\tz@initial@dot@size} }
{
  \renewcommand\tzdotsize{ #1 }
  
  \tzdots_stop_action
}


\NewDocumentCommand\tzdots_stop_action {}
{
  \exp_last_unbraced:Nf \path \l_tzdots_cmd_tl ;
}

%%% --- end of \tzdots


%%%%% Circle Dots -- (code original, using radius)

\keys_define:nn { keytzCdot }
{
  tzcdot  .tl_set:N = \key_tzCdot_radius_tl
}


%% (keep)
%% \tzcdot --- circle dot (original)
%%% *[<opt>]<shift>(coor){label}[angle](radius)

\clist_new:N \l_tzCdot_opt_clist
\bool_new:N \l_tzCdot_shift_coor_bool

\NewDocumentCommand\tzcdot{ s o d<> r() +G{} O{} d() }
{
  \tl_clear:N \l_tzCdot_opt_tl % (needed)
  \tl_clear:N \l_tzCdot_cmd_tl

  % default dot radius == arg specifier D<>{\tz@initial@radius}
  \renewcommand\tzCdotradius{\tz@initial@Cdot@radius}

  \IfValueT { #7 }
    { \renewcommand\tzCdotradius{ #7 } }

  \IfBooleanTF { #1 }
  { \tl_set:Nn \l_tzCdot_fill_tl { fill , solid, thin } }
  { \tl_set:Nn \l_tzCdot_fill_tl { solid , thin } }

  \IfValueTF { #3 }
  {
    \tl_set:Nn \l_tzCdot_shift_coor_tl { #3 }
    \bool_set_true:N \l_tzCdot_shift_coor_bool
  }
  {
    \tl_clear:N \l_tzCdot_shift_coor_tl
    \bool_set_false:N \l_tzCdot_shift_coor_bool
  }

  \IfNoValueTF { #2 }
  {
    \tl_clear:N \l_tzCdot_opt_tl           % arg specifier O{}
  }
  {
     \clist_clear:N \l_tzCdot_opt_tested_clist
     \clist_set:Nn \l_tzCdot_opt_input_clist { #2 }
     \clist_map_inline:Nn \l_tzCdot_opt_input_clist
     {
       \str_if_in:nnTF { ##1 } { tzcdot }
       { % (matched item)
         \clist_pop:NN \l_tzCdot_opt_input_clist \l_tmpa_tl 
         \keys_set:nV { keytzCdot } \l_tmpa_tl   % form: { tzcdot=\l_tmpa_tl }
         \exp_args:NNo \renewcommand\tzCdotradius { \key_tzCdot_radius_tl }
         \clist_map_break:
         % non-tested list remains
       }
       { % (tested items -> list)
         \clist_pop:NN \l_tzCdot_opt_input_clist \l_tmpb_tl 
         \clist_put_right:NV \l_tzCdot_opt_tested_clist \l_tmpb_tl
       }
     }
     \clist_concat:NNN \l_tzCdot_opt_clist 
                       \l_tzCdot_opt_tested_clist % tested list
                       \l_tzCdot_opt_input_clist  % remained list
     \clist_if_empty:NF \l_tzCdot_opt_clist
     { % expand x needed
       \tl_set:Nx \l_tzCdot_opt_tl { \clist_use:Nn \l_tzCdot_opt_clist {,} }
     }
  }

  \tl_put_right:Nx \l_tzCdot_cmd_tl
    {
      [ \l_tzCdot_fill_tl ,
    }
  \tl_put_right:No \l_tzCdot_cmd_tl  % expand `once'
    {
        \l_tzCdot_opt_tl
      ]
    }
  \bool_if:NTF \l_tzCdot_shift_coor_bool
  {% if shift
    \tl_put_right:Nx \l_tzCdot_cmd_tl
      {
        ( [ shift = { (\l_tzCdot_shift_coor_tl) } ]#4 )
      }
  }
  { \tl_put_right:Nn \l_tzCdot_cmd_tl { ( #4 ) } } % no shift (normal)
  
  \tl_put_right:Nn \l_tzCdot_cmd_tl
    {
      circle ( \tzCdotradius )
    }
  \tl_put_right:Nx \l_tzCdot_cmd_tl
    {
      node
        [ inner~sep = 0pt ,
          label = { \exp_not:n { #6 } \c_colon_str \exp_not:n { #5 } }
        ] {}
    }
  \exp_last_unbraced:No \draw \l_tzCdot_cmd_tl ;
}

%%% --- end of \tzcdot


%%% multiple dots
%%% coding CAUTION! : _tzCdot_ changes to _tzCdots

%%% *[<opt>]<shift> (){}[] (){}[] repeated (){}[] ; (radius)
%%% repeat pattern: (coor){label}[angle]

\clist_new:N \l_tzCdots_opt_clist
\bool_new:N \l_tzCdots_size_call_bool
\bool_new:N \l_tzCdots_shift_coor_bool

\NewDocumentCommand\tzcdots{ s o d<> }
{
  \renewcommand\tzCdotradius{\tz@initial@Cdot@radius}

  \tl_clear:N \l_tzCdots_opt_tl  % (needed)
  \tl_clear:N \l_tzCdots_cmd_tl

  \IfBooleanTF { #1 }
  { \bool_set_true:N \l_tmpa_bool }
  { \bool_set_false:N \l_tmpa_bool }

  \IfValueTF { #3 }
  {
    \tl_set:Nn \l_tzCdots_shift_coor_tl { #3 }
    \bool_set_true:N \l_tzCdots_shift_coor_bool
  }
  {
    \tl_clear:N \l_tzCdots_shift_coor_tl
    \bool_set_false:N \l_tzCdots_shift_coor_bool
  }
  
  \IfNoValueTF { #2 }
  {
    \tl_clear:N \l_tzCdots_opt_tl              % arg specifier O{}
  }
  {
     \clist_clear:N \l_tzCdots_opt_tested_clist
     \clist_set:Nn \l_tzCdots_opt_input_clist { #2 }
     \clist_map_inline:Nn \l_tzCdots_opt_input_clist
     {
       \str_if_in:nnTF { ##1 } { tzcdot }
       {
         \clist_pop:NN \l_tzCdots_opt_input_clist \l_tmpa_tl
         \keys_set:nV { keytzCdot } \l_tmpa_tl
         \exp_args:NNo \renewcommand\tzCdotradius { \key_tzCdot_radius_tl }
         \bool_set_true:N \l_tzCdots_size_call_bool
         \clist_map_break:
       }
       {
         \clist_pop:NN \l_tzCdots_opt_input_clist \l_tmpb_tl
         \clist_put_right:NV \l_tzCdots_opt_tested_clist \l_tmpb_tl
       }
     }
     \clist_concat:NNN \l_tzCdots_opt_clist 
                       \l_tzCdots_opt_tested_clist 
                       \l_tzCdots_opt_input_clist
     \clist_if_empty:NF \l_tzCdots_opt_clist
     {
       \tl_set:Nx \l_tzCdots_opt_tl { \clist_use:Nn \l_tzCdots_opt_clist {,} }
     }
  }

  \tzCdots_check_token:n
}

\cs_new:Npn \tzCdots_check_token:n #1
{
%  \token_if_eq_charcode:NNTF #1 (
%  { \tzCdots_sub_fn #1 }
%  { \tzCdots_stop_action }
  \str_case:nnF { #1 }
  {
    { ( } { \tzCdots_sub_fn #1 }
    { ; } { \tzCdots_late_opt_fn }
  }
  {
    \tzCdots_stop_action
  }
}

\NewDocumentCommand\tzCdots_sub_fn { r() +G{} O{} }
{
  \bool_if:NTF \l_tzCdots_shift_coor_bool
  {% if shift
    \tl_put_right:Nx \l_tzCdots_cmd_tl
    {
      ( [ shift = { (\l_tzCdots_shift_coor_tl) } ]#1 ) circle (\tzCdotradius)
    }
  }
  {% no shift (normal)
    \tl_put_right:Nn \l_tzCdots_cmd_tl { (#1) circle (\tzCdotradius) } 
  }

  \tl_put_right:Nx \l_tzCdots_cmd_tl
  {
    node
    [ inner~sep = 0pt ,
      label = { \exp_not:n { #3 } \c_colon_str \exp_not:n { #2 } }
    ] {}
  }
  \tzCdots_check_token:n
}

\NewDocumentCommand\tzCdots_late_opt_fn { d() }
{
  \IfValueT { #1 }
    { 
      \bool_if:NF \l_tzCdots_size_call_bool
      { \renewcommand\tzCdotradius { #1 } }
    }
  
  \tzCdots_stop_action
}

\NewDocumentCommand\tzCdots_stop_action {}
{
  \tl_if_empty:NTF \l_tzCdots_opt_tl
  {
    \tl_put_left:Nn \l_tzCdots_cmd_tl { ] }
  }
  {
    \tl_put_left:No \l_tzCdots_cmd_tl { \l_tzCdots_opt_tl ] }  % expand `once'
  }

  \bool_if:NTF \l_tmpa_bool
  {
    \tl_put_left:Nn \l_tzCdots_cmd_tl { [ fill , solid , thin , }
  }
  {
    \tl_put_left:Nn \l_tzCdots_cmd_tl { [ solid , thin , }
  }

  \exp_last_unbraced:Nf \draw \l_tzCdots_cmd_tl ;

  \bool_set_false:N \l_tzCdots_size_call_bool
}

%%% --- end of \tzcdots


%%% \tzshoworigin  (node text and dot at the origin)

\NewDocumentCommand\tzshoworigin
  { s O{} d<> D(){0,0} +g O{} D(){\tz@initial@dot@size} }
{
  \IfValueTF { #5 }
  {% if shift
    \IfValueTF { #3 }
    {
      \path [ shift = {(#3)} ] (#4) node  
        [ text~height = 1.25ex , text~depth=.25ex , below~left , #6 ]
        { #5 } ;
      \IfBooleanT { #1 } { \tzdot* [ #2 ] ([shift={(#3)}] #4) (#7) }
    }
    {% no shift
      \path (#4) node  
        [ text~height = 1.25ex , text~depth=.25ex , below~left , #6 ]
        { #5 } ;
      \IfBooleanT { #1 } { \tzdot* [ #2 ] (#4) (#7) }
    }
  }
  {
    \IfValueTF { #3 }
    {% if shift
      \IfBooleanTF { #1 }
      { 
        \tzdot* [ #2 ] ([shift={(#3)}] #4) (#7)
      }
      {
        \path [ shift = {(#3)} ] (#4) node
          [ text~height = 1.25ex , text~depth=.25ex , below~left , #6 ]
          { 0 } ;
      }
    }
    {% no shift
      \IfBooleanTF { #1 }
      { 
        \tzdot* [ #2 ] (#4) (#7)
      }
      {
        \path (#4) node
          [ text~height = 1.25ex , text~depth=.25ex , below~left , #6 ]
          { 0 } ;
      }
    }
  }
}

%%% --- end of \tzshoworigin


%%%%% Coordinates

%%% \tzcoor()(){label}[pos]
\NewDocumentCommand\tzcoor{ s O{} d<> r() r() +G{} O{} D(){\tz@initial@dot@size} }
{
  \tl_clear:N \l_tzcoor_cmd_tl
  
  \IfBooleanTF { #1 }
  {
    \IfValueTF { #3 }
    {
      \path ([shift={(#3)}]#4) coordinate (#5) ;
      \tzdot*[#2]([shift={(#3)}]#4){#6}[#7](#8)
    }
    {
      \path (#4) coordinate (#5) ;
      \tzdot*[#2](#4){#6}[#7](#8)
    }
  }
  {
    \IfValueTF { #3 }
    {
      \tl_put_right:Nn \l_tzcoor_cmd_tl
        {
          ([shift={(#3)}]#4) coordinate
        }
    }
    { \tl_put_right:Nn \l_tzcoor_cmd_tl { (#4) coordinate } }

    \tl_put_right:Nn \l_tzcoor_cmd_tl
      {
        [ inner~sep = 0pt ,
      }
    \tl_put_right:Nx \l_tzcoor_cmd_tl
      {
          label = { \exp_not:n { #7 } \c_colon_str \exp_not:n { #6 } }
      }
    \tl_put_right:Nn \l_tzcoor_cmd_tl
      {
        ] (#5)
      }
    \exp_last_unbraced:No \path \l_tzcoor_cmd_tl ;
  }
}

%%% --- end of \tzcoor


%%% \tzcoors

\bool_new:N \l_tzcoors_shift_coor_bool

%%% \tzcoors*[opt]<radius> ()(){}[] ()(){}[] repeated ()(){}[];
%% repeat pattern: (coor)(name){label}[pos]
\NewDocumentCommand\tzcoors{ s O{} d<> }
{
  \tl_clear:N \l_tzcoors_cmd_tl
  \tl_clear:N \l_tzcoors_tzdot_cmd_tl

  \IfBooleanTF { #1 }
  { \bool_set_true:N \l_tmpa_bool }
  { \bool_set_false:N \l_tmpa_bool }

  \IfValueTF { #2 }
  { \tl_set:Nn \l_tzcoors_opt_tl { #2 } }
  { \tl_clear:N \l_tzcoors_opt_tl }
  
  \IfValueTF { #3 }
  {
    \tl_set:Nn \l_tzcoors_shift_coor_tl { #3 }
    \bool_set_true:N \l_tzcoors_shift_coor_bool
  }
  {
    \tl_clear:N \l_tzcoors_shift_coor_tl
    \bool_set_false:N \l_tzcoors_shift_coor_bool
  }
  
  \tzcoors_check_token:n
}

\cs_new:Npn \tzcoors_check_token:n #1
{
%  \str_if_eq:nnTF { #1 } { ( }
%    { \tzcoors_sub_fn ( }
%    { \tzcoors_stop_action }
  \str_case:nnF { #1 }
  {
    { ( } { \tzcoors_sub_fn #1 }
    { ; } { \tzcoors_late_opt_fn }
  }
  {
    \tzcoors_stop_action
  }
}

\NewDocumentCommand\tzcoors_sub_fn { r() r() +G{} O{} }
{
  \bool_if:NTF \l_tmpa_bool
  {
    % collect only coor info
    \bool_if:NTF \l_tzcoors_shift_coor_bool
    {% if shift
      \tl_put_right:Nx \l_tzcoors_cmd_tl 
      { ([ shift = { (\l_tzcoors_shift_coor_tl) } ]#1) }
    }
    {% no shift (normal)
      \tl_put_right:Nn \l_tzcoors_cmd_tl { (#1) }
    }
    \tl_put_right:Nn \l_tzcoors_cmd_tl
      { coordinate (#2) }
    % collect dot info: (coor) [ dot opt ] {}
    \bool_if:NTF \l_tzcoors_shift_coor_bool
    {% if shift
      \tl_put_right:Nx \l_tzcoors_tzdot_cmd_tl 
      { ([ shift = { (\l_tzcoors_shift_coor_tl) } ]#1) }
    }
    {% no shift
      \tl_put_right:Nn \l_tzcoors_tzdot_cmd_tl { (#1) }
    }
    \tl_put_right:Nn \l_tzcoors_tzdot_cmd_tl
      { 
        node
        [ fill , tzdot = \tzdotsize ,
      }
    \tl_put_right:Nx \l_tzcoors_tzdot_cmd_tl
      {
          label = { \exp_not:n { #4 } \c_colon_str \exp_not:n { #3 } } ,
      }
    \tl_put_right:No \l_tzcoors_tzdot_cmd_tl
      {
          \l_tzcoors_opt_tl  % expand `once'
        ] {}
      }
  }
  {
    \bool_if:NTF \l_tzcoors_shift_coor_bool
    {% if shift
      \tl_put_right:Nx \l_tzcoors_cmd_tl
        { ([ shift = { (\l_tzcoors_shift_coor_tl) } ]#1) coordinate }
    }
    {% no shift (normal)
      \tl_put_right:Nn \l_tzcoors_cmd_tl
        { (#1) coordinate }
    }
    \tl_put_right:Nx \l_tzcoors_cmd_tl
      { [ label = { \exp_not:n { #4 } \c_colon_str \exp_not:n { #3 } } ] }
    \tl_put_right:Nn \l_tzcoors_cmd_tl
      { (#2) }
  }
  \tzcoors_check_token:n
}

\NewDocumentCommand\tzcoors_late_opt_fn { D(){\tz@initial@dot@size} }
{
  \renewcommand\tzdotsize{ #1 }
  
  \tzcoors_stop_action
}

\cs_new:Npn \tzcoors_stop_action
{
  \exp_last_unbraced:Nf \path \l_tzcoors_cmd_tl ;
  \bool_if:NT \l_tmpa_bool
  { \exp_last_unbraced:Nf \path \l_tzcoors_tzdot_cmd_tl ; }
}

%%% --- end of \tzcoors


%%% \tzcoorsquick --- with labels (quick view)

\bool_new:N \l_tzcoors_quick_shift_coor_bool

\NewDocumentCommand\tzcoorsquick { s O{} d<> }
{
  \tl_clear:N \l_tzcoors_quick_cmd_tl
  \tl_clear:N \l_tzcoors_quick_tzdot_cmd_tl

  \IfBooleanTF { #1 }
  { \bool_set_true:N \l_tmpa_bool }
  { \bool_set_false:N \l_tmpa_bool }

  \IfValueTF { #2 }
  { \tl_set:Nn \l_tzcoors_quick_opt_tl { #2 } }
  { \tl_clear:N \l_tzcoors_quick_opt_tl }

  \IfValueTF { #3 }
  {
    \tl_set:Nn \l_tzcoors_quick_shift_coor_tl { #3 }
    \bool_set_true:N \l_tzcoors_quick_shift_coor_bool
  }
  {
    \tl_clear:N \l_tzcoors_quick_shift_coor_tl
    \bool_set_false:N \l_tzcoors_quick_shift_coor_bool
  }

  \tzcoors_quick_check_token:n
}

\cs_new:Npn \tzcoors_quick_check_token:n #1
{
%  \str_if_eq:nnTF { #1 } { ( }
%    { \tzcoorsquick_sub_fn ( }
%    { \tzcoorsquick_stop_action }
  \str_case:nnF { #1 }
  {
    { ( } { \tzcoorsquick_sub_fn #1 }
    { ; } { \tzcoorsquick_late_opt_fn }
  }
  {
    \tzcoorsquick_stop_action
  }
}

% repetition ***
\NewDocumentCommand\tzcoorsquick_sub_fn { r() r() +g O{} }
{
  \IfValueTF { #3 }
    { \tl_set:Nx \l_tmpa_tl { \exp_not:n { #3 } } }
    { \tl_set:Nn \l_tmpa_tl { #2 } } % automatic view
  \tl_if_empty:nTF { #4 }
  {
    \bool_if:NTF \l_tmpa_bool
    { \tl_set:Nn \l_tmpb_tl { } } % texts with dots (tikz default: above)
    { \tl_set:Nn \l_tmpb_tl { center } } % only texts
  }
  {
    \tl_set:Nx \l_tmpb_tl { \exp_not:n { #4 } }
  }

  \bool_if:NTF \l_tmpa_bool
  { %% glancing labels with dots
    % collect only coor info
    % collect only coor info
    \bool_if:NTF \l_tzcoors_quick_shift_coor_bool
    {% if shift
      \tl_put_right:Nx \l_tzcoors_quick_cmd_tl 
      { ([ shift = { (\l_tzcoors_quick_shift_coor_tl) } ]#1) }
    }
    {% no shift (normal)
      \tl_put_right:Nn \l_tzcoors_quick_cmd_tl { (#1) }
    }
    \tl_put_right:Nn \l_tzcoors_quick_cmd_tl
      { coordinate (#2) }
    % collect dot info: (coor) [ dot opt ] {}
    \bool_if:NTF \l_tzcoors_quick_shift_coor_bool
    {% if shift
      \tl_put_right:Nx \l_tzcoors_quick_tzdot_cmd_tl 
      { ([ shift = { (\l_tzcoors_quick_shift_coor_tl) } ]#1) }
    }
    {% no shift
      \tl_put_right:Nn \l_tzcoors_quick_tzdot_cmd_tl { (#1) }
    }
    \tl_put_right:Nn \l_tzcoors_quick_tzdot_cmd_tl
      {
        node
        [ fill , tzdot = \tzdotsize ,
      }
    \tl_put_right:Nx \l_tzcoors_quick_tzdot_cmd_tl
      {
          label = { \l_tmpb_tl \c_colon_str { \l_tmpa_tl } } ,
      }
    \tl_put_right:No \l_tzcoors_quick_tzdot_cmd_tl
      {
          \l_tzcoors_quick_opt_tl  % expand `once'
        ] {}
      }
  }
  { %% glancing just labels (right on the coors)
    % collect coor and node info
    \bool_if:NTF \l_tzcoors_quick_shift_coor_bool
    {% if shift
      \tl_put_right:Nx \l_tzcoors_quick_cmd_tl
        { ([ shift = { (\l_tzcoors_quick_shift_coor_tl) } ]#1) coordinate }
    }
    {% no shift (normal)
      \tl_put_right:Nn \l_tzcoors_quick_cmd_tl
        { (#1) coordinate }
    }
    \tl_put_right:Nx \l_tzcoors_quick_cmd_tl
      { [ label = { \l_tmpb_tl \c_colon_str { \l_tmpa_tl } } ] }
    \tl_put_right:Nn \l_tzcoors_quick_cmd_tl
      { (#2) }
  }

  \tzcoors_quick_check_token:n
}

\NewDocumentCommand\tzcoorsquick_late_opt_fn{ D(){\tz@initial@dot@size} }
{
  \renewcommand\tzdotsize{ #1 }
  
  \tzcoorsquick_stop_action
}

\cs_new:Npn \tzcoorsquick_stop_action
{
  \exp_last_unbraced:Nf \path \l_tzcoors_quick_cmd_tl ;
  \bool_if:NT \l_tmpa_bool
  { \exp_last_unbraced:Nf \path \l_tzcoors_quick_tzdot_cmd_tl ; }
}

%%% --- end of \tzcoorsquick



%%%%% Lines

%%% \tzline
%% do not use: inner sep=0pt

%%% \tzline

\bool_new:N \l_tzline_shift_coor_bool

%%% \tzline
\NewDocumentCommand\tzline{ s t+ o d<> d"" }
{
  \tl_clear:N \l_tzline_cmd_tl

  \IfBooleanTF { #1 } % (*) or not (NOT USED!)
  { \bool_set_true:N \l_tmpa_bool }
  { \bool_set_false:N \l_tmpa_bool }

  \IfBooleanTF { #2 } % (+) or not
  { \bool_set_true:N \l_tmpb_bool }
  { \bool_set_false:N \l_tmpb_bool }

  \IfValueTF { #4 }
  {
    \tl_set:Nn \l_tzline_shift_coor_tl { #4 } 
    \bool_set_true:N \l_tzline_shift_coor_bool
  }
  { 
    \tl_clear:N \l_tzline_shift_coor_tl 
    \bool_set_false:N \l_tzline_shift_coor_bool
  }

  \IfValueTF { #3 }
  { \tl_set:Nn \l_tzline_opt_tl { #3 } }
  { \tl_clear:N \l_tzline_opt_tl }

  \IfValueTF { #5 }
  { \tl_set:Nn \l_tzline_namepath_tl { name~path = #5 } }
  { \tl_clear:N \l_tzline_namepath_tl }

  \tzline_check_token:n
}

\cs_new:Npn \tzline_check_token:n #1
{
  \str_if_eq:nnT { #1 } { ( }
    { \tzline_sub_fn ( }
%  \tzline_stop_action
}

%% structure: (coorA) -- node [pos] {text} (coorB) node [pos] {text}
\NewDocumentCommand\tzline_sub_fn{ r() +G{} O{} d<> r() +G{} O{} D<>{} }
{
  % determine connect line STYLE
  \tl_set:Nn \l_tzline_STYLE_A_tl { -- }
  \IfValueTF { #4 }
  {
    \tl_set:Nn \l_tzline_STYLE_C_tl { #4 }
  }
  {
    \bool_if:NTF \l_tmpb_bool
      { \tl_set:Nn \l_tzline_STYLE_C_tl { ++ } }
      { \tl_set:Nn \l_tzline_STYLE_C_tl {    } }
  }
  % insert connect line STYLE
  \bool_if:NTF \l_tzline_shift_coor_bool
  {% if shift
    \tl_put_right:Nx \l_tzline_cmd_tl 
    { ([ shift = { (\l_tzline_shift_coor_tl) } ]#1) }
  }
  {% no shift (normal)
    \tl_put_right:Nn \l_tzline_cmd_tl { (#1) } 
  }
  
  \tl_put_right:No \l_tzline_cmd_tl  % once
    {
      \l_tzline_STYLE_A_tl %% just --
    }
  \tl_put_right:Nn \l_tzline_cmd_tl
    {
      ~ node [ above , #3 ] { #2 }
    }
  \tl_put_right:No \l_tzline_cmd_tl  % once
    {
      \l_tzline_STYLE_C_tl
    }
  \bool_if:NTF \l_tmpb_bool
  {% if ++
    \tl_put_right:Nn \l_tzline_cmd_tl { (#5) }
  }
  {% no ++
    \bool_if:NTF \l_tzline_shift_coor_bool
    {% if shift
      \tl_put_right:Nx \l_tzline_cmd_tl 
      { ([ shift = { (\l_tzline_shift_coor_tl) } ]#5) } 
    }
    {% no shift (normal)
      \tl_put_right:Nn \l_tzline_cmd_tl { (#5) } 
    }
  }

  \tl_put_right:Nn \l_tzline_cmd_tl
    { node [ #7 ] { #6 } }

  % final action
  \tl_put_left:No \l_tzline_cmd_tl
  { 
    \l_tzline_opt_tl ] % expand `once'
  }

  \tl_put_left:Nx \l_tzline_cmd_tl
      { [ \l_tzline_namepath_tl , }

  \exp_last_unbraced:Nf \draw \l_tzline_cmd_tl #8 ;
}

%%% --- end of \tzline


%%% \tzlines

\bool_new:N \l_tzlines_shift_coor_bool

%% do not use: inner sep=0pt
\NewDocumentCommand\tzlines{ s t+ O{} d<> D""{} }
{
  \tl_clear:N \l_tzlines_cmd_tl
  \tl_clear:N \l_tzlines_STYLE_tl

  \IfBooleanTF { #1 } % (*) or not (NOT USED!)
  { \bool_set_true:N \l_tmpa_bool }
  { \bool_set_false:N \l_tmpa_bool }

  \IfBooleanTF { #2 } % (+) or not
  { \bool_set_true:N \l_tmpb_bool }
  { \bool_set_false:N \l_tmpb_bool }

  \IfValueTF { #4 }
  {
    \tl_set:Nn \l_tzlines_shift_coor_tl { #4 } 
    \bool_set_true:N \l_tzlines_shift_coor_bool
  }
  { 
    \tl_clear:N \l_tzlines_shift_coor_tl 
    \bool_set_false:N \l_tzlines_shift_coor_bool
  }

  \IfValueTF { #3 }
  { \tl_set:Nn \l_tzlines_opt_tl { #3 } }
  { \tl_clear:N \l_tzlines_opt_tl }

  \IfValueTF { #5 }
  { \tl_set:Nn \l_tzlines_namepath_tl { name~path = #5 } }
  { \tl_clear:N \l_tzlines_namepath_tl }

  \int_zero:N \l_tmpa_int
  \tzlines_check_token:n
}

\cs_new:Npn \tzlines_check_token:n #1
{
%  \token_if_eq_charcode:NNTF #1 (
%  { \tzlines_sub_fn #1 }
%  { \tzlines_stop_action }
  \str_case:nnF { #1 }
  {
    { ( } { \tzlines_sub_fn #1 }
    { ; } { \tzlines_late_opt_fn }
  }
  {
    \tzlines_stop_action
  }
}

\NewDocumentCommand\tzlines_sub_fn{ r() +G{} O{} d<> }
{
  \int_incr:N \l_tmpa_int
  % (from the second round) put line STYLE before the next cmd-tl
  \int_compare:nT { \l_tmpa_int > 1 }
  {
    \tl_put_right:No \l_tzlines_cmd_tl { \l_tzlines_STYLE_tl }
    \tl_clear:N \l_tzlines_STYLE_tl    
  }

  % collect cmd-tl
  \bool_if:NTF \l_tzlines_shift_coor_bool
  {% shift-coor
    \bool_if:NTF \l_tmpb_bool
    {% if ++
      \int_compare:nTF { \l_tmpa_int > 1 }
      { \tl_put_right:Nn \l_tzlines_cmd_tl { (#1) } } % no shift from 2nd
      {
        \tl_put_right:Nx \l_tzlines_cmd_tl
        { ([ shift = { (\l_tzlines_shift_coor_tl) } ]#1) } % shift first
      }
    }
    {% no ++
      \tl_put_right:Nx \l_tzlines_cmd_tl
      { ([ shift = { (\l_tzlines_shift_coor_tl) } ]#1) } % shift all coors
    }
  }
  { \tl_put_right:Nn \l_tzlines_cmd_tl { (#1) } } % no shift (normal)

  % (from the first round on) determine and save STYLE
  % determine connect line STYLE
  \tl_set:Nn \l_tzlines_STYLE_A_tl { -- }
  % save node info (for later use, at the end)
  \tl_set:Nn \l_tzlines_STYLE_B_tl { ~ node [ #3 ] { #2 } }
  \IfValueTF { #4 }
  {
    \tl_set:Nn \l_tzlines_STYLE_C_tl { #4 } % empty, + , or ++
  }
  {
    \bool_if:NTF \l_tmpb_bool
      { \tl_set:Nn \l_tzlines_STYLE_C_tl { ++ } }
      { \tl_set:Nn \l_tzlines_STYLE_C_tl {    } }
  }
  
  \tl_put_right:No \l_tzlines_STYLE_tl { \l_tzlines_STYLE_A_tl }
  \tl_put_right:No \l_tzlines_STYLE_tl { \l_tzlines_STYLE_B_tl }
  \tl_put_right:No \l_tzlines_STYLE_tl { \l_tzlines_STYLE_C_tl }
  
  \tzlines_check_token:n
}

\NewDocumentCommand\tzlines_late_opt_fn { D<>{} }
{
  \tl_set:Nn \l_tzlines_code_at_end_tl { #1 }
  \tzlines_stop_action
}

\NewDocumentCommand\tzlines_stop_action {}
{
  \tl_put_right:No \l_tzlines_cmd_tl { \l_tzlines_STYLE_B_tl }
  \tl_clear:N \l_tzlines_STYLE_tl
  % gathering options
  \tl_put_left:No \l_tzlines_cmd_tl
  {
    \l_tzlines_opt_tl ]    % expand `once' needed
  }
  \tl_put_left:Nx \l_tzlines_cmd_tl
    { [ \l_tzlines_namepath_tl , }
  % final action
  \exp_last_unbraced:Nf
    \draw \l_tzlines_cmd_tl \l_tzlines_code_at_end_tl ;
}

%%% --- end of \tzlines


%%% \tzpolygon (closed path of \tzlines)

\bool_new:N \l_tzpolygon_shift_coor_bool

%% do not use: inner sep=0pt
\NewDocumentCommand\tzpolygon{ s t+ O{} d<> D""{} }
{
  \tl_clear:N \l_tzpolygon_cmd_tl
  \tl_clear:N \l_tzpolygon_STYLE_tl

  \IfBooleanTF { #1 } % fill(*) or not
  { \bool_set_true:N \l_tmpa_bool }
  { \bool_set_false:N \l_tmpa_bool }

  \IfBooleanTF { #2 } % (+) or not
  { \bool_set_true:N \l_tmpb_bool }
  { \bool_set_false:N \l_tmpb_bool }

  \IfValueTF { #4 }
  {
    \tl_set:Nn \l_tzpolygon_shift_coor_tl { #4 } 
    \bool_set_true:N \l_tzpolygon_shift_coor_bool
  }
  { 
    \tl_clear:N \l_tzpolygon_shift_coor_tl 
    \bool_set_false:N \l_tzpolygon_shift_coor_bool
  }

  \IfValueTF { #3 }
  { \tl_set:Nx \l_tzpolygon_opt_tl { #3 } }
  { \tl_clear:N \l_tzpolygon_opt_tl }

  \IfValueTF { #5 }
  { \tl_set:Nn \l_tzpolygon_namepath_tl { name~path = #5 } }
  { \tl_clear:N \l_tzpolygon_namepath_tl }

  \int_zero:N \l_tmpa_int
  \tzpolygon_check_token:n
}

\cs_new:Npn \tzpolygon_check_token:n #1
{
%  \token_if_eq_charcode:NNTF #1 (
%  { \tzpolygon_sub_fn #1 }
%  { \tzpolygon_stop_action }
  \str_case:nnF { #1 }
  {
    { ( } { \tzpolygon_sub_fn #1 }
    { ; } { \tzpolygon_late_opt_fn }
  }
  {
    \tzpolygon_stop_action
  }
}

\NewDocumentCommand\tzpolygon_sub_fn{ r() +G{} O{} d<> }
{
  \int_incr:N \l_tmpa_int
  % (from the second round) put line STYLE before the next cmd-tl
  \int_compare:nT { \l_tmpa_int > 1 }
  {
    \tl_put_right:No \l_tzpolygon_cmd_tl { \l_tzpolygon_STYLE_tl }
    \tl_clear:N \l_tzpolygon_STYLE_tl    
  }

  % collect cmd-tl
  \bool_if:NTF \l_tzpolygon_shift_coor_bool
  {% shift-coor
    \bool_if:NTF \l_tmpb_bool
    {% if ++
      \int_compare:nTF { \l_tmpa_int > 1 }
      { \tl_put_right:Nn \l_tzpolygon_cmd_tl { (#1) } } % no shift from 2nd
      {
        \tl_put_right:Nx \l_tzpolygon_cmd_tl
        { ([ shift = { (\l_tzpolygon_shift_coor_tl) } ]#1) } % shift first
      }
    }
    {% no ++
      \tl_put_right:Nx \l_tzpolygon_cmd_tl
      { ([ shift = { (\l_tzpolygon_shift_coor_tl) } ]#1) } % shift all coors
    }
  }
  { \tl_put_right:Nn \l_tzpolygon_cmd_tl { (#1) } } % no shift (normal)

  % (from the first round on) determine and save STYLE
  % determine connect line STYLE
  \tl_set:Nn \l_tzpolygon_STYLE_A_tl { -- }
  % save node info (for later use, at the end)
  \tl_set:Nn \l_tzpolygon_STYLE_B_tl { ~ node [ #3 ] { #2 } }
  \IfValueTF { #4 }
  {
    \tl_set:Nn \l_tzpolygon_STYLE_C_tl { #4 } % empty, + , or ++
  }
  {
    \bool_if:NTF \l_tmpb_bool
      { \tl_set:Nn \l_tzpolygon_STYLE_C_tl { ++ } }
      { \tl_set:Nn \l_tzpolygon_STYLE_C_tl {    } }
  }
  
  \tl_put_right:No \l_tzpolygon_STYLE_tl { \l_tzpolygon_STYLE_A_tl }
  \tl_put_right:No \l_tzpolygon_STYLE_tl { \l_tzpolygon_STYLE_B_tl }
  \tl_put_right:No \l_tzpolygon_STYLE_tl { \l_tzpolygon_STYLE_C_tl }
  
  \tzpolygon_check_token:n
}

\NewDocumentCommand\tzpolygon_late_opt_fn { G{\tz@initial@fill@opacity} D<>{} }
{
  \renewcommand\tzfillopacity{ #1 }
  \tl_set:Nn \l_tzpolygon_code_at_end_tl { #2 }
  \tzpolygon_stop_action
}

\NewDocumentCommand\tzpolygon_stop_action {}
{
  \tl_put_right:No \l_tzpolygon_cmd_tl { \l_tzpolygon_STYLE_B_tl }
  \tl_clear:N \l_tzpolygon_STYLE_tl
  % fill or not
  \tl_put_left:No \l_tzpolygon_cmd_tl
  {
    \l_tzpolygon_opt_tl ]    % expand `once' needed
  }
  \bool_if:NTF \l_tmpa_bool
  {
    \tl_put_left:Nx \l_tzpolygon_cmd_tl
      {
        [ fill=\tzfillcolor , fill~opacity = \tzfillopacity , 
          text~opacity = 1 ,
          \l_tzpolygon_namepath_tl , 
      }
  }
  {
    \tl_put_left:Nx \l_tzpolygon_cmd_tl
      { [ \l_tzpolygon_namepath_tl , }
  }
  % final action
  \exp_last_unbraced:Nf
    \draw \l_tzpolygon_cmd_tl \l_tzpolygon_code_at_end_tl -- cycle ;
}

%%% --- end of \tzpolygon


%%% \tzpath 
%%  draw=none version of \tzlinks (mainly for filling area)

\bool_new:N \g_tzpath_BEGIN_cmd_bool
\bool_new:N \g_tzpath_END_cmd_bool
\bool_new:N \l_tzpath_shift_coor_bool

%% \tzpathAtBegin
\NewDocumentCommand\tzpathAtBegin{ m }
{
  \bool_gset_true:N \g_tzpath_BEGIN_cmd_bool
  \tl_gset:No \g_tzpath_BEGIN_cmd_tl { #1 }
}

%% \tzpathAtEnd
\NewDocumentCommand\tzpathAtEnd{ m }
{
  \bool_gset_true:N \g_tzpath_END_cmd_bool
  \tl_gset:No \g_tzpath_END_cmd_tl { #1 }
}

%%% \tzpath
%% do not use: inner sep=0pt
\NewDocumentCommand\tzpath{ s t+ G{\tz@initial@path@style} O{} d<> D""{} }
{
  \tl_clear:N \l_tzpath_cmd_tl
  \tl_clear:N \l_tzpath_STYLE_tl

  \IfValueT { #3 }
  { \renewcommand\tzpathstyle{ #3 } }

  \IfBooleanTF { #1 } % (*) or not  (NOT USED!)
  { \bool_set_true:N \l_tmpa_bool }
  { \bool_set_false:N \l_tmpa_bool }

  \IfBooleanTF { #2 } % (+) or not
  { \bool_set_true:N \l_tmpb_bool }
  { \bool_set_false:N \l_tmpb_bool }

  \IfValueTF { #5 }
  {
    \tl_set:Nn \l_tzpath_shift_coor_tl { #5 } 
    \bool_set_true:N \l_tzpath_shift_coor_bool
  }
  { 
    \tl_clear:N \l_tzpath_shift_coor_tl 
    \bool_set_false:N \l_tzpath_shift_coor_bool
  }

  \IfValueTF { #4 }
  { \tl_set:Nx \l_tzpath_opt_tl { #4 } }
  { \tl_clear:N \l_tzpath_opt_tl }

  \IfValueTF { #6 }
  { \tl_set:Nn \l_tzpath_namepath_tl { name~path = #6 } }
  { \tl_clear:N \l_tzpath_namepath_tl }

  \int_zero:N \l_tmpa_int
  \tzpath_check_token:n
}

\cs_new:Npn \tzpath_check_token:n #1
{
%  \token_if_eq_charcode:NNTF #1 (
%  { \tzpath_sub_fn #1 }
%  { \tzpath_stop_action }
  \str_case:nnF { #1 }
  {
    { ( } { \tzpath_sub_fn #1 }
    { ; } { \tzpath_late_opt_fn }
  }
  {
    \tzpath_stop_action
  }
}

\NewDocumentCommand\tzpath_sub_fn{ r() O{} +G{} O{} d<> }
{
  \int_incr:N \l_tmpa_int
  % (from the second round) put line STYLE before the next cmd-tl
  \int_compare:nT { \l_tmpa_int > 1 }
  {
    \tl_put_right:No \l_tzpath_cmd_tl { \l_tzpath_STYLE_tl }
    \tl_clear:N \l_tzpath_STYLE_tl    
  }

  % collect cmd-tl
  \bool_if:NTF \l_tzpath_shift_coor_bool
  {% shift-coor
    \bool_if:NTF \l_tmpb_bool
    {% if ++
      \int_compare:nTF { \l_tmpa_int > 1 }
      { \tl_put_right:Nn \l_tzpath_cmd_tl { (#1) } } % no shift from 2nd
      {
        \tl_put_right:Nx \l_tzpath_cmd_tl
        { ([ shift = { (\l_tzpath_shift_coor_tl) } ]#1) } % shift first
      }
    }
    {% no ++
      \tl_put_right:Nx \l_tzpath_cmd_tl
      { ([ shift = { (\l_tzpath_shift_coor_tl) } ]#1) } % shift all coors
    }
  }
  { \tl_put_right:Nn \l_tzpath_cmd_tl { (#1) } } % no shift (normal)

  % (from the first round on) determine and save STYLE
  % determine connect line STYLE
  \tl_if_empty:nTF { #2 }
    { \tl_set:Nn \l_tzpath_STYLE_A_tl { ~ \tzpathstyle ~ } }
    { \tl_set:Nn \l_tzpath_STYLE_A_tl { #2 } }
  % save node info (for later use, at the end)
  \tl_if_empty:nTF { #3 }
  {
    \tl_clear:N \l_tzpath_STYLE_B_tl
  }
  {
    \tl_set:Nn \l_tzpath_STYLE_B_tl 
      { ~ node [ #4 ] { #3 } }
  }
  \IfValueTF { #5 }
  {
    \tl_set:Nn \l_tzpath_STYLE_C_tl { #5 }
  }
  {
    \bool_if:NTF \l_tmpb_bool
      { \tl_set:Nn \l_tzpath_STYLE_C_tl { ++ } }
      { \tl_set:Nn \l_tzpath_STYLE_C_tl {    } }
  }

  \tl_put_right:No \l_tzpath_STYLE_tl { \l_tzpath_STYLE_A_tl }
  \tl_put_right:No \l_tzpath_STYLE_tl { \l_tzpath_STYLE_B_tl }
  \tl_put_right:No \l_tzpath_STYLE_tl { \l_tzpath_STYLE_C_tl }
  
  \tzpath_check_token:n
}

\NewDocumentCommand\tzpath_late_opt_fn { G{\tz@initial@fill@opacity} D<>{} }
{
  \renewcommand\tzfillopacity{ #1 }
  \tl_set:Nn \l_tzpath_code_at_end_tl { #2 }
  \tzpath_stop_action
}

\NewDocumentCommand\tzpath_stop_action {}
{
  \tl_if_empty:NF \l_tzpath_STYLE_B_tl
  {
    \tl_put_right:No \l_tzpath_cmd_tl { \l_tzpath_STYLE_B_tl }
  }
  \tl_clear:N \l_tzpath_STYLE_tl
  %% add at begin/end
  \bool_if:NT \g_tzpath_BEGIN_cmd_bool
    { \tl_put_left:Nx \l_tzpath_cmd_tl { \g_tzpath_BEGIN_cmd_tl } }
  \bool_if:NT \g_tzpath_END_cmd_bool
    { \tl_put_right:Nx \l_tzpath_cmd_tl { \g_tzpath_END_cmd_tl } }
  %% collect options
  \tl_put_left:No \l_tzpath_cmd_tl
    { \l_tzpath_opt_tl ] }          % expand `once' needed 
  % * or not
  \bool_if:NTF \l_tmpa_bool
  {
    \tl_put_left:Nx \l_tzpath_cmd_tl
      { 
        [ fill=\tzfillcolor , fill~opacity = \tzfillopacity , 
          text~opacity = 1 , 
          \l_tzpath_namepath_tl , 
      }
  }
  {
    \tl_put_left:Nx \l_tzpath_cmd_tl
      { [ \l_tzpath_namepath_tl , }
  }
  %% final action
  \exp_last_unbraced:Nf
    \path \l_tzpath_cmd_tl \l_tzpath_code_at_end_tl ;  %% path

  \bool_gset_false:N \g_tzpath_BEGIN_cmd_bool
  \bool_gset_false:N \g_tzpath_END_cmd_bool
}

%%% --- end of \tzpath


%%% \tzto 

\bool_new:N \g_tzto_BEGIN_cmd_bool
\bool_new:N \g_tzto_END_cmd_bool
\bool_new:N \l_tzto_shift_coor_bool

%% \tztoAtBegin
\NewDocumentCommand\tztoAtBegin{ m }
{
  \bool_gset_true:N \g_tzto_BEGIN_cmd_bool
  \tl_gset:No \g_tzto_BEGIN_cmd_tl { #1 }
}

%% \tztoAtEnd
\NewDocumentCommand\tztoAtEnd{ m }
{
  \bool_gset_true:N \g_tzto_END_cmd_bool
  \tl_gset:No \g_tzto_END_cmd_tl { #1 }
}

%%% \tzto (main)
\NewDocumentCommand\tzto{ s t+ o d<> d"" }
{
  \tl_clear:N \l_tzto_cmd_tl

  \IfBooleanTF { #1 } % (*) or not  (NOT USED!)
  { \bool_set_true:N \l_tmpa_bool }
  { \bool_set_false:N \l_tmpa_bool }

  \IfBooleanTF { #2 } % (+) or not
  { \bool_set_true:N \l_tmpb_bool }
  { \bool_set_false:N \l_tmpb_bool }

  \IfValueTF { #4 }
  {
    \tl_set:Nn \l_tzto_shift_coor_tl { #4 } 
    \bool_set_true:N \l_tzto_shift_coor_bool
  }
  { 
    \tl_clear:N \l_tzto_shift_coor_tl 
    \bool_set_false:N \l_tzto_shift_coor_bool
  }

  \IfValueTF { #3 }
  { \tl_set:Nn \l_tzto_opt_tl { #3 } }
  { \tl_clear:N \l_tzto_opt_tl }

  \IfValueTF { #5 }
  { \tl_set:Nn \l_tzto_namepath_tl { name~path = #5 } }
  { \tl_clear:N \l_tzto_namepath_tl }

  \tzto_check_token:n
}

\cs_new:Npn \tzto_check_token:n #1
{
  \str_if_eq:nnT { #1 } { ( }
    { \tzto_sub_fn ( }
%  \tzto_stop_action
}

\NewDocumentCommand\tzto_sub_fn{ r() +G{} O{} r() +G{} O{} D<>{} }
{

  \bool_if:NTF \l_tzto_shift_coor_bool
  {% if shift
    \tl_put_right:Nx \l_tzto_cmd_tl 
    { ([ shift = { (\l_tzto_shift_coor_tl) } ]#1) }
  }
  { \tl_put_right:Nn \l_tzto_cmd_tl { (#1) } }

  \tl_put_right:Nn \l_tzto_cmd_tl
    { to ~node [ above , #3 ] { #2 } }

  \bool_if:NTF \l_tmpb_bool
  {% if ++
    \tl_put_right:Nn \l_tzto_cmd_tl { ++ (#4) }
  }
  {% no ++
    \bool_if:NTF \l_tzto_shift_coor_bool
    {% if shift
      \tl_put_right:Nx \l_tzto_cmd_tl 
      { ([ shift = { (\l_tzto_shift_coor_tl) } ]#4) } 
    }
    { \tl_put_right:Nn \l_tzto_cmd_tl { (#4) } }
  }
  
  \tl_put_right:Nn \l_tzto_cmd_tl
    { node [ #6 ] { #5 } }

  % add at begin/end
  \bool_if:NT \g_tzto_BEGIN_cmd_bool
    { \tl_put_left:Nx \l_tzto_cmd_tl { \g_tzto_BEGIN_cmd_tl } }
  \bool_if:NT \g_tzto_END_cmd_bool
    { \tl_put_right:Nx \l_tzto_cmd_tl { \g_tzto_END_cmd_tl } }

  % final action
  \tl_put_left:No \l_tzto_cmd_tl
  {
    \l_tzto_opt_tl ]    % expand `once' needed
  }

  \tl_put_left:Nx \l_tzto_cmd_tl
    { [ \l_tzto_namepath_tl , }

  \exp_last_unbraced:Nf \draw \l_tzto_cmd_tl #7 ;

  \bool_gset_false:N \g_tzto_BEGIN_cmd_bool
  \bool_gset_false:N \g_tzto_END_cmd_bool
%  \tl_clear:N \g_tzto_BEGIN_cmd_tl
%  \tl_clear:N \g_tzto_END_cmd_tl
}

%%% --- end of \tzto


%%% \tztos (longer version of \tzto)

\bool_new:N \g_tztos_BEGIN_cmd_bool
\bool_new:N \g_tztos_END_cmd_bool
\bool_new:N \l_tztos_shift_coor_bool

%% \tztosAtBegin
\NewDocumentCommand\tztosAtBegin{ m }
{
  \bool_gset_true:N \g_tztos_BEGIN_cmd_bool
  \tl_gset:No \g_tztos_BEGIN_cmd_tl { #1 }
}

%% \tztosAtEnd
\NewDocumentCommand\tztosAtEnd{ m }
{
  \bool_gset_true:N \g_tztos_END_cmd_bool
  \tl_gset:No \g_tztos_END_cmd_tl { #1 }
}

%%% \tztos (main)
%% do not use: inner sep=0pt
\NewDocumentCommand\tztos{ s t+ O{} d<> D""{} }
{
  \tl_clear:N \l_tztos_cmd_tl
  \tl_clear:N \l_tztos_STYLE_tl

%  \IfValueT { #3 }
%  { \renewcommand\tztostyle{ #3 } }

  \IfBooleanTF { #1 } % (*) or not  (NOT USED!)
  { \bool_set_true:N \l_tmpa_bool }
  { \bool_set_false:N \l_tmpa_bool }

  \IfBooleanTF { #2 } % (+) or not
  { \bool_set_true:N \l_tmpb_bool }
  { \bool_set_false:N \l_tmpb_bool }

  \IfValueTF { #4 }
  {
    \tl_set:Nn \l_tztos_shift_coor_tl { #4 } 
    \bool_set_true:N \l_tztos_shift_coor_bool
  }
  { 
    \tl_clear:N \l_tztos_shift_coor_tl 
    \bool_set_false:N \l_tztos_shift_coor_bool
  }

  \IfValueTF { #3 }
  { \tl_set:Nn \l_tztos_opt_tl { #3 } }
  { \tl_clear:N \l_tztos_opt_tl }

  \IfValueTF { #5 }
  { \tl_set:Nn \l_tztos_namepath_tl { name~path = #5 } }
  { \tl_clear:N \l_tztos_namepath_tl }

  \int_zero:N \l_tmpa_int
  \tztos_check_token:n
}

\cs_new:Npn \tztos_check_token:n #1
{
%  \token_if_eq_charcode:NNTF #1 (
%  { \tztos_sub_fn #1 }
%  { \tztos_stop_action }
  \str_case:nnF { #1 }
  {
    { ( } { \tztos_sub_fn #1 }
    { ; } { \tztos_late_opt_fn }
  }
  {
    \tztos_stop_action
  }
}

%% (coor)[to opt]{text}[node opt]
\NewDocumentCommand\tztos_sub_fn{ r() O{} +G{} O{} }
{
  \int_incr:N \l_tmpa_int
  % (from the second round) put line STYLE before the next cmd-tl
  \int_compare:nT { \l_tmpa_int > 1 }
  {
    \tl_put_right:No \l_tztos_cmd_tl { \l_tztos_STYLE_tl }
    \tl_clear:N \l_tztos_STYLE_tl    
  }

  % collect cmd-tl
  \bool_if:NTF \l_tztos_shift_coor_bool
  {% shift-coor
    \bool_if:NTF \l_tmpb_bool
    {% if ++
      \int_compare:nTF { \l_tmpa_int > 1 }
      { \tl_put_right:Nn \l_tztos_cmd_tl { (#1) } } % no shift from 2nd
      {
        \tl_put_right:Nx \l_tztos_cmd_tl
        { ([ shift = { (\l_tztos_shift_coor_tl) } ]#1) } % shift first
      }
    }
    {% no ++
      \tl_put_right:Nx \l_tztos_cmd_tl
      { ([ shift = { (\l_tztos_shift_coor_tl) } ]#1) } % shift all coors
    }
  }
  { \tl_put_right:Nn \l_tztos_cmd_tl { (#1) } } % no shift (normal)

  % (from the first round on) determine and save STYLE
  % determine connect line STYLE
  \tl_set:Nn \l_tztos_STYLE_A_tl { ~ to [ #2 ] }
  % save node info (for later use, at the end)
  \tl_if_empty:nTF { #3 }
  {
    \tl_clear:N \l_tztos_STYLE_B_tl
  }
  {
    \tl_set:Nn \l_tztos_STYLE_B_tl 
      { ~ node [ #4 ] { #3 } }
  }
  \bool_if:NTF \l_tmpb_bool
    { \tl_set:Nn \l_tztos_STYLE_C_tl { ++ } }
    { \tl_set:Nn \l_tztos_STYLE_C_tl {    } }

  \tl_put_right:No \l_tztos_STYLE_tl { \l_tztos_STYLE_A_tl }
  \tl_put_right:No \l_tztos_STYLE_tl { \l_tztos_STYLE_B_tl }
  \tl_put_right:No \l_tztos_STYLE_tl { \l_tztos_STYLE_C_tl }
  
  \tztos_check_token:n
}

\NewDocumentCommand\tztos_late_opt_fn { D<>{} }
{
  \tl_set:Nn \l_tztos_code_at_end_tl { #1 }
  \tztos_stop_action
}

\NewDocumentCommand\tztos_stop_action {}
{
  \tl_if_empty:NF \l_tztos_STYLE_B_tl
  {
    \tl_put_right:No \l_tztos_cmd_tl { \l_tztos_STYLE_B_tl }
  }
  \tl_clear:N \l_tztos_STYLE_tl
  % add at begin/end
  \bool_if:NT \g_tztos_BEGIN_cmd_bool
    { \tl_put_left:Nx \l_tztos_cmd_tl { \g_tztos_BEGIN_cmd_tl } }
  \bool_if:NT \g_tztos_END_cmd_bool
    { \tl_put_right:Nx \l_tztos_cmd_tl { \g_tztos_END_cmd_tl } }
  % fill or not
  \tl_put_left:No \l_tztos_cmd_tl
  {
    \l_tztos_opt_tl ]    % expand `once' needed for user convenience
  }
  \tl_put_left:Nx \l_tztos_cmd_tl
    { [ \l_tztos_namepath_tl , }
  % final action
  \exp_last_unbraced:Nf
    \draw \l_tztos_cmd_tl \l_tztos_code_at_end_tl ;  %% draw

  \bool_gset_false:N \g_tztos_BEGIN_cmd_bool
  \bool_gset_false:N \g_tztos_END_cmd_bool
%  \tl_clear:N \g_tztos_BEGIN_cmd_tl
%  \tl_clear:N \g_tztos_END_cmd_tl
}

%%% --- end of \tztos


%%%%% Figures: circles, frames, ellipses, triangles, etc.

%%% \tzcircle

\NewDocumentCommand\tzcircle
  { s O{} d<> D""{} r() r() G{\tz@initial@fill@opacity} }
{
  \renewcommand\tzfillopacity{#7}
  \IfBooleanTF { #1 }
  {
    \IfValueTF { #3 }
    {% if shift
      \draw [ fill = \tzfillcolor , fill~opacity = #7 , 
              text~opacity = 1 ,
              name~path = #4 , #2 ] ([shift={(#3)}]#5) circle (#6) ;
    }
    {% no shift (normal)
      \draw [ fill = \tzfillcolor , fill~opacity = #7 , 
              text~opacity = 1 ,
              name~path = #4 , #2 ] (#5) circle (#6) ;
    }
  }
  {
    \IfValueTF { #3 }
    { \draw [ #2 ] ([shift={(#3)}]#5) circle (#6) ; }
    { \draw [ #2 ] (#5) circle (#6) ; }
  }
}

%%% \tzellipse

\NewDocumentCommand\tzellipse
  { s O{} d<> D""{} r() r() G{\tz@initial@fill@opacity} }
{
  \renewcommand\tzfillopacity{#7}
  \IfBooleanTF { #1 }
  {
    \IfValueTF { #3 }
    {% if shift
      \draw [ fill = \tzfillcolor , fill~opacity = #7 , 
              text~opacity = 1 ,
              name~path = #4 , #2 ] ([shift={(#3)}]#5) ellipse (#6) ;
    }
    {% no shift (normal)
      \draw [ fill = \tzfillcolor , fill~opacity = #7 , 
              text~opacity = 1 ,
              name~path = #4 , #2 ] (#5) ellipse (#6) ;
    }
  }
  {
    \IfValueTF { #3 }
    { \draw [ name~path = #4 , #2 ] ([shift={(#3)}]#5) ellipse (#6) ; }
    { \draw [ name~path = #4 , #2 ] (#5) ellipse (#6) ; }
  }
}


%%% \tzframe

\NewDocumentCommand\tzframe
  { s t+ O{} d<> D""{} r() r() G{\tz@initial@fill@opacity} }
{
  \renewcommand\tzfillopacity{#8}
  \IfBooleanTF { #1 }
  {
    \IfBooleanTF { #2 }
    {
      \IfValueTF { #4 }
      {% if shift
        \draw [ fill = \tzfillcolor , fill~opacity = \tzfillopacity , 
                text~opacity = 1 ,
                name~path = #5 , #3 ] 
              ([shift={(#4)}]#6) rectangle ++ (#7) ;
      }
      {% no shift
        \draw [ fill = \tzfillcolor , fill~opacity = \tzfillopacity , 
                text~opacity = 1 ,
                name~path = #5 , #3 ] 
              (#6) rectangle ++ (#7) ;
      }
    }
    {
      \IfValueTF { #4 }
      {% if shift
        \draw [ fill = \tzfillcolor , fill~opacity = \tzfillopacity , 
                text~opacity = 1 ,
                name~path = #5 , #3 ] 
              ([shift={(#4)}]#6) rectangle    ([shift={(#4)}]#7) ;
      }
      {% no shift
        \draw [ fill = \tzfillcolor , fill~opacity = \tzfillopacity , 
                text~opacity = 1 ,
                name~path = #5 , #3 ] 
              (#6) rectangle    (#7) ;
      }
    }
  }
  {
    \IfBooleanTF { #2 }
    { 
      \IfValueTF { #4 }
      {% if shift
        \draw [ name~path = #5 , #3 ] 
              ([shift={(#4)}]#6) rectangle ++ (#7) ; 
      }
      {% no shift
        \draw [ name~path = #5 , #3 ] (#6) rectangle ++ (#7) ; 
      }
    }
    { 
      \IfValueTF { #4 }
      {% if shift
        \draw [ name~path = #5 , #3 ] 
              ([shift={(#4)}]#6) rectangle    ([shift={(#4)}]#7) ; 
      }
      {% no shift
        \draw [ name~path = #5 , #3 ] (#6) rectangle    (#7) ; 
      }
    }
  }
}


%%% \tzparabola

\bool_new:N \l_tzparabola_shift_coor_bool

\NewDocumentCommand\tzparabola
{ s t+ O{} d<> D""{} }
{
  \tl_clear:N \l_tzparabola_cmd_tl
  
  \IfBooleanTF { #1 } % NOT USED!!!
  { \bool_set_true:N \l_tmpa_bool }
  { \bool_set_false:N \l_tmpa_bool }

  \IfBooleanTF { #2 }
  { \bool_set_true:N \l_tmpb_bool }
  { \bool_set_false:N \l_tmpb_bool }
  
  \IfValueTF { #5 }
  { \tl_set:Nn \l_tzparabola_pathname_tl { name~path = #5 } }
  { \tl_clear:N \l_tzparabola_pathname_tl }

  \IfValueTF { #4 }
  {
    \tl_set:Nn \l_tzparabola_shift_coor_tl { #4 } 
    \bool_set_true:N \l_tzparabola_shift_coor_bool
  }
  { 
    \tl_clear:N \l_tzparabola_shift_coor_tl 
    \bool_set_false:N \l_tzparabola_shift_coor_bool
  }

  \IfValueTF { #3 }
  { \tl_set:Nn \l_tzparabola_opt_tl { #3 } }
  { \tl_clear:N \l_tzparabola_opt_tl }

  \tzparabola_check_token:n
}

\cs_new:Npn \tzparabola_check_token:n #1
{
  \str_if_eq:nnT { #1 } { ( }
    { \tzparabola_sub_fn ( }
%  \tzparabola_stop_action
}

\NewDocumentCommand\tzparabola_sub_fn
  { r() r() d() +G{} O{} G{\tz@initial@fill@opacity} D<>{} }
{
  \renewcommand\tzfillopacity{#6} %% NOT USED! (to be removed)

  \bool_if:NTF \l_tzparabola_shift_coor_bool
  {% if shift
    \tl_put_right:Nx \l_tzparabola_cmd_tl
    { ([shift = { (\l_tzparabola_shift_coor_tl) } ]#1) }
  }
  {% no shift (normal)
    \tl_put_right:Nn \l_tzparabola_cmd_tl { (#1) }
  }
  
  \IfNoValueTF { #3 }
  {%% 2 coors
    \bool_if:NTF \l_tmpb_bool
    {% if + (relative coor)
      \bool_if:NTF \l_tzparabola_shift_coor_bool
      {% if shift
        \tl_put_right:Nx \l_tzparabola_cmd_tl 
        { parabola ([shift = { (\l_tzparabola_shift_coor_tl) } ]$(#1)+(#2)$) }
      }
      {% no shift (normal)
        \tl_put_right:Nn \l_tzparabola_cmd_tl { parabola ($(#1)+(#2)$) }
      }
    }
    {% no + (absolute coor)
      \bool_if:NTF \l_tzparabola_shift_coor_bool
      {% if shift
        \tl_put_right:Nx \l_tzparabola_cmd_tl 
        { parabola ([shift = { (\l_tzparabola_shift_coor_tl) } ]#2) }
      }
      {% no shift (normal)
        \tl_put_right:Nn \l_tzparabola_cmd_tl { parabola (#2) }
      }
    }
  }
  {%% 3 coors
    \bool_if:NTF \l_tmpb_bool
    {% if + (relative coor)
      \tl_put_right:Nn \l_tzparabola_cmd_tl 
      { parabola~bend + (#2) }
      \bool_if:NTF \l_tzparabola_shift_coor_bool
      {% if shift
        \tl_put_right:Nx \l_tzparabola_cmd_tl 
        { ([shift = { (\l_tzparabola_shift_coor_tl) } ]$(#1)+(#3)$) }
      }
      {% no shift (normal)
        \tl_put_right:Nn \l_tzparabola_cmd_tl { ($(#1)+(#3)$) } 
      }
    }
    {% no + (absolute coor)
      \bool_if:NTF \l_tzparabola_shift_coor_bool
      {
        \tl_put_right:Nx \l_tzparabola_cmd_tl 
        {
          parabola~bend 
          ([shift = { (\l_tzparabola_shift_coor_tl) } ]#2) 
        }
      }
      {
        \tl_put_right:Nn \l_tzparabola_cmd_tl 
        { parabola~bend (#2) }
      }
      \bool_if:NTF \l_tzparabola_shift_coor_bool
      {% if shift
        \tl_put_right:Nx \l_tzparabola_cmd_tl 
        { ([shift = { (\l_tzparabola_shift_coor_tl) } ]#3) }
      }
      {% no shift (normal)
        \tl_put_right:Nn \l_tzparabola_cmd_tl { (#3) } 
      }
    }
  }
  
  \tl_put_left:No \l_tzparabola_cmd_tl 
    { \l_tzparabola_opt_tl ] } % expand `once'
  \tl_put_left:Nx \l_tzparabola_cmd_tl 
    { [ \l_tzparabola_pathname_tl , }
  % final action
  \exp_last_unbraced:Nf 
    \draw \l_tzparabola_cmd_tl node [ #5 ] { #4 } #7 ;
}

%%% -- end of \tzparabola


%%% \tzbezier

\bool_new:N \l_tzbezier_shift_coor_bool

\NewDocumentCommand\tzbezier{ s t+ O{} d<> D""{tzplot~path} }
{
  \tl_clear:N \l_tzbezier_cmd_tl
  
  \IfBooleanTF { #1 } %% NOT USED!
  { \bool_set_true:N \l_tmpa_bool }
  { \bool_set_true:N \l_tmpa_bool }
  
  \IfBooleanTF { #2 }
  { \bool_set_true:N \l_tmpb_bool }
  { \bool_set_false:N \l_tmpb_bool }

  \IfValueTF { #5 }
  { \tl_set:Nn \l_tzbezier_pathname_tl { name~path = #5 } }
  { \tl_clear:N \l_tzbezier_pathname_tl }
  
  \IfValueTF { #4 }
  {
    \tl_set:Nn \l_tzbezier_shift_coor_tl { #4 } 
    \bool_set_true:N \l_tzbezier_shift_coor_bool
  }
  { 
    \tl_clear:N \l_tzbezier_shift_coor_tl 
    \bool_set_false:N \l_tzbezier_shift_coor_bool
  }

  \IfValueTF { #3 }
  { \tl_set:Nn \l_tzbezier_opt_tl { #3 } }
  { \tl_clear:N \l_tzbezier_opt_tl }

  \tzbezier_check_token:n
}

\cs_new:Npn \tzbezier_check_token:n #1
{
  \str_if_eq:nnT { #1 } { ( }
    { \tzbezier_sub_fn ( }
%  \tzbezier_stop_action
}

\NewDocumentCommand\tzbezier_sub_fn{ r() r() r() d() +G{} O{} D<>{} }
{
  \bool_if:NTF \l_tzbezier_shift_coor_bool
  {% if shift
    \tl_put_right:Nx \l_tzbezier_cmd_tl 
    { ([shift = { (\l_tzbezier_shift_coor_tl) } ]#1) .. controls }
  }
  {% no shift (normal)
    \tl_put_right:Nn \l_tzbezier_cmd_tl { (#1) .. controls }
  }

  \IfNoValueTF { #4 }
  {%% 3 coors
    \bool_if:NTF \l_tmpb_bool
    {% if + (relative coor)
      \tl_put_right:Nn \l_tzbezier_cmd_tl { + (#2) }
      \bool_if:NTF \l_tzbezier_shift_coor_bool
      {% if shift
        \tl_put_right:Nx \l_tzbezier_cmd_tl 
        { .. ([shift = { (\l_tzbezier_shift_coor_tl) } ]$(#1)+(#3)$) }
      }
      {% no shift (normal)
        \tl_put_right:Nn \l_tzbezier_cmd_tl { .. ($(#1)+(#3)$) }
      }
    }
    {% no + (absolute coor)
      % control coor
      \bool_if:NTF \l_tzbezier_shift_coor_bool 
      {% if shift
        \tl_put_right:Nx \l_tzbezier_cmd_tl
        { ([ shift = { (\l_tzbezier_shift_coor_tl) } ]#2) }
      }
      {% no shift (normal)
        \tl_put_right:Nn \l_tzbezier_cmd_tl { (#2) }
      }
      %% end coor
      \bool_if:NTF \l_tzbezier_shift_coor_bool
      {% if shift
        \tl_put_right:Nx \l_tzbezier_cmd_tl 
        { .. ([shift = { (\l_tzbezier_shift_coor_tl) } ]#3) }
      }
      {% no shift (normal)
        \tl_put_right:Nn \l_tzbezier_cmd_tl { .. (#3) }
      }
    }
  }
  {%% 4 coors
    \bool_if:NTF \l_tmpb_bool
    {% if + (relative coor)
      \tl_put_right:Nn \l_tzbezier_cmd_tl { + (#2) and + (#3) }
      \bool_if:NTF \l_tzbezier_shift_coor_bool
      {% if shift
        \tl_put_right:Nx \l_tzbezier_cmd_tl 
        { .. ([shift = { (\l_tzbezier_shift_coor_tl) } ]$(#1)+(#4)$) }
      }
      {% no shift (normal)
        \tl_put_right:Nn \l_tzbezier_cmd_tl { .. ($(#1)+(#4)$) }
      }
    }
    {% no + (absolute coor)
      %% control coors
      \bool_if:NTF \l_tzbezier_shift_coor_bool 
      {% if shift
        \tl_put_right:Nx \l_tzbezier_cmd_tl
        {
          ([ shift = { (\l_tzbezier_shift_coor_tl) } ]#2) 
          and
          ([ shift = { (\l_tzbezier_shift_coor_tl) } ]#3) 
        }
      }
      {% no shift (normal)
        \tl_put_right:Nn \l_tzbezier_cmd_tl { (#2) and (#3) } 
      }
      %% end coor
      \bool_if:NTF \l_tzbezier_shift_coor_bool
      {% if shift
        \tl_put_right:Nx \l_tzbezier_cmd_tl 
        { .. ([shift = { (\l_tzbezier_shift_coor_tl) } ]#4) }
      }
      {% no shift (normal)
        \tl_put_right:Nn \l_tzbezier_cmd_tl { .. (#4) }
      }
    }
  }
  
  \tl_put_left:No \l_tzbezier_cmd_tl { \l_tzbezier_opt_tl ] }
  \tl_put_left:Nx \l_tzbezier_cmd_tl
    { [ \l_tzbezier_pathname_tl , }
  % final action
  \exp_last_unbraced:Nf \draw \l_tzbezier_cmd_tl node [ #6 ] { #5 } #7 ;
}

%%% -- end of \tzbezier


%%% \tzarc

\use:x{
  \NewDocumentCommand \exp_not:N \tzarc
  { s t' O{} d<> D""{} r()
    >{ \SplitArgument {2} { \tl_to_str:n {:} } } r()
  }
}
{
  \IfBooleanTF { #1 } {}{}  % NOT USED!

  \tl_clear:N \l_tzarc_cmd_tl
  
  \tzarc_args_process #7
  \fp_set:Nn \l_tmpa_fp { \tzarcAngleA }
  \fp_set:Nn \l_tmpb_fp { \tzarcAngleB }

  \tl_put_right:Nn \l_tzarc_cmd_tl
    { [ name~path = #5 , #3 ] }
  \IfValueTF { #4 }
  {% if shift
    \tl_put_right:Nn \l_tzarc_cmd_tl
    { ([shift={(#4)}]#6) ++ (\tzarcAngleA \c_colon_str \tzarcRadius) }
  }
  {% no shift (normal)
    \tl_put_right:Nn \l_tzarc_cmd_tl
    { (#6) ++ (\tzarcAngleA \c_colon_str \tzarcRadius) }
  }
  
  \tl_put_right:Nx \l_tzarc_cmd_tl
    {
      \fp_compare:nTF { \l_tmpa_fp < \l_tmpb_fp }
      {
        arc ( \tzarcAngleA
              \c_colon_str
              \IfBooleanTF {#2} 
                {\tzarcAngleB - 360} 
                {\tzarcAngleB}
              \c_colon_str
              \tzarcRadius )
      }
      {
        arc ( \IfBooleanTF {#2} 
                {\tzarcAngleA - 360} 
                {\tzarcAngleA}
              \c_colon_str
              \tzarcAngleB
              \c_colon_str
              \tzarcRadius )
      }
    }
  
  \tzarc_sub_fn:n
}

\NewDocumentCommand\tzarc_args_process{ m m m }
{
  \def\tzarcAngleA{#1}
  \def\tzarcAngleB{#2}
  \def\tzarcRadius{#3}
}

\cs_new:Npn \tzarc_sub_fn:n
{
  \tzarc_final_actions
}

\NewDocumentCommand\tzarc_final_actions{ +G{} O{} D<>{} }
{
  \tl_put_right:Nn \l_tzarc_cmd_tl
    { node [ #2 ] { #1 } #3 }

  \exp_last_unbraced:Nf \draw \l_tzarc_cmd_tl ;
}

%%% --- end of \tzarc



%%% \tzarcfrom  % (works like tikz original)

\use:x{
  \NewDocumentCommand \exp_not:N \tzarcfrom
  { s t' O{} d<> D""{} r()
    >{ \SplitArgument {2} { \tl_to_str:n {:} } } r()
  }
}
{
  \IfBooleanTF { #1 } {}{}  % NOT USED!

  \tl_clear:N \l_tzarcfrom_cmd_tl

  \tzarcfrom_args_process #7
  \fp_set:Nn \l_tmpa_fp { \tzarcfromAngleA }
  \fp_set:Nn \l_tmpb_fp { \tzarcfromAngleB }

  \tl_put_right:Nn \l_tzarcfrom_cmd_tl
    { [ name~path = #5 , #3 ] }

  \IfValueTF { #4 }
  {% if shift
    \tl_put_right:Nn \l_tzarcfrom_cmd_tl
      { ([shift={(#4)}]#6) }
  }
  {% no shift (normal)
    \tl_put_right:Nn \l_tzarcfrom_cmd_tl
      { (#6) } % ++ (\tzarcfromAngleA \c_colon_str \tzarcfromRadius)
  }
  
  \tl_put_right:No \l_tzarcfrom_cmd_tl
    {
      \fp_compare:nTF { \l_tmpa_fp < \l_tmpb_fp }
      {
        arc ( \tzarcfromAngleA
              \c_colon_str
              \IfBooleanTF {#2} 
                {\tzarcfromAngleB - 360} 
                {\tzarcfromAngleB}
              \c_colon_str
              \tzarcfromRadius )
      }
      {
        arc ( \IfBooleanTF {#2} 
                {\tzarcfromAngleA - 360} 
                {\tzarcfromAngleA}
              \c_colon_str
              \tzarcfromAngleB
              \c_colon_str
              \tzarcfromRadius )
      }
    }

  \tzarcfrom_sub_fn:n

}

\NewDocumentCommand\tzarcfrom_args_process{ m m m }
{
  \def\tzarcfromAngleA{#1}
  \def\tzarcfromAngleB{#2}
  \def\tzarcfromRadius{#3}
}

\cs_new:Npn \tzarcfrom_sub_fn:n
{
  \tzarcfrom_final_actions
}

\NewDocumentCommand\tzarcfrom_final_actions{ +G{} O{} D<>{} }
{
  \tl_put_right:Nn \l_tzarcfrom_cmd_tl
    { node [ #2 ] { #1 } #3 }
  \exp_last_unbraced:Nf \draw \l_tzarcfrom_cmd_tl ;
}

%%% --- end of \tzarcfrom


%%% \tzarcsfrom  % (works like tikz original)

\tl_new:N \l_tzarcsfrom_code_at_end_tl

\NewDocumentCommand\tzarcsfrom { s t' O{} d<> D""{} r() }
{
  \IfBooleanTF { #1 } {}{}  % NOT USED!
  { \bool_set_true:N \l_tmpa_bool }
  { \bool_set_false:N \l_tmpa_bool }

  \IfBooleanTF { #2 }
  { \bool_set_true:N \l_tmpb_bool }
  { \bool_set_false:N \l_tmpb_bool }

  \tl_clear:N \l_tzarcsfrom_cmd_tl
  \tl_put_right:Nn \l_tzarcsfrom_cmd_tl
    { [ name~path = #5 , #3 ] }

  \IfValueTF { #4 }
  {% if shift
    \tl_put_right:Nn \l_tzarcsfrom_cmd_tl
      { ([shift={(#4)}]#6) }
  }
  {% no shift
    \tl_put_right:Nn \l_tzarcsfrom_cmd_tl
      { (#6) } % ++ (\tzarcsfromAngleA \c_colon_str \tzarcsfromRadius)
  }

  \tzarcsfrom_check_token:n  
}

\cs_new:Npn \tzarcsfrom_check_token:n #1
{
  \str_case:nnF { #1 }
  {
    { ( } { \tzarcsfrom_sub_fn #1 }
    { ; } { \tzarcsfrom_late_opt_fn }
  }
  {
    \tzarcsfrom_stop_action
  }
}


\use:x{
  \NewDocumentCommand \exp_not:N \tzarcsfrom_sub_fn
  { >{ \SplitArgument {2} { \tl_to_str:n {:} } } r() +G{} O{} 
  }
}
{
  \tzarcsfrom_args_process #1
  \fp_set:Nn \l_tmpa_fp { \tzarcsfromAngleA }
  \fp_set:Nn \l_tmpb_fp { \tzarcsfromAngleB }

  \tl_put_right:Nx \l_tzarcsfrom_cmd_tl
    {
      \fp_compare:nTF { \l_tmpa_fp < \l_tmpb_fp }
      {
        arc ( \tzarcsfromAngleA
              \c_colon_str
              \bool_if:NTF \l_tmpb_bool
                {\tzarcsfromAngleB - 360} 
                {\tzarcsfromAngleB}
              \c_colon_str
              \tzarcsfromRadius )
      }
      {
        arc ( \bool_if:NTF \l_tmpb_bool
                {\tzarcsfromAngleA - 360} 
                {\tzarcsfromAngleA}
              \c_colon_str
              \tzarcsfromAngleB
              \c_colon_str
              \tzarcsfromRadius )
      }
    }
  \tl_put_right:Nn \l_tzarcsfrom_cmd_tl
    { node [ #3 ] { #2 } }

  \tzarcsfrom_check_token:n
}

\NewDocumentCommand\tzarcsfrom_late_opt_fn { D<>{} }
{
  \tl_set:Nn \l_tzarcsfrom_code_at_end_tl { #1 }
  \tzarcsfrom_stop_action
}

\NewDocumentCommand\tzarcsfrom_stop_action {}
{
  \tl_put_right:No \l_tzarcsfrom_cmd_tl
    { \l_tzarcsfrom_code_at_end_tl }
  \exp_last_unbraced:Nf \draw \l_tzarcsfrom_cmd_tl ;
}

\NewDocumentCommand\tzarcsfrom_args_process{ m m m }
{
  \def\tzarcsfromAngleA{#1}
  \def\tzarcsfromAngleB{#2}
  \def\tzarcsfromRadius{#3}
}

%%% --- end of \tzarcsfrom



%%% \tzwedge

\use:x{
  \NewDocumentCommand \exp_not:N \tzwedge
  { s t' O{} d<> D""{} r()
    >{ \SplitArgument {2} { \tl_to_str:n {:} } } r() 
  }
}
{
  \tl_clear:N \l_tzwedge_cmd_tl
  
  \tzwedge_args_process #7
  \fp_set:Nn \l_tmpa_fp { \tzwedgeAngleA }
  \fp_set:Nn \l_tmpb_fp { \tzwedgeAngleB }
  
  \IfBooleanTF { #1 }
  {
    \tl_put_right:Nn \l_tzwedge_cmd_tl
      {
        [ fill=\tzfillcolor , 
          fill~opacity = \tzfillopacity , text~opacity = 1 , 
          name~path = #5 , #3 ] 
      }
  }
  {
    \tl_put_right:Nn \l_tzwedge_cmd_tl
      { [ name~path = #5 , #3 ] }
  }
  
  \IfValueTF { #4 }
  {
    \tl_put_right:Nn \l_tzwedge_cmd_tl
    { ([shift={(#4)}]#6) -- ++ (\tzwedgeAngleA \c_colon_str \tzwedgeRadius) }
  }
  {
    \tl_put_right:Nn \l_tzwedge_cmd_tl
    { (#6) -- ++ (\tzwedgeAngleA \c_colon_str \tzwedgeRadius) }
  }
  
  \tl_put_right:No \l_tzwedge_cmd_tl
    {
      \fp_compare:nTF { \l_tmpa_fp < \l_tmpb_fp }
      {
        arc ( \tzwedgeAngleA
              \c_colon_str
              \IfBooleanTF {#2} 
                {\tzwedgeAngleB - 360} 
                {\tzwedgeAngleB}
              \c_colon_str
              \tzwedgeRadius )
      }
      {
        arc ( \IfBooleanTF {#2} 
                {\tzwedgeAngleA - 360} 
                {\tzwedgeAngleA}
              \c_colon_str
              \tzwedgeAngleB
              \c_colon_str
              \tzwedgeRadius )
      }
    }

  \tzwedge_sub_fn:n
}

\cs_new:Npn \tzwedge_sub_fn:n
{
  \tzwedge_final_actions
}

\NewDocumentCommand\tzwedge_final_actions{ +G{} O{} G{.3} }
{
  \tl_if_empty:nTF { #3 }
  { \renewcommand\tzfillopacity{\tz@initial@fill@opacity} }
  { \renewcommand\tzfillopacity{#3} }

  \tl_put_right:Nn \l_tzwedge_cmd_tl
    {
      node [ midway , #2 ] { #1 } 
    }

  \exp_last_unbraced:Nf \draw \l_tzwedge_cmd_tl -- cycle ;
}

\NewDocumentCommand\tzwedge_args_process{ m m m }
{
  \def\tzwedgeAngleA{#1}
  \def\tzwedgeAngleB{#2}
  \def\tzwedgeRadius{#3}
}

%%% --- end of \tzwedge


%%%%% plot of Tikz

%%% \tzplot

\bool_new:N \l_tzplot_shift_coor_bool

\NewDocumentCommand\tzplot{ s O{} G{0} O{} d<> D""{} }
{
  \tl_clear:N \l_tzplot_opt_cmd_tl
  \tl_clear:N \l_tzplot_cmd_tl
  \tl_clear:N \l_tzplot_nodes_cmd_tl
  \tl_clear:N \l_tzplot_coors_cmd_tl
  \tl_clear:N \l_tzplot_code_at_end_tl
  
  \renewcommand\tzmarksize{\tz@initial@mark@size}
  
  \tl_put_right:Nn \l_tzplot_opt_cmd_tl
  {
    [ 
      name~path = #6 , 
      tension = #3 ,
      smooth ,
      tzmark = \tzmarksize ,
  }
  
  \IfBooleanT { #1 }
  {
    \tl_put_right:Nn \l_tzplot_opt_cmd_tl 
    { mark = * , draw = none , }
  }
  
  \IfValueTF { #5 }
  {
    \tl_set:Nn \l_tzplot_shift_coor_tl { #5 }
    \bool_set_true:N \l_tzplot_shift_coor_bool
  }
  {
    \tl_clear:N \l_tzplot_shift_coor_tl
    \bool_set_false:N \l_tzplot_shift_coor_bool
  }
  
  \tl_put_right:Nn \l_tzplot_opt_cmd_tl
  {
      #2
    ]
      plot [ #4 ] coordinates
  }
  \tzplot_check_token:n
}

\cs_new:Npn \tzplot_check_token:n #1
{
%  \token_if_eq_charcode:NNTF #1 (
%  { \tzplot_sub_fn #1 }
%  { \tzplot_stop_action }
  \str_case:nnF { #1 }
  {
    { ( } { \tzplot_sub_fn #1 }
    { ; } { \tzplot_late_opt_fn }
  }
  {
    \tzplot_stop_action
  }
}

\NewDocumentCommand\tzplot_sub_fn{ r() +G{} O{} }
{
  % collect coordinates only
  \bool_if:NTF \l_tzplot_shift_coor_bool
  {
    \tl_put_right:Nx \l_tzplot_coors_cmd_tl 
    { ([shift = { (\l_tzplot_shift_coor_tl) } ]#1) }
  }
  {
    \tl_put_right:Nn \l_tzplot_coors_cmd_tl { (#1) }
  }
  % collect nodes information
  \bool_if:NTF \l_tzplot_shift_coor_bool
  {
    \tl_put_right:Nx \l_tzplot_nodes_cmd_tl 
    { ([shift = { (\l_tzplot_shift_coor_tl) } ]#1) }
  }
  {
    \tl_put_right:Nn \l_tzplot_nodes_cmd_tl { (#1) }
  }
  \tl_put_right:Nx \l_tzplot_nodes_cmd_tl
  {
    node 
    [ label = { \exp_not:n { #3 } \c_colon_str \exp_not:n { #2 } }
    ] {} 
  }
  \tzplot_check_token:n
}

\NewDocumentCommand\tzplot_late_opt_fn { d() D<>{} }
{
  \IfValueTF { #1 }
    { \edef\tztmpMarkSize { #1 } }
    { \edef\tztmpMarkSize { \tz@initial@mark@size } }
  \tl_put_right:Nn \l_tzplot_code_at_end_tl { #2 }
  \tzplot_stop_action
}

\NewDocumentCommand\tzplot_stop_action {}
{
  \renewcommand\tzmarksize{ \tztmpMarkSize }
  % final action
  \exp_last_unbraced:Nf
    \draw
      \l_tzplot_opt_cmd_tl       % [opt] plot coordinates
      { \l_tzplot_coors_cmd_tl } % { (coor-1)(coor-2)...(coor-n) }
      \l_tzplot_code_at_end_tl   % should precede _nodes_cmd_tl
      \l_tzplot_nodes_cmd_tl     % (coor-i) node [opt] {text}, for all i
    ;
}

%%% --- end of \tzplot


%%% \tzplotcurve

\bool_new:N \l_tzplotcurve_shift_coor_bool

\NewDocumentCommand\tzplotcurve{ s O{} G{1} O{} d<> D""{} }
{
  \IfBooleanT { #1 } {}{} % NOT USED!

  \tl_clear:N \l_tzplotcurve_opt_cmd_tl
  \tl_clear:N \l_tzplotcurve_cmd_tl
  \tl_clear:N \l_tzplotcurve_nodes_cmd_tl
  \tl_clear:N \l_tzplotcurve_coors_cmd_tl
  \tl_clear:N \l_tzplotcurve_code_at_end_tl

  \tl_put_right:Nn \l_tzplotcurve_opt_cmd_tl
  {
    [ name~path = #6 ,
      tension = #3 , 
      smooth , 
      tzmark = \tzmarksize ,
  }

  \IfBooleanT { #1 }
  {
    \tl_put_right:Nn \l_tzplotcurve_opt_cmd_tl 
    { mark = * , }
  }

  \IfValueTF { #5 }
  {
    \tl_set:Nn \l_tzplotcurve_shift_coor_tl { #5 }
    \bool_set_true:N \l_tzplotcurve_shift_coor_bool
  }
  {
    \tl_clear:N \l_tzplotcurve_shift_coor_tl
    \bool_set_false:N \l_tzplotcurve_shift_coor_bool
  }
  
  \tl_put_right:Nn \l_tzplotcurve_opt_cmd_tl
  {
      #2 
    ]
    plot [ #4 ] coordinates
  }
  \tzplotcurve_check_token:n
}

\cs_new:Npn \tzplotcurve_check_token:n #1
{
%  \token_if_eq_charcode:NNTF #1 (
%  { \tzplotcurve_sub_fn #1 }
%  { \tzplotcurve_stop_action }
  \str_case:nnF { #1 }
  {
    { ( } { \tzplotcurve_sub_fn #1 }
    { ; } { \tzplotcurve_late_opt_fn }
  }
  {
    \tzplotcurve_stop_action
  }
}

\NewDocumentCommand\tzplotcurve_sub_fn{ r() +G{} O{} }
{
  % collect coordinates only
  \bool_if:NTF \l_tzplotcurve_shift_coor_bool
  {
    \tl_put_right:Nx \l_tzplotcurve_coors_cmd_tl 
    { ([shift = { (\l_tzplotcurve_shift_coor_tl) } ]#1) }
  }
  {
    \tl_put_right:Nn \l_tzplotcurve_coors_cmd_tl { (#1) }
  }
  % collect nodes information
  \bool_if:NTF \l_tzplotcurve_shift_coor_bool
  {
    \tl_put_right:Nx \l_tzplotcurve_nodes_cmd_tl 
    { ([shift = { (\l_tzplotcurve_shift_coor_tl) } ]#1) }
  }
  {
    \tl_put_right:Nn \l_tzplotcurve_nodes_cmd_tl { (#1) }
  }
  \tl_put_right:Nx \l_tzplotcurve_nodes_cmd_tl
    { node 
      [ label = { \exp_not:n { #3 } \c_colon_str \exp_not:n { #2 } }
      ] {} 
    }
  \tzplotcurve_check_token:n
}

\NewDocumentCommand\tzplotcurve_late_opt_fn { d() D<>{} }
{
  \IfValueTF { #1 }
    { \edef\tztmpMarkSize { #1 } }
    { \edef\tztmpMarkSize { \tz@initial@mark@size } }
  \tl_put_right:Nn \l_tzplotcurve_code_at_end_tl { #2 }
  \tzplotcurve_stop_action
}

\NewDocumentCommand\tzplotcurve_stop_action {}
{
  \renewcommand\tzmarksize{ \tztmpMarkSize }
  % final action
  \exp_last_unbraced:Nf
    \draw
      \l_tzplotcurve_opt_cmd_tl       % [opt] plot [ smooth ] coordinates
      { \l_tzplotcurve_coors_cmd_tl } % { (coor-1)(coor-2)...(coor-n) }
      \l_tzplotcurve_code_at_end_tl   % should precede _nodes_cmd_tl
      \l_tzplotcurve_nodes_cmd_tl     % (coor-i) node [opt] {text}, for all i
    ;
}

%%% --- end of \tzplotcurve


%%% \tzLFn  -- plot Linear Function (LF)

\bool_new:N \g_tzLFn_BEGIN_cmd_bool
\bool_new:N \g_tzLFn_END_cmd_bool

%% \tzLFnAtBegin
\NewDocumentCommand\tzLFnAtBegin{ m }
{
  \bool_gset_true:N \g_tzLFn_BEGIN_cmd_bool
  \tl_gset:No \g_tzLFn_BEGIN_cmd_tl { #1 }
}

%% \tzLFnAtEnd
\NewDocumentCommand\tzLFnAtEnd{ m }
{
  \bool_gset_true:N \g_tzLFn_END_cmd_bool
  \tl_gset:No \g_tzLFn_END_cmd_tl { #1 }
}

%%% \tzLFn
%% \tzLFn :  variable = \x (default)
%% \tzLFn':  variable = \y

\NewDocumentCommand \tzLFn { t' o D<>{0,0} d"" }
{
  \tl_clear:N \l_tzLFn_cmd_tl

  \IfBooleanTF { #1 }
  { \bool_set_true:N \l_tmpa_bool }
  { \bool_set_false:N \l_tmpa_bool }
  
  \IfValueTF { #3 }
  { 
    \tl_set:Nn \l_tzLFn_shift_tl 
    { shift = { (#3) } }
  }
  { \tl_clear:N \l_tzLFn_shift_tl }

  \IfValueTF { #2 }
  { \tl_set:Nn \l_tzLFn_opt_tl { #2 } }
  { \tl_clear:N \l_tzLFn_opt_tl }
  
  \IfValueTF { #4 }
  { \tl_set:Nn \l_tzLFn_namepath_tl { name~path = #4 } }
  { \tl_clear:N \l_tzLFn_namepath_tl }
  
  \tzLFn_check_token:n
}

\cs_new:Npn \tzLFn_check_token:n #1
{
  \str_if_eq:nnT { #1 } { ( }
    { \tzLFn_sub_fn ( }
}

\use:x{
  \NewDocumentCommand \exp_not:N \tzLFn_sub_fn
  { r() d() G{1} 
    >{ \SplitArgument {1} { \tl_to_str:n {:} } } r[] + G{} O{} D<>{} 
  }
}
{
  \tzLFn_domain_process #4

  \tl_put_right:Nx \l_tzLFn_cmd_tl
    {
      [ 
        \l_tzLFn_namepath_tl ,
        domain = \tzLFnFromVal \c_colon_str \tzLFnToVal , %%% [here?]
%        samples = 200 , 
        \bool_if:NTF \l_tmpa_bool
        { variable = \exp_not:n { \y } }
        { variable = \exp_not:n { \x } } ,
        \l_tzLFn_shift_tl ,
    }
  \tl_put_right:No \l_tzLFn_cmd_tl
    {
        \l_tzLFn_opt_tl
      ] 
    }
  \bool_if:NT \g_tzLFn_BEGIN_cmd_bool
    { \tl_put_right:No \l_tzLFn_cmd_tl { \g_tzLFn_BEGIN_cmd_tl } }
  
  % define LF
  \tzgetxyval(#1){\tzLFAval}{\tzLFBval}
  \IfNoValueTF { #2 }
  {
    \bool_if:NTF \l_tmpa_bool
    { \def\tzLFnDEF{#3*(\y-\tzLFBval)+\tzLFAval} }
    { \def\tzLFnDEF{#3*(\x-\tzLFAval)+\tzLFBval} }
  }
  {
    \tzgetxyval(#2){\tzLFAAval}{\tzLFBBval}
    \bool_if:NTF \l_tmpa_bool
    {
      \edef\tzLFSlope{(\tzLFAAval-\tzLFAval)/(\tzLFBBval-\tzLFBval)}
      \def\tzLFnDEF{\tzLFSlope*(\y-\tzLFBval)+\tzLFAval}
    }
    {
      \edef\tzLFSlope{(\tzLFBBval-\tzLFBval)/(\tzLFAAval-\tzLFAval)}
      \def\tzLFnDEF{\tzLFSlope*(\x-\tzLFAval)+\tzLFBval}
    }
  }
  
  \bool_if:NTF \l_tmpa_bool
  {
    \tl_put_right:Nn \l_tzLFn_cmd_tl
      { plot ( { \tzLFnDEF } , \y ) }  % \y should not be expanded
  }
  {
    \tl_put_right:Nn \l_tzLFn_cmd_tl
      { plot ( \x , { \tzLFnDEF } ) }  % \x should not be expanded
  }
  \bool_if:NT \g_tzLFn_END_cmd_bool
    { \tl_put_right:No \l_tzLFn_cmd_tl { \g_tzLFn_END_cmd_tl } }
  \tl_put_right:Nn \l_tzLFn_cmd_tl
    { node [ #6 ] { #5 } }
  % final action
  \exp_last_unbraced:Nf \draw \l_tzLFn_cmd_tl #7 ;

  \bool_gset_false:N \g_tzLFn_BEGIN_cmd_bool
  \bool_gset_false:N \g_tzLFn_END_cmd_bool
}

\NewDocumentCommand\tzLFn_domain_process{ m m }
{
  \def\tzLFnFromVal{#1}
  \def\tzLFnToVal{#2}
}

%%% --- end of \tzLFn


%% \tzfn (variable=\x -- default)

\bool_new:N \g_tzfn_BEGIN_cmd_bool
\bool_new:N \g_tzfn_END_cmd_bool

%% \tzfnAtBegin
\NewDocumentCommand\tzfnAtBegin{ m }
{
  \bool_gset_true:N \g_tzfn_BEGIN_cmd_bool
  \tl_gset:No \g_tzfn_BEGIN_cmd_tl { #1 }
}

%% \tzfnAtEnd
\NewDocumentCommand\tzfnAtEnd{ m }
{
  \bool_gset_true:N \g_tzfn_END_cmd_bool
  \tl_gset:No \g_tzfn_END_cmd_tl { #1 }
}

%% \tzfn  (variable=\x)
%% \tzfn' (variable=\y)  -- equivalent to \tzfnofy
\use:x{
  \NewDocumentCommand \exp_not:N \tzfn
  { t' O{} D<>{0,0} D""{} m 
    >{ \SplitArgument {1} { \tl_to_str:n {:} } } r[] +G{} O{} D<>{} 
  }
}
{
  \tl_clear:N \l_tzfn_cmd_tl

  \IfBooleanTF { #1 }
  { \bool_set_true:N \l_tmpa_bool }
  { \bool_set_false:N \l_tmpa_bool }

  \tzfn_domain_process #6

  \tl_set:No \l_tmpa_tl { \tl_to_str:n { #5 } }
  \tl_set:No \l_tzfn_pathname_tl { \tl_tail:N \l_tmpa_tl }
  \tl_put_right:Nx \l_tzfn_cmd_tl
    {
      [
        name~path = 
          \tl_if_empty:nTF { #4 } { \l_tzfn_pathname_tl } { #4 } , 
        domain = \tzfnFromVal \c_colon_str \tzfnToVal ,
        samples = 200 , 
        shift = { (#3) } , 
        \bool_if:NTF \l_tmpa_bool
        { variable = \exp_not:n { \y } }
        { variable = \exp_not:n { \x } } ,
        \exp_not:n { #2 }
      ] 
    }
  \bool_if:NT \g_tzfn_BEGIN_cmd_bool
    { \tl_put_right:No \l_tzfn_cmd_tl { \g_tzfn_BEGIN_cmd_tl } }
  \bool_if:NTF { \l_tmpa_bool }
  {
    \tl_put_right:Nn \l_tzfn_cmd_tl
      { plot ( { #5 } , \y ) }        % \y should not be expanded
  }
  {
    \tl_put_right:Nn \l_tzfn_cmd_tl
      { plot ( \x , { #5 } ) }        % \x should not be expanded
  }
  \bool_if:NT \g_tzfn_END_cmd_bool
    { \tl_put_right:No \l_tzfn_cmd_tl { \g_tzfn_END_cmd_tl } }
  \tl_put_right:Nn \l_tzfn_cmd_tl
    { node [ #8 ] { #7 } }
  % final action
  \exp_last_unbraced:Nf \draw \l_tzfn_cmd_tl #9 ;

  \bool_gset_false:N \g_tzfn_BEGIN_cmd_bool
  \bool_gset_false:N \g_tzfn_END_cmd_bool
}

\NewDocumentCommand\tzfn_domain_process{ m m }
{
  \def\tzfnFromVal{#1}
  \def\tzfnToVal{#2}
}

%%% --- end of \tzfn


%% \tzvfnat
\use:x{
  \NewDocumentCommand \exp_not:N \tzvfnat
  { O{} D<>{0,0} D""{} m 
    >{ \SplitArgument {1} { \tl_to_str:n {:} } } d[] +G{} O{} D<>{} 
  }
}
{
  \tl_clear:N \l_tzvfnat_cmd_tl
  
  \IfValueT { #5 }  { \tzvfnat_domain_process #5 }

  \tl_put_right:Nx \l_tzvfnat_cmd_tl
    {
      [ 
        name~path = #3 ,
        shift = { (#2) } ,
%        samples = 200 , 
        \exp_not:n { #1 }
      ] 
    }
  \IfValueTF { #5 }
  {
    \tl_put_right:Nn \l_tzvfnat_cmd_tl
      { (#4,\tzvfnatFromVal) -- (#4,\tzvfnatToVal) } 
  }
  {
    \tl_put_right:Nn \l_tzvfnat_cmd_tl
      {
           (#4,0 |- current~bounding~box.south)
        -- (#4,0 |- current~bounding~box.north)
      } 
  }
  \tl_put_right:Nn \l_tzvfnat_cmd_tl
    { node [ #7 ] { #6 } }
  % final action
  \exp_last_unbraced:Nf \draw \l_tzvfnat_cmd_tl #8 ;
}

\NewDocumentCommand\tzvfnat_domain_process{ m m }
{
  \def\tzvfnatFromVal{#1}
  \def\tzvfnatToVal{#2}
}

%%% --- end of \tzvfnat


%%% \tzvfn (On) -- vertical line through (x,y)


%%% \tzvfn
\use:x{
  \NewDocumentCommand \exp_not:N \tzvfn
  { O{} d<> D""{} r() 
    >{ \SplitArgument {1} { \tl_to_str:n {:} } } d[] +G{} O{} D<>{} 
  }
}
{
  \tl_clear:N \l_tzvfn_cmd_tl

  \IfValueT { #5 }  { \tzvfn_domain_process #5 }

  \tl_put_right:Nx \l_tzvfn_cmd_tl
    {
      [ 
        name~path = #3 ,
        \exp_not:n { #1 }
      ] 
    }
  \IfValueTF { #5 }
  {
    \IfValueTF { #2 }
    {
      \tl_put_right:Nn \l_tzvfn_cmd_tl
      {
        ([shift = { (#2) }]#4 |- 0,\tzvfnFromVal) -- 
        ([shift = { (#2) }]#4 |- 0,\tzvfnToVal) } 
    }
    {
      \tl_put_right:Nn \l_tzvfn_cmd_tl
      { (#4 |- 0,\tzvfnFromVal) -- (#4 |- 0,\tzvfnToVal) } 
    }
  }
  {
    \IfValueTF { #2 }
    {
      \tl_put_right:Nn \l_tzvfn_cmd_tl
      {
        ([shift = { (#2) }]#4 |- current~bounding~box.south) --
        ([shift = { (#2) }]#4 |- current~bounding~box.north)
      } 
    }
    {
      \tl_put_right:Nn \l_tzvfn_cmd_tl
      {
        (#4 |- current~bounding~box.south) --
        (#4 |- current~bounding~box.north)
      } 
    }
  }
  \tl_put_right:Nn \l_tzvfn_cmd_tl
    { node [ #7 ] { #6 } }
  % final action
  \exp_last_unbraced:Nf \draw \l_tzvfn_cmd_tl #8 ;
}

\NewDocumentCommand\tzvfn_domain_process{ m m }
{
  \def\tzvfnFromVal{#1}
  \def\tzvfnToVal{#2}
}

%%% --- end of \tzvfn


%% \tzhfnat
\use:x{
  \NewDocumentCommand \exp_not:N \tzhfnat
  { O{} D<>{0,0} D""{} m 
    >{ \SplitArgument {1} { \tl_to_str:n {:} } } d[] +G{} O{} D<>{} 
  }
}
{
  \tl_clear:N \l_tzhfnat_cmd_tl
  
  \IfValueT { #5 }  { \tzhfnat_domain_process #5 }

  \tl_put_right:Nx \l_tzhfnat_cmd_tl
    {
      [ 
        name~path = #3 ,
        shift = { (#2) } ,
        variable = \exp_not:n { \x } ,
        \exp_not:n { #1 }
      ] 
    }
  \IfValueTF { #5 }
  {
    \tl_put_right:Nn \l_tzhfnat_cmd_tl
      { (\tzhfnatFromVal,#4) -- (\tzhfnatToVal,#4) } 
  }
  {
    \tl_put_right:Nn \l_tzhfnat_cmd_tl
      {
           (0,#4 -| current~bounding~box.west)
        -- (0,#4 -| current~bounding~box.east)
      } 
  }
  \tl_put_right:Nn \l_tzhfnat_cmd_tl
    { node [ #7 ] { #6 } }
  % final action
  \exp_last_unbraced:Nf \draw \l_tzhfnat_cmd_tl #8 ;
}

\NewDocumentCommand\tzhfnat_domain_process{ m m }
{
  \def\tzhfnatFromVal{#1}
  \def\tzhfnatToVal{#2}
}

%%% --- end of \tzhfnat


%%% \tzhfn (On)  -- horizontal line through (x,y)

%% \tzhfn
\use:x{
  \NewDocumentCommand \exp_not:N \tzhfn
  { O{} d<> D""{} r() 
    >{ \SplitArgument {1} { \tl_to_str:n {:} } } d[] +G{} O{} D<>{} 
  }
}
{
  \tl_clear:N \l_tzhfn_cmd_tl
  
  \IfValueT { #5 }  { \tzhfn_domain_process #5 }

  \tl_put_right:Nx \l_tzhfn_cmd_tl
    {
      [ 
        name~path = #3 ,
        variable = \exp_not:n { \x } ,
        \exp_not:n { #1 }
      ] 
    }
  \IfValueTF { #5 }
  {
    \IfValueTF { #2 }
    {
      \tl_put_right:Nn \l_tzhfn_cmd_tl
      {
        ([shift = { (#2) }]\tzhfnFromVal,0 |- #4) -- 
        ([shift = { (#2) }]\tzhfnToVal,0 |- #4) 
      }
    } 
    {
      \tl_put_right:Nn \l_tzhfn_cmd_tl
      {
        (\tzhfnFromVal,0 |- #4) -- 
        (\tzhfnToVal,0 |- #4) 
      }
    } 
  }
  {
    \IfValueTF { #2 }
    {
      \tl_put_right:Nn \l_tzhfn_cmd_tl
      {
           ([shift = { (#2) }]#4 -| current~bounding~box.west)
        -- ([shift = { (#2) }]#4 -| current~bounding~box.east)
      } 
    }
    {
      \tl_put_right:Nn \l_tzhfn_cmd_tl
      {
           (#4 -| current~bounding~box.west)
        -- (#4 -| current~bounding~box.east)
      } 
    }
  }
  \tl_put_right:Nn \l_tzhfn_cmd_tl
    { node [ #7 ] { #6 } }
  % final action
  \exp_last_unbraced:Nf \draw \l_tzhfn_cmd_tl #8 ;
}

\NewDocumentCommand\tzhfn_domain_process{ m m }
{
  \def\tzhfnFromVal{#1}
  \def\tzhfnToVal{#2}
}

%%% --- end of \tzhfn


%%%%% Intersections

%%% \tzXpoint -- intersection point of two paths
\NewDocumentCommand\tzXpoint
  { s O{} m m D(){intersection} O{1} +G{} O{} D(){\tz@initial@dot@size} }
{
  \tl_clear:N \l_tzXpoint_cmd_tl
  \path [ name~intersections = { of = #3 ~ and ~ #4 , name = #5 } ] ;
  \tl_put_right:Nn \l_tzXpoint_cmd_tl
  {
    (#5-#6) coordinate (#5)
    \IfBooleanTF {#1}
    { node [ tzdot , fill ,        minimum~size = #9  , }
    { node [ tzdot , draw = none , minimum~size = 0pt , }
  }

  \tl_put_right:Nx \l_tzXpoint_cmd_tl
  {
             label = { \exp_not:n { #8 } \c_colon_str \exp_not:n { #7 } } , 
  }

  \tl_put_right:Nn \l_tzXpoint_cmd_tl
  {
             #2
           ] {}
  }
  
  \exp_last_unbraced:Nf \path \l_tzXpoint_cmd_tl ;
}

%%% --- end of \tzXpoint


%%% \tzvXpointat  -- vertical intersection point at x
%%% *[<opt>]{<path>}(<coor>)(<coor name>)[<nth>]{<label>}[<[<opt>]angle>](<dotsize>)
\NewDocumentCommand\tzvXpointat
  { s O{} m m D(){intersection} O{1} +G{} O{} D(){\tz@initial@dot@size} }
{
  \tl_clear:N \l_tzvXpointat_cmd_tl
  
  \tzvfnat[draw=none]"tzvXpoint-At" {#4} % depends on (current bounding box)

  \path [ name~intersections = { of = tzvXpoint-At ~and~ #3 , name = #5 } ] ;
  
  \tl_put_right:Nn \l_tzvXpointat_cmd_tl
  {
    (#5-#6) coordinate (#5)
    \IfBooleanTF {#1}
    { node [ tzdot , fill ,        minimum~size = #9  , }
    { node [ tzdot , draw = none , minimum~size = 0pt , }
  }

  \tl_put_right:Nx \l_tzvXpointat_cmd_tl
  {
             label = { \exp_not:n { #8 } \c_colon_str \exp_not:n { #7 } } , 
  }

  \tl_put_right:Nn \l_tzvXpointat_cmd_tl
  {
             #2
           ] {}
  }
  
  \exp_last_unbraced:Nf \path \l_tzvXpointat_cmd_tl ;
  \tl_clear:N \tzvXpointat_cmd_tl
}

%%% --- end of \tzvXpointat


%%% \tzvXpoint (On)  
%%% -- vertical intersection point at (x,y) of a path
%%% *[<opt>]{<path>}(<coor>)(<coor name>)[<nth>]{<label>}[<[<opt>]angle>](<dotsize>)
\NewDocumentCommand\tzvXpoint
  { s O{} m r() D(){intersection} O{1} +G{} O{} D(){\tz@initial@dot@size} }
{
  \tl_clear:N \l_tzvXpoint_cmd_tl
  
  \tzvfn[draw=none]"tzvXpoint-On"(#4) % depends on (current bounding box)

  \path [ name~intersections = { of = tzvXpoint-On ~and~ #3 , name = #5 } ] ;
  \tl_put_right:Nn \l_tzvXpoint_cmd_tl
  {
    (#5-#6) coordinate (#5)
    \IfBooleanTF {#1}
    { node [ tzdot , fill ,        minimum~size = #9  , }
    { node [ tzdot , draw = none , minimum~size = 0pt , }
  }

  \tl_put_right:Nx \l_tzvXpoint_cmd_tl
  {
             label = { \exp_not:n { #8 } \c_colon_str \exp_not:n { #7 } } , 
  }

  \tl_put_right:Nn \l_tzvXpoint_cmd_tl
  {
             #2
           ] {}
  }
  
  \exp_last_unbraced:Nf \path \l_tzvXpoint_cmd_tl ;
  \tl_clear:N \l_tzvXpoint_cmd_tl
}

%%% --- end of \tzvXpoint



%%% \tzhXpointat  -- horizontal intersection point at y
\NewDocumentCommand\tzhXpointat
  { s O{} m m D(){intersection} O{1} +G{} O{} D(){\tz@initial@dot@size} }
{
  \tl_clear:N \l_tzhXpointat_cmd_tl
  
  \tzhfnat[draw=none]"tzhXpoint-At"{#4} % depends on (current bounding box)

  \path [ name~intersections = { of = tzhXpoint-At ~and~ #3 , name = #5 } ] ;
  \tl_put_right:Nn \l_tzhXpointat_cmd_tl
  {
    (#5-#6) coordinate (#5)
    \IfBooleanTF {#1}
    { node [ tzdot , fill ,        minimum~size = #9  , }
    { node [ tzdot , draw = none , minimum~size = 0pt , }
  }

  \tl_put_right:Nx \l_tzhXpointat_cmd_tl
  {
             label = { \exp_not:n { #8 } \c_colon_str \exp_not:n { #7 } } , 
  }

  \tl_put_right:Nn \l_tzhXpointat_cmd_tl
  {
             #2
           ] {}
  }
  
  \exp_last_unbraced:Nf \path \l_tzhXpointat_cmd_tl ;
  \tl_clear:N \l_tzhXpointat_cmd_tl
}

%%% --- end of \tzhXpointat


%%% \tzhXpoint (On)  -- horizontal intersection point at (x,y)
\NewDocumentCommand\tzhXpoint
  { s O{} m r() D(){intersection} O{1} +G{} O{} D(){\tz@initial@dot@size} }
{
  \tl_clear:N \l_tzhXpoint_cmd_tl
  
  \tzhfn[draw=none]"tzhXpoint-On"(#4) % depends on (current bounding box)

  \path [ name~intersections = { of = tzhXpoint-On ~and~ #3 , name = #5 } ] ;

  \tl_put_right:Nn \l_tzhXpoint_cmd_tl
  {
    (#5-#6) coordinate (#5)
    \IfBooleanTF {#1}
    { node [ tzdot , fill ,        minimum~size = #9  , }
    { node [ tzdot , draw = none , minimum~size = 0pt , }
  }

  \tl_put_right:Nx \l_tzhXpoint_cmd_tl
  {
             label = { \exp_not:n { #8 } \c_colon_str \exp_not:n { #7 } } , 
  }

  \tl_put_right:Nn \l_tzhXpoint_cmd_tl
  {
             #2
           ] {}
  }
  
  \exp_last_unbraced:Nf \path \l_tzhXpoint_cmd_tl ;
  \tl_clear:N \l_tzhXpoint_cmd_tl
}

%%% --- end of \tzhXpoint



%%%%% Axes

%%% \tzaxes

\NewDocumentCommand\tzaxes{ s O{} D<>{0,0} r() d() +G{} O{} +G{} O{} }
{
  \IfNoValueTF { #5 }
  {
    \draw [ -> , #2 ] 
      ( 0,0 |- #3 ) -- ( #4 |- #3 ) node [ right , #7 ] { #6 } ;
    \draw [ -> , #2 ] 
      ( #3 |- 0,0 ) -- ( #3 |- #4 ) node [ above , #9 ] { #8 } ;
  }
  {
    \draw [ -> , #2 ] 
      ( #4 |- #3 )  -- ( #5 |- #3 ) node [ right , #7 ] { #6 } ;
    \draw [ -> , #2 ] 
      ( #3 |- #4 )  -- ( #3 |- #5 ) node [ above , #9 ] { #8 } ;
  }
  \IfBooleanT { #1 }
  {
    \coordinate (bbxOpposite) at (current~bounding~box.north~east) ;
    \coordinate (bbxOrigin) at (current~bounding~box.south~west) ;
    \useasboundingbox (bbxOrigin) rectangle (bbxOpposite) ;
  }
}

%%% \tzaxesL  -- simpler version of \tzaxes

\NewDocumentCommand\tzaxesL{ t' O{} d<> r() r() +G{} O{} +G{} O{} }
{
  \IfBooleanTF { #1 }
  {
    \draw [ #2 ] 
      \IfValueTF { #3 }
      {
        ( [shift={(#3)}]#5 ) -- ( [shift={(#3)}]#4 |- #5 )
      }
      {
        ( #5 ) -- ( #4 |- #5 )
      }
      node [ left , #7  ] { #6 } ;
    \draw [ #2 ] 
      \IfValueTF { #3 }
      {
        ( [shift={(#3)}]#5 ) -- ( [shift={(#3)}]#5 |- #4 )
      }
      {
        ( #5 ) -- ( #5 |- #4 )
      }
      node [ below , #9 ] { #8 } ;
  }
  {
    \draw [ #2 ] 
      \IfValueTF { #3 }
      {
        ( [shift={(#3)}]#4 ) -- ( [shift={(#3)}]#5 |- #4 ) 
      }
      {
        ( #4 ) -- ( #5 |- #4 )       
      }
      node [ right , #7 ] { #6 } ;
    \draw [ #2 ]
      \IfValueTF { #3 }
      {
        ( [shift={(#3)}]#4 ) -- ( [shift={(#3)}]#4 |- #5 ) 
      }
      {
        ( #4 ) -- ( #4 |- #5 ) 
      }
      node [ above , #9 ] { #8 } ;
  }
}

%%% -- end of \tzaxesL

%%% \tzaxisx

\NewDocumentCommand\tzaxisx{ s O{} D<>{0} m m G{} O{} }
{
  \draw [ -> , #2 ] 
    ( #4 , #3 ) -- ( #5 , #3 ) node [ right , #7 ] { #6 } ;
}

%%% \tzaxisy

\NewDocumentCommand\tzaxisy{ s O{} D<>{0} m m G{} O{} }
{
  \draw [ -> , #2 ] 
    ( #3 , #4 ) -- ( #3 , #5 ) node [ above , #7 ] { #6 } ;
}


%%%%% Ticks

%%% \tztikcs : (combine \tzticksx and \tzticksy)

\use:x{
  \NewDocumentCommand \exp_not:N \tzticks
  { s O{} D<>{0,0} 
      >{ \SplitArgument {1} { \tl_to_str:n {:} } } d() m O{}
      >{ \SplitArgument {1} { \tl_to_str:n {:} } } d() G{} O{} 
  }
}
{
  \tzgetxyval(#3){\tzticksXshift}{\tzticksYshift}
  \IfValueT { #4 } { \tzticks_Xlength_process #4 }
  %% ------
  \IfValueT { #7 } { \tzticks_Ylength_process #7 }
  
  \IfBooleanTF { #1 }
  { 
    \IfNoValueT { #4 }
    {
      \def\tzticksXFromVal{0pt}
      \def\tzticksXToVal{3pt}
    }
    \foreach \xx / \tzXtext in { #5 }
      \draw [ shift = {(0,\tzticksYshift)} , #2 ] 
            (\xx , \tzticksXFromVal)
         -- (\xx , \tzticksXToVal)   ; % ignores \txXtext
    %% --------
    \IfNoValueT { #7 } 
    {
      \def\tzticksYFromVal{0pt}
      \def\tzticksYToVal{3pt}
    }
    \foreach \yy/\tzYtext in { #8 }
      \draw [ shift = {(\tzticksXshift,0)} , #2 ] 
            (\tzticksYFromVal , \yy)
         -- (\tzticksYToVal , \yy)   ; % ignores \txXtext
  }
  { 
    \IfNoValueT { #4 }
    {
      \def\tzticksXFromVal{0pt}
      \def\tzticksXToVal{0pt}
    }
    \foreach \xx / \tzXtext in { #5 }
      \draw [ shift = {(0,\tzticksYshift)} , #2 ] 
            (\xx ,\tzticksXFromVal)
         -- (\xx , \tzticksXToVal)   
            (\xx , 0 ) node 
              [ text~height = 1.25ex , 
                text~depth = .25ex , 
                below , #6 ] {\tzXtext} ;
    %% --------
    \IfNoValueT { #7 }
    {
      \def\tzticksYFromVal{0pt}
      \def\tzticksYToVal{0pt}
    }
    \foreach \yy / \tzYtext in { #8 }
      \draw [ shift = {(\tzticksXshift,0)} , #2 ] 
            (\tzticksYFromVal , \yy)
         -- (\tzticksYToVal , \yy)
            (0 , \yy)
            node [ left , #9 ] { \tzYtext } ;
  }
}

\NewDocumentCommand\tzticks_Xlength_process { m m }
{
  \def\tzticksXFromVal{#1}
  \def\tzticksXToVal{#2}
}
%% --------
\NewDocumentCommand\tzticks_Ylength_process { m m }
{
  \def\tzticksYFromVal{#1}
  \def\tzticksYToVal{#2}
}

%%% --- end of \tzticks


%%% \tztikcsx  -- ticks and labels along the x axis

\use:x{
  \NewDocumentCommand \exp_not:N \tzticksx
  { s O{} D<>{0} 
    >{ \SplitArgument {1} { \tl_to_str:n {:} } } d() m O{} 
  }
}
{
  \IfValueT { #4 } { \tzticksx_length_process #4 }
  
  \IfBooleanTF { #1 }
  { 
    \IfNoValueT { #4 }
    {
      \def\tzticksxFromVal{0pt}
      \def\tzticksxToVal{3pt}
    }
    \foreach \xx / \tzxtext in { #5 }
      \draw [ shift = {(0,#3)} , #2 ] 
            (\xx , \tzticksxFromVal)
         -- (\xx , \tzticksxToVal)   ;
  }
  { 
    \IfNoValueT { #4 }
    {
      \def\tzticksxFromVal{0pt}
      \def\tzticksxToVal{0pt}
    }
    \foreach \xx / \tzxtext in { #5 }
      \draw [ shift = {(0,#3)} , #2 ] 
            (\xx ,\tzticksxFromVal)
         -- (\xx , \tzticksxToVal)   
            (\xx , 0 ) node 
              [ text~height = 1.25ex , 
                text~depth = .25ex , 
                below , #6 ] {\tzxtext} ;

  }
}

\NewDocumentCommand\tzticksx_length_process { m m }
{
  \def\tzticksxFromVal{#1}
  \def\tzticksxToVal{#2}
}

%%% --- end of \tzticksx


%%% \tztikcsy -- ticks and labels along with the y axis

\use:x{
  \NewDocumentCommand \exp_not:N \tzticksy
  { s O{} D<>{0} 
    >{ \SplitArgument {1} { \tl_to_str:n {:} } } d() m O{} 
  }
}
{
  
  \IfValueT { #4 } { \tzticksy_length_process #4 }
  
  \IfBooleanTF { #1 }
  { 
    \IfNoValueT { #4 }
    {
      \def\tzticksyFromVal{0pt}
      \def\tzticksyToVal{3pt}
    }
    \foreach \yy/\tzytext in { #5 }
      \draw [ shift = {(#3,0)} , #2 ] 
            (\tzticksyFromVal , \yy)
         -- (\tzticksyToVal , \yy)   ;
  }
  { 
    \IfNoValueT { #4 }
    {
      \def\tzticksyFromVal{0pt}
      \def\tzticksyToVal{0pt}
    }
    \foreach \yy / \tzytext in { #5 }
      \draw [ shift = {(#3,0)} , #2 ] 
            (\tzticksyFromVal , \yy)            
         -- (\tzticksyToVal , \yy)
            (0 , \yy)
            node [ left , #6 ] { \tzytext } ;
  }
}

\NewDocumentCommand\tzticksy_length_process { m m }
{
  \def\tzticksyFromVal{#1}
  \def\tzticksyToVal{#2}
}

%%% --- end of \tzticksy


%%%%% Projections
%% lines and tick labels of projection onto x/y axis

%%% \tzproj

\NewDocumentCommand\tzproj
  { s O{} d<> r() G{} O{} G{} O{} D(){\tz@initial@dot@size} }
{
  \IfValueTF { #3 }
  { \coordinate (tzProj) at (#3)  ; }
  { \coordinate (tzProj) at (0,0) ; }
  \draw [ dotted , #2 ] 
        (#4 |- tzProj) 
        node [ text~height = 1.25ex , 
                text~depth = .25ex ,
                below , #6 ] { #5 } 
     -- (#4) -- (tzProj |- #4) 
        node [ left , #8 ] {#7} ;
  \IfBooleanT {#1} { \tzdot*(#4)(#9) }
}

%%% \tzprojx

\NewDocumentCommand\tzprojx
  { s O{} d<> r() G{} O{} D(){\tz@initial@dot@size} }
{
  \IfValueTF { #3 }
  { \coordinate (tzProjx) at (#3)  ; }
  { \coordinate (tzProjx) at (0,0) ; }
  \draw [ dotted , #2 ] (#4)
     -- (#4 |- tzProjx) 
        node [ text~height = 1.25ex , 
               text~depth = .25ex , 
               below , #6 ] { #5 } ;
  \IfBooleanT { #1 } { \tzdot*(#4)(#7) }
}

%%% \tzprojy

\NewDocumentCommand\tzprojy
  { s O{} d<> r() G{} O{} D(){\tz@initial@dot@size} }
{
  \IfValueTF { #3 }
  { \coordinate (tzProjy) at (#3)  ; }
  { \coordinate (tzProjy) at (0,0) ; }
  \draw [ dotted , #2 ] (#4) 
     -- (#4 -| tzProjy) 
        node [ left , #6 ] { #5 } ;
  \IfBooleanT { #1 } { \tzdot*(#4)(#7) }
}


%%%%% Nodes

%%% \tznode -- putting texts (and labels as option)

\NewDocumentCommand\tznode{ s O{} d<> r() D(){tzNodeName} +G{} O{} }
{
  \IfBooleanTF { #1 }
  {
    \IfValueTF { #3 }
    { \node [ draw , #2 ] (#5) at ([shift={(#3)}]#4) [ #7 ] { #6 } ; }
    { \node [ draw , #2 ] (#5) at (#4) [ #7 ] { #6 } ; }
  }
  {
    \IfValueTF { #3 }
    { \node [        #2 ] (#5) at ([shift={(#3)}]#4) [ #7 ] { #6 } ; }
    { \node [        #2 ] (#5) at (#4) [ #7 ] { #6 } ; }
  }
}


%%% \tznodedot
\NewDocumentCommand\tznodedot
  { s O{} d<> r() D(){tzNodeName} +G{} O{} D(){\tz@initial@dot@size} }
{
  \tl_clear:N \l_tznodedot_cmd_tl

  \renewcommand\tzdotsize{ #8 }

  \IfValueTF { #3 }
  {% if shift
    \tl_put_right:Nn \l_tznodedot_cmd_tl
      { ([shift={(#3)}]#4) node (#5) }
  }
  {% no shift (normal)
    \tl_put_right:Nn \l_tznodedot_cmd_tl
      { (#4) node (#5) }
  }
  \IfBooleanTF { #1 }
  {
    \tl_put_right:Nn \l_tznodedot_cmd_tl { [ tzdot , fill , }
  }
  {
    \tl_put_right:Nn \l_tznodedot_cmd_tl { [ tzdot , }
  }
  \tl_put_right:Nx \l_tznodedot_cmd_tl
    {
      label = { \exp_not:n { #7 } \c_colon_str \exp_not:n { #6 } } ,
    }
  \tl_put_right:Nn \l_tznodedot_cmd_tl
    {
      minimum~size = \tzdotsize , #2 ] {}
    }
  \exp_last_unbraced:Nf \path \l_tznodedot_cmd_tl ;
}

%%% --- end of \tznodedot



%%% \tznodeframe

\NewDocumentCommand\tznodeframe
  { s O{} d<> r() D(){tzNodeName} +G{} O{} G{\tz@initial@fill@opacity} }
{
  \renewcommand\tzfillopacity{#8}
  \IfBooleanTF { #1 }
  {
    \node [
            draw , rectangle , 
            fill ,
            fill~opacity = \tzfillopacity , text~opacity = 1 , 
            #2 
          ] 
      (#5) at \IfValueTF { #3 } { ([shift={(#3)}]#4) } { (#4) } 
      [ draw = black , text = black , #7 ] { #6 } ;
  }
  {
    \node [ draw , rectangle , #2 ] 
      (#5) at \IfValueTF { #3 } { ([shift={(#3)}]#4) } { (#4) } 
      [ text = black , #7 ] { #6 } ;
  }
}


%%% \tznodebox  \tznoderectangle
\let\tznodebox\tznodeframe
\let\tznoderectangle\tznodeframe


%%% \tznodecircle

\NewDocumentCommand\tznodecircle
  { s O{} d<> r() D(){tzNodeName} +G{} O{} G{\tz@initial@fill@opacity} }
{
  \renewcommand\tzfillopacity{#8}
  \IfBooleanTF { #1 }
  {
    \node [
            draw , circle , 
            fill ,
            fill~opacity = \tzfillopacity , text~opacity = 1 , 
            #2 
          ] 
      (#5) at \IfValueTF { #3 } { ([shift={(#3)}]#4) } { (#4) } 
      [ draw = black , text = black , #7 ] { #6 } ;
  }
  {
    \node [ draw , circle , #2 ] 
      (#5) at \IfValueTF { #3 } { ([shift={(#3)}]#4) } { (#4) } 
      [ text = black , #7 ] { #6 } ;
  }
}

%%% \tznodeellipse

\NewDocumentCommand\tznodeellipse
  { s O{} d<> r() D(){tzNodeName} +G{} O{} G{\tz@initial@fill@opacity} }
{
  \renewcommand\tzfillopacity{#8}
  \IfBooleanTF { #1 }
  {
    \node [
            draw , ellipse , 
            fill ,
            fill~opacity = \tzfillopacity , text~opacity = 1 , 
            #2 
          ] 
      (#5) at \IfValueTF { #3 } { ([shift={(#3)}]#4) } { (#4) } 
      [ draw = black , text = black , #7 ] { #6 } ;
  }
  {
    \node [ draw , ellipse , #2 ] 
      (#5) at \IfValueTF { #3 } { ([shift={(#3)}]#4) } { (#4) } 
      [ text = black , #7 ] { #6 } ;
  }
}

%%% \tznodeoval
\let\tznodeoval\tznodeellipse



%%%%% Secant lines

%% secant line

%%% \tzsecantat

\use:x{
  \NewDocumentCommand \exp_not:N \tzsecantat
  { s O{} d<> D""{} m m m 
    >{ \SplitArgument { 1 } { \tl_to_str:n {:} } } o
  }
}
{
  \tl_clear:N \l_tzsecantat_cmd_tl

  \IfBooleanTF { #1 }  % NOT USED!
  { \bool_set_true:N \l_tmpa_bool }
  { \bool_set_false:N \l_tmpa_bool }

  % define two points
  \tzvXpointat{#5}{#6}(LX-point) % vertical X point
  \tzvXpointat{#5}{#7}(RX-point) % vertical X point
  
  % collect cmd_tl

  \IfNoValueTF { #8 }
  {
    \IfValueTF { #3 }
    {% if shift
      \tl_put_right:Nn \l_tzsecantat_cmd_tl
      {
        [ name~path = #4 , #2 ]
        ([ shift = { (#3) } ]LX-point) -- ([ shift = { (#3) } ]RX-point) 
      }
    }
    {% no shift (normal)
      \tl_put_right:Nn \l_tzsecantat_cmd_tl
      { 
        [ name~path = #4 , #2 ]
        (LX-point) -- (RX-point)
      }
    }
  }
  {
    \tzsecantat_domain_process #8
    \tzgetxyval(LX-point){\tzTANLLX}{\tzTANLLY}
    \tzgetxyval(RX-point){\tzTANRRX}{\tzTANRRY}
  
    \edef\tzTANSlope{(\tzTANRRY-\tzTANLLY)/(\tzTANRRX-\tzTANLLX)}
    \def\tzsecantatLFn{\tzTANSlope*(\x-\tzTANLLX)+\tzTANLLY}
    
    \IfValueTF { #3 }
    {% shift
      \tl_put_right:Nn \l_tzsecantat_cmd_tl
      {
        [ name~path = #4 , 
          shift = { (#3) } ,
      }
    }
    {% no shift (normal)
      \tl_put_right:Nn \l_tzsecantat_cmd_tl
      {
        [ name~path = #4 , 
      }    
    }
    
    \tl_put_right:Nx \l_tzsecantat_cmd_tl
    {
          domain = \tzsecantatFromVal \c_colon_str \tzsecantatToVal ,
    }
    \tl_put_right:Nn \l_tzsecantat_cmd_tl
    {
          #2 ]
      plot ( \x , { \tzsecantatLFn } ) % \x should not be expanded
    }
  }

  \tzsecantat_sub_fn:n
}

\NewDocumentCommand\tzsecantat_domain_process{ m m }
{
  \def\tzsecantatFromVal{#1}
  \def\tzsecantatToVal{#2}
}

\cs_new:Npn \tzsecantat_sub_fn:n 
{
  \tzsecantat_final_actions
}

\NewDocumentCommand\tzsecantat_final_actions { +G{} O{} D<>{} }
{
  \begin{pgfonlayer}{\tzsecantlayer}
  \exp_last_unbraced:Nf \draw \l_tzsecantat_cmd_tl node [ #2 ] { #1 } #3 ;
  \end{pgfonlayer}
  % to resolve TikZ issue: unknown path name with layer group
  \exp_last_unbraced:Nf \path \l_tzsecantat_cmd_tl ;
}

%%% --- end of \tzsecantat


%%% \tzsecant

\use:x{
  \NewDocumentCommand \exp_not:N \tzsecant
  { s O{} d<> d"" m r() r() 
    >{ \SplitArgument { 1 } { \tl_to_str:n {:} } } o
  }
}
{
  \tl_clear:N \l_tzsecant_cmd_tl

  \IfBooleanTF { #1 }  % NOT USED!
  { \bool_set_true:N \l_tmpa_bool }
  { \bool_set_false:N \l_tmpa_bool }

  % define two points
  \tzvXpoint{#5}(#6)(LX-point) % vertical X point
  \tzvXpoint{#5}(#7)(RX-point) % vertical X point
  
  % collect cmd_tl    
  \IfNoValueTF { #8 }
  {
    \IfValueTF { #3 }
    {% if shift
      \tl_put_right:Nn \l_tzsecant_cmd_tl
      {
        [ name~path = #4 , #2 ]
        ([ shift = { (#3) } ]LX-point) -- ([ shift = { (#3) } ]RX-point) 
      }
    }
    {% no shift (normal)
      \tl_put_right:Nn \l_tzsecant_cmd_tl
      { 
        [ name~path = #4 , #2 ]
        (LX-point) -- (RX-point)
      }
    }
  }
  {
    \tzsecant_domain_process #8
    \tzgetxyval(LX-point){\tzTANLLX}{\tzTANLLY}
    \tzgetxyval(RX-point){\tzTANRRX}{\tzTANRRY}
  
    \edef\tzTANSlope{(\tzTANRRY-\tzTANLLY)/(\tzTANRRX-\tzTANLLX)}
    \def\tzsecantLFn{\tzTANSlope*(\x-\tzTANLLX)+\tzTANLLY}
    
    \IfValueTF { #3 }
    {% shift
      \tl_put_right:Nn \l_tzsecant_cmd_tl
      {
        [ name~path = #4 , 
          shift = { (#3) } ,
      }
    }
    {% no shift (normal)
      \tl_put_right:Nn \l_tzsecant_cmd_tl
      {
        [ name~path = #4 , 
      }    
    }
    
    \tl_put_right:Nx \l_tzsecant_cmd_tl
    {
          domain = \tzsecantFromVal \c_colon_str \tzsecantToVal ,
    }
    \tl_put_right:Nn \l_tzsecant_cmd_tl
    {
          #2 ]
      plot ( \x , { \tzsecantLFn } ) % \x should not be expanded
    }
  }

  \tzsecant_sub_fn:n
}

\NewDocumentCommand\tzsecant_domain_process{ m m }
{
  \def\tzsecantFromVal{#1}
  \def\tzsecantToVal{#2}
}

\cs_new:Npn \tzsecant_sub_fn:n 
{
  \tzsecant_final_actions
}

\NewDocumentCommand\tzsecant_final_actions { +G{} O{} D<>{} }
{
  \begin{pgfonlayer}{\tzsecantlayer}
  \exp_last_unbraced:Nf \draw \l_tzsecant_cmd_tl node [ #2 ] { #1 } #3 ;
  \end{pgfonlayer}
  % to resolve TikZ issue: unknown path name with layer group
  \exp_last_unbraced:Nf \path \l_tzsecant_cmd_tl ;
}

%%% --- end of \tzsecant


%%%%% Slope and Tangent

%%% to **resolve** the discrepancy issue due to bounding box
%%% for \tzslope(at) and \tztangent(at)
%%% (ndh)

\NewDocumentCommand \IfNodeDefined { m m m }
{
  \@ifundefined{pgf@sh@ns@#1}
  {#3}
  {#2}
}

\AddToHook{env/tikzpicture/before}{%
  \@ifundefined{pgf@sh@ns@bbxBottom}
  {}
  { \cs_undefine:N \pgf@sh@ns@bbxBottom }
  \def\TANCurve{} \def\TANWhere{}
}
%\AddToHook{env/tikzpicture/before}{%
%  \@ifundefined{pgf@sh@ns@bbxBottom}
%  {}
%  { \cs_undefine:N \pgf@sh@ns@bbxBottom }
%}

%%% Do not forget to declare, before final action,
%%% \gdef\TANCurve{<#m>}\gdef\TANWhere{<#n>}


%%%%% Tangent lines

%%% ref. \settztangentepsilon

\bool_new:N \l_tztangentat_bbox_bool

%%% \tztangentat -- tangent to a path at x
%%% [<opt>]<shift coor>"<path name>"{<path>}{<x>}(<epsilon1>,<epsilon2>)[<from>:<to>]{<text>}[<pos,opt>]<code.append>

\use:x{
  \NewDocumentCommand \exp_not:N \tztangentat
  { s O{} d<> D""{} m m
    >{ \SplitArgument { 1 } { , } } d()
    >{ \SplitArgument { 1 } { \tl_to_str:n {:} } } r[] }
  }
{
  \tl_clear:N \l_tztangentat_cmd_tl

  \IfBooleanTF { #1 } % NOT USED!
  { \bool_set_true:N \l_tmpa_bool }
  { \bool_set_false:N \l_tmpa_bool }
  
  % to resolve discrepancy (due to bounding box), when repeated
  \bool_if:nTF 
  {
    \str_if_eq_p:ee { \TANCurve } { #5 } &&
  	\str_if_eq_p:ee { \TANWhere } { #6 } 
	}
	{ \bool_set_true:N \l_tztangentat_bbox_bool }
	{ \bool_set_false:N \l_tztangentat_bbox_bool }
	
  % for local change of epsilon_1 and _2
  \IfValueT { #7 }
  {
    \tztangentat_epsilon_process #7
    \renewcommand\tztangentepsilonL{\tztangentatEpsilonOne}
    \renewcommand\tztangentepsilonR{\tztangentatEpsilonTwo}
  }

  \tztangentat_domain_process #8

  % getting ready
  \coordinate (LXcoor)   at ($(#6,0)-(\tztangentepsilonL,0)$) ;
  \coordinate (RXcoor)   at ($(#6,0)+(\tztangentepsilonR,0)$) ;
  
  \bool_if:NTF \l_tztangentat_bbox_bool
  {
    \IfNodeDefined{bbxBottom}{}
    {
      \coordinate (bbxTop)    at (current~bounding~box.north) ;
      \coordinate (bbxBottom) at (current~bounding~box.south) ;
    }
  }
  {
    \coordinate (bbxTop)    at (current~bounding~box.north) ;
    \coordinate (bbxBottom) at (current~bounding~box.south) ;
  }

  % find vertical X points
  \path [ name~path = C-vline ] (#6,0 |- bbxBottom) -- (#6,0 |- bbxTop) ;
  \path [ name~intersections = { of = #5 ~ and ~ C-vline , name = TANp } ] ;

  \path [ name~path = L-vline ] (LXcoor |- bbxBottom) -- (LXcoor |- bbxTop) ;
  \path [ name~intersections = { of = #5 ~ and ~ L-vline , name = LXcut } ] ;

  \path [ name~path = R-vline ] (RXcoor |- bbxBottom) -- (RXcoor |- bbxTop) ;
  \path [ name~intersections = { of = #5 ~ and ~ R-vline , name = RXcut } ] ;

  % move to tangent point
  \coordinate (tzXproj)
    at ($(LXcut-1)!(TANp-1)!(RXcut-1)$); % projection
  \coordinate (LLpoint)
    at ($(LXcut-1)+(TANp-1)-(tzXproj)$); % move
  \coordinate (RRpoint)
    at ($(RXcut-1)+(TANp-1)-(tzXproj)$); % move

  % determine final extended points
  \tl_set:Nx \l_tmpa_tl
  { 
    (RRpoint) -- (TANp-1) -- 
    ([turn]0 \c_colon_str ~ -\tztangentatFromVal) coordinate (final-LL) 
  }
  \tl_set:Nx \l_tmpb_tl
  { 
    (LLpoint) -- (TANp-1) -- 
    ([turn]0 \c_colon_str ~ \tztangentatToVal) coordinate (final-RR) 
  }

  \exp_last_unbraced:Nf \path \l_tmpa_tl ;
  \exp_last_unbraced:Nf \path \l_tmpb_tl ;

  \tzgetxyval(LLpoint){\tzTANLLX}{\tzTANLLY}
  \tzgetxyval(RRpoint){\tzTANRRX}{\tzTANRRY}

  \edef\tzTANSlope{(\tzTANRRY-\tzTANLLY)/(\tzTANRRX-\tzTANLLX)}
  \def\tztangentatLFn{\tzTANSlope*(\x-\tzTANLLX)+\tzTANLLY}

  \IfValueTF { #3 }
  {
    \tl_put_right:Nn \l_tztangentat_cmd_tl
    { 
      [ name~path = #4 , 
        shift = { (#3) } , 
    }
  }
  {
    \tl_put_right:Nn \l_tztangentat_cmd_tl
    { 
      [ name~path = #4 , 
    }
  }
  
  \tl_put_right:Nx \l_tztangentat_cmd_tl
    { 
        domain = \tztangentatFromVal \c_colon_str \tztangentatToVal ,
    }

  \tl_put_right:Nn \l_tztangentat_cmd_tl
    { 
        #2 ] 
      plot ( \x , { \tztangentatLFn } ) % \x should not be expanded
    }
  
  \gdef\TANCurve{#5}\gdef\TANWhere{#6}

  \tztangentat_sub_fn:n
}

\NewDocumentCommand\tztangentat_epsilon_process{ m m }
{
  \def\tztangentatEpsilonOne{#1}
  \def\tztangentatEpsilonTwo{#2}
}

\NewDocumentCommand\tztangentat_domain_process{ m m }
{
  \def\tztangentatFromVal{#1}
  \def\tztangentatToVal{#2}
}

\cs_new:Npn \tztangentat_sub_fn:n
{
  \tztangentat_final_actions
}

\NewDocumentCommand\tztangentat_final_actions { +G{} O{} D<>{} }
{
  \begin{pgfonlayer}{\tztangentlayer}
  \exp_last_unbraced:Nf \draw \l_tztangentat_cmd_tl 
    node [ black , above~right , #2 ] { #1 } #3 ;
  \end{pgfonlayer}
  % to resolve TikZ issue: unknown path name with layer group
  \exp_last_unbraced:Nf \path \l_tztangentat_cmd_tl ;
}

%%% --- end of \tztangentat


\bool_new:N \l_tztangent_bbox_bool

%%% \tztangent (On) -- tangent to a path at (x,y)
%%% [<opt>]<shift coor>"<path name>"{<path>}(<coor>)(<epsilon1>,<epsilon2>)[<from>:<to>]{<text>}[<pos,opt>]<code.append>

\use:x{
  \NewDocumentCommand \exp_not:N \tztangent
  { s O{} d<> D""{} m r()
    >{ \SplitArgument { 1 } { , } } d()
    >{ \SplitArgument { 1 } { \tl_to_str:n {:} } } r[] }
  }
{
  \tl_clear:N \l_tztangent_cmd_tl

  \IfBooleanTF { #1 } % NOT USED!
  { \bool_set_true:N \l_tmpa_bool }
  { \bool_set_false:N \l_tmpa_bool }
  
  % to resolve discrepancy (due to bounding box), when repeated
  \bool_if:nTF 
  {
    \str_if_eq_p:ee { \TANCurve } { #5 } &&
  	\str_if_eq_p:ee { \TANWhere } { #6 } 
	}
	{ \bool_set_true:N \l_tztangent_bbox_bool }
	{ \bool_set_false:N \l_tztangent_bbox_bool }

  % for local change of epsilon_1 and _2
  \IfValueT { #7 }
  {
    \tztangent_epsilon_process #7
    \renewcommand\tztangentepsilonL{\tztangentEpsilonOne}
    \renewcommand\tztangentepsilonR{\tztangentEpsilonTwo}
  }

  \tztangent_domain_process #8

  % getting ready
  \coordinate (LXcoor)   at ($(#6)-(\tztangentepsilonL,0)$) ;
  \coordinate (RXcoor)   at ($(#6)+(\tztangentepsilonR,0)$) ;

  \bool_if:NTF \l_tztangent_bbox_bool
  {
    \IfNodeDefined{bbxBottom}{}
    {
      \coordinate (bbxTop)    at (current~bounding~box.north) ;
      \coordinate (bbxBottom) at (current~bounding~box.south) ;
    }
  }
  {
    \coordinate (bbxTop)    at (current~bounding~box.north) ;
    \coordinate (bbxBottom) at (current~bounding~box.south) ;
  }
    
  % find vertical X points
  \path [ name~path = C-vline ] (#6 |- bbxBottom) -- (#6 |- bbxTop) ;
  \path [ name~intersections = { of = #5 ~ and ~ C-vline , name = TANp } ] ;

  \path [ name~path = L-vline ] (LXcoor |- bbxBottom) -- (LXcoor |- bbxTop) ;
  \path [ name~intersections = { of = #5 ~ and ~ L-vline , name = LXcut } ] ;

  \path [ name~path = R-vline ] (RXcoor |- bbxBottom) -- (RXcoor |- bbxTop) ;
  \path [ name~intersections = { of = #5 ~ and ~ R-vline , name = RXcut } ] ;

  % move to tangent point
  \coordinate (tzXproj)
    at ($(LXcut-1)!(TANp-1)!(RXcut-1)$); % projection
  \coordinate (LLpoint)
    at ($(LXcut-1)+(TANp-1)-(tzXproj)$); % move
  \coordinate (RRpoint)
    at ($(RXcut-1)+(TANp-1)-(tzXproj)$); % move

  % determine final extended points
  \tl_set:Nx \l_tmpa_tl
  { (RRpoint) -- (TANp-1) -- 
    ([turn]0 \c_colon_str ~ -\tztangentFromVal) coordinate (final-LL) }
  \tl_set:Nx \l_tmpb_tl
  { (LLpoint) -- (TANp-1) -- 
    ([turn]0 \c_colon_str ~ \tztangentToVal) coordinate (final-RR) }

  \exp_last_unbraced:Nf \path \l_tmpa_tl ;
  \exp_last_unbraced:Nf \path \l_tmpb_tl ;

  \tzgetxyval(LLpoint){\tzTANLLX}{\tzTANLLY}
  \tzgetxyval(RRpoint){\tzTANRRX}{\tzTANRRY}

  \edef\tzTANSlope{(\tzTANRRY-\tzTANLLY)/(\tzTANRRX-\tzTANLLX)}
  \def\tztangentLFn{\tzTANSlope*(\x-\tzTANLLX)+\tzTANLLY}

  \IfValueTF { #3 }
  {
    \tl_put_right:Nn \l_tztangent_cmd_tl
    { 
      [ name~path = #4 , 
        shift = { (#3) } , 
    }
  }
  {
    \tl_put_right:Nn \l_tztangent_cmd_tl
    { 
      [ name~path = #4 , 
    }
  }
  
  \tl_put_right:Nx \l_tztangent_cmd_tl
    { 
        domain = \tztangentFromVal \c_colon_str \tztangentToVal ,
    }

  \tl_put_right:Nn \l_tztangent_cmd_tl
    { 
        #2 ] 
      plot ( \x , { \tztangentLFn } ) % \x should not be expanded
    }
    
  \gdef\TANCurve{#5}\gdef\TANWhere{#6}
  
  \tztangent_sub_fn:n
}

\NewDocumentCommand\tztangent_epsilon_process{ m m }
{
  \def\tztangentEpsilonOne{#1}
  \def\tztangentEpsilonTwo{#2}
}

\NewDocumentCommand\tztangent_domain_process{ m m }
{
  \def\tztangentFromVal{#1}
  \def\tztangentToVal{#2}
}

\cs_new:Npn \tztangent_sub_fn:n
{
  \tztangent_final_actions
}

\NewDocumentCommand\tztangent_final_actions { +G{} O{} D<>{} }
{
  \begin{pgfonlayer}{\tztangentlayer}
  \exp_last_unbraced:Nf \draw \l_tztangent_cmd_tl 
    node [ black , above~right , #2 ] { #1 } #3 ;
  \end{pgfonlayer}
  % to resolve TikZ issue: unknown path name with layer group
  \exp_last_unbraced:Nf \path \l_tztangent_cmd_tl ;
}

%%% --- end of \tztangent


%%%%% \tzbrace

%%% \tzbrace'[<opt>]{<raise>}[<brace opt>]
%%%          <shift coor>(<coor>)(<coor>){<text>}[<pos,opt>]
\NewDocumentCommand\tzbrace{ t' O{} G{5pt} O{} d<> r() r() +G{} O{} }
{
  \IfBooleanTF { #1 }
  {
    \draw [ decorate , decoration = 
            { calligraphic~brace , mirror , 
              amplitude = 5pt, raise = #3 , #4 } , #2
          ] 
  }
  {
    \draw [ decorate , decoration = 
            { calligraphic~brace , 
              amplitude = 5pt, raise = #3 , #4 } , #2
          ] 
  }
  \IfValueTF { #5 }
  {
    ([shift={(#5)}]#6) to node [ midway , #9 ] { #8 } 
    ([shift={(#5)}]#7) ;
  }
  {
    (#6) to node [ midway , #9 ] { #8 } (#7) ;
  }
}

%%% -- end of \tzbrace


%=====================================================
%=====================================================
\ExplSyntaxOff
%=====================================================
%=====================================================


\endinput

