%
% OODGraph: One Out-Degree Graphs library
%
% This library draws connected graphs with out-degree one. To draw unconnected OOD graphs, just draw separatedly their connected components
%
%\RequirePackage{etoolbox}
% % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % %
% This code below have been borrowed from etoolbox package  ----|          %
% % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % %%V% % % %
\newcommand*{\oodgraph@csxdef}[2]{\expandafter\xdef\csname#1\endcsname{#2}}
\newcommand*{\oodgraph@ifcsdef}[1]{%
  \ifcsname#1\endcsname
    \expandafter\@firstoftwo
  \else
    \expandafter\@secondoftwo
  \fi}
\newcommand*{\oodgraph@ifcsundef}[1]{%
  \ifcsname#1\endcsname
    \expandafter\ifx\csname#1\endcsname\relax
      \expandafter\expandafter
      \expandafter\@firstoftwo
    \else
      \expandafter\expandafter
      \expandafter\@secondoftwo
    \fi
  \else
    \expandafter\@firstoftwo
  \fi}
\newcommand*{\oodgraph@csuse}[1]{%
  \ifcsname#1\endcsname
    \csname#1\expandafter\endcsname
  \fi}
\newcommand{\oodgraph@cslet}[2]{%
    \expandafter\let\csname#1\endcsname#2}
\newcommand*{\oodgraph@csgundef}[1]{\global\oodgraph@cslet{#1}\relax}

% % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % A %
% The above code have been borrowed from etoolbox package  ----| %
% % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % %
%
% Version 0.1 (2019/05/25):
% - first public release
% Version 0.2 (2019/06/01):
% - added /.store in key
% - added /.default key
% - cleaned up code
% Version 0.3 (2019/06/14)
% - fixed drawing algorithm
% - points definitions are now saved in a list
% - the points list is emptied at the closing of the environment oodgraph
% Version 0.4 (2019/06/18)
% - now commands are completely scoped
% - redisigned the graph printing algorithm to take into account that now
%    everything is scoped
% Version 0.45 (2019/06/19)
% - added the option 'rotation angle'
% Version 0.46 (2019/06/20)
% - added the option 'node content'
% - added bridge to tikz and pgf when a key is not known
% - made the library independent of 'etoolbox' package (borrow
%    some code from the package)
% - added oodgraph@ prefix to all commands so to avoid conflicts with other
%    packages/libraries
% Version 0.47 (2019/06/28)
% - options 'oodgraph arrow' and 'oodgraph node' renamed into 'oodgraph edges' and 'oodgraph nodes' for more consistancy
% - fixed a bug with edges style
% - now '->' is the default edge style
% Version 0.48 (2019/07/14)
% - added a check in \addorigin to verifiy if the point has been defined before
% - some code polishing (eliminated the list oodgraph@more@options which is no
%    more used, deleted \oodgraph@resetkeys function and integrated its code
%    directly into the calling functions since its body contained only an \end{scope}
%    command, deleted several unuseful \expandafter commands)
% - explicited the definition of oodgraph@csxdef
% - partially rewritten the drawing routine for beards. Now it is much faster
% Version 0.50 (2019/07/15)
% - renamed style options 'oodgraph nodes' into 'nodes style' which is shorter and nicer
% - renamed style options 'oodgraph nodes' into 'nodes style' which is shorter and nicer
% - introduced the option 'loop style' which allows to style the loops
% - fixed a bug for the special case of cycles of order 2 which drawn the two edges
%   one over the other (obtening a double arrow). Thanks to François Doré for signalling
%   this.
% - bug fix: the beards to be wrongly oriented when the xshift key
%   was used in the addcycle command. Bug discovery and fix by François Doré
% - bug fix: when a cycle had only 2 nodes, they addresses where exchanged. Thanks
%   to François Doré for signalling this

\def\fileversion{0.50}
\def\filedate{2019/08/21}
\message{Library OODGraph}
\message{ v.\ \fileversion, \filedate}
% load tikz dependencies
\usetikzlibrary{calc}
\makeatletter
\gdef\oodgraph@tmp{}
\gdef\oodgraph@points@list{}
%
% convenience routines to extract the prefix from a node path
%
\def\oodgraph@get@prefix@from@path@@#1-#2\pgf@eov{\xdef\oodgraph@tmp{\oodgraph@csuse{#1.origin}}}
\def\oodgraph@get@prefix@from@path#1{
\pgfutil@in@{-}{#1}
\ifpgfutil@in@% if there is a minus sign then it is a package defined point
\oodgraph@get@prefix@from@path@@#1\pgf@eov
\else% regular pgf/tikz point
\path(#1);\pgfgetlastxy{\XCoord}{\YCoord};
\xdef\oodgraph@tmp{(\XCoord,\YCoord)}
\fi
}
%
%  oodgraph@addtolist
%  #1 = name of the list to add to
%  #2 = object to be added
% Service function to append objects to lists
%
\newcommand*{\oodgraph@addtolist}[2]{%
   \expandafter\if\expandafter\relax\csname #1\endcsname\relax%
      \expandafter\expandafter\xdef\csname #1\endcsname{#2}%
   \else%
    \expandafter\xdef\csname #1\endcsname{\csname #1\endcsname,#2}%
\fi%
}
%
%  oodgraph@docslist@undeft
%  #1 = separator char
%  #2 = name of the list
% Service routine to \csundef all elements of the list
% 
\newcommand{\oodgraph@docslist@undef}[2][,]{%
%   #1 = separation char
%   #2 = list
   \def\dolist##1{\expandafter\@dolist##1#1\@eol}%
   \def\@dolist##1#1##2\@eol{%
   % process stuff here with ##1
   \oodgraph@csgundef{##1}
   \ifx\@eol##2\@eol\else\@dolist##2\@eol\fi}%
   \dolist{#2}%
}
%
\pgfkeys{/oodgraph/.search also={/tikz, /pgf}} %,/oodgraph/catch unknown}}%
%\pgfkeys{/oodgraph/.search also={/tikz,/pgf,/oodgraph/catch unknown}}%
\pgfkeys{%
/oodgraph/.cd,
%radius/.initial={1},
radius/.value required,
radius/.default={1},
radius/.store in=\oodgraph@radius,
radius,
%attach node/.initial={a->1},
attach node/.value required,
attach node/.default={a->1},
attach node/.store in=\oodgraph@attach@node,
attach node,
%nodes prefix/.initial={a},
nodes prefix/.value required,
nodes prefix/.default={a},
nodes prefix/.store in=\oodgraph@nodes@prefix,
nodes prefix,
%opening angle/.initial={120},
opening angle/.value required,
opening angle/.default={120},
opening angle/.store in=\oodgraph@opa,
opening angle,
rotation angle/.value required,
rotation angle/.default={0},
rotation angle/.store in=\oodgraph@rota,
rotation angle,
nodes content/.value required,
nodes content/.default={$\bullet$},
nodes content/.store in=\oodgraph@node@content,
nodes content,
nodes@style/.style={},
edges@style/.style={->},
loop@style/.style={out=-30, in=-150,looseness=6},
nodes style/.code=\pgfkeys{/oodgraph/nodes@style/.style={#1}},
edges style/.code=\pgfkeys{/oodgraph/edges@style/.style={#1}},
loop style/.code=\pgfkeys{/oodgraph/loop@style/.style={#1}},
semi thick/.code=\pgfkeys{/oodgraph/edges@style/.append style={semi thick}},
thick/.code=\pgfkeys{/oodgraph/edges@style/.append style={thick}},
ultra thick/.code=\pgfkeys{/oodgraph/edges@style/.append style={ultra thick}},
edges color/.code=\pgfkeys{/oodgraph/edges@style/.append style={#1}},
nodes color/.code=\pgfkeys{/oodgraph/nodes@style/.append style={#1}},
}
%\pgfkeys{/oodgraph/.unknown/.code={%
%\ifx#1\pgfutil@empty\oodgraph@addtolist{oodgraph@more@options}{\pgfkeyscurrentname}\else\oodgraph@addtolist{oodgraph@more@options}{\pgfkeyscurrentname=#1}
%\fi}}
%
\newenvironment{oodgraph}[1][]{\begin{scope}[#1]}
{% closing the environment
% free all points definition in the current list
%\forcsvlist{\csgundef}{\oodgraph@points@list}
\expandafter\oodgraph@docslist@undef\expandafter{\oodgraph@points@list}
% free the points list
\gdef\oodgraph@points@list{}
% free temporary definitions
\gdef\oodgraph@tmp{}
\end{scope}}
%
\newcommand{\oodgraph@processkeys}[1][]{
\begin{scope}
\pgfkeys{/oodgraph/.cd,#1}
}
\long\def\oodgraph@drawcycle#1;{
\ifnum#1=1\oodgraph@drawcycle@\else%
{\ifnum#1=2\oodgraph@drawcycle@@{#1}\else%
\oodgraph@drawcycle@@@{#1}\fi}\fi
% record circle center on points list and define it
\path(0,0);\pgfgetlastxy{\XCoord}{\YCoord};
\oodgraph@ifcsundef{\oodgraph@nodes@prefix.origin}{%
% if undefined then add to the point list
\oodgraph@csxdef{\oodgraph@nodes@prefix.origin}{(\XCoord,\YCoord)}
\oodgraph@addtolist{oodgraph@points@list}{\oodgraph@nodes@prefix.origin}
}%
{% if already defined then simply replace the old definition
\oodgraph@csxdef{\oodgraph@nodes@prefix.origin}{(\XCoord,\YCoord)}
}%
\end{scope}
}
%
\newcommand{\oodgraph@drawcycle@}{
%\pgfcoordinate{myorigin}{\pgfpointorigin}
\node[/oodgraph/nodes@style](\oodgraph@nodes@prefix->1) at(0,0){\oodgraph@node@content};
% save points on the list
\oodgraph@addtolist{oodgraph@points@list}{\oodgraph@nodes@prefix->1}
%\expandafter\oodgraph@csxdef\expandafter{\oodgraph@nodes@prefix->1}{(0pt,0pt)}
\oodgraph@csxdef{\oodgraph@nodes@prefix->1}{(0pt,0pt)}
% draw edges
\draw[/oodgraph/edges@style] 
(\oodgraph@nodes@prefix->1) edge[/oodgraph/loop@style] (\oodgraph@nodes@prefix->1);
}
\newcommand{\oodgraph@drawcycle@@}{
% second node
\pgfmathsetmacro{\oodgraph@half@radius}{.5*\oodgraph@radius}
\node[/oodgraph/nodes@style](\oodgraph@nodes@prefix->2) at(-\oodgraph@half@radius,0){\oodgraph@node@content};
% first node
\node[/oodgraph/nodes@style](\oodgraph@nodes@prefix->1) at(\oodgraph@half@radius,0){\oodgraph@node@content};
% register nodes
\oodgraph@addtolist{oodgraph@points@list}{\oodgraph@nodes@prefix->1}
\oodgraph@addtolist{oodgraph@points@list}{\oodgraph@nodes@prefix->2}
\oodgraph@csxdef{\oodgraph@nodes@prefix->1}{(-\oodgraph@half@radius,0pt)}
\oodgraph@csxdef{\oodgraph@nodes@prefix->2}{(\oodgraph@half@radius,0pt)}
% draw edges
\draw[/oodgraph/edges@style] 
(\oodgraph@nodes@prefix->1) edge[/oodgraph/edges@style, bend left] (\oodgraph@nodes@prefix->2);
\draw[/oodgraph/edges@style] 
(\oodgraph@nodes@prefix->2) edge[/oodgraph/edges@style, bend left] (\oodgraph@nodes@prefix->1);
}
\newcommand{\oodgraph@drawcycle@@@}[1]{
\pgfmathsetmacro\myangle{360.0/#1}
\foreach \i in {1,...,#1}{
  \pgfmathsetmacro\curangle{(\i-1)*\myangle}
\node[/oodgraph/nodes@style](\oodgraph@nodes@prefix->\i) at ({\oodgraph@radius*cos(\curangle)},{\oodgraph@radius*sin(\curangle)}){\oodgraph@node@content};
  \path(\oodgraph@nodes@prefix->\i); \pgfgetlastxy{\XCoord}{\YCoord};
  \oodgraph@addtolist{oodgraph@points@list}{\oodgraph@nodes@prefix->\i}
  \oodgraph@csxdef{\oodgraph@nodes@prefix->\i}{(\XCoord,\YCoord)}
}
%\wlog{list=\oodgraph@points@list}
\foreach \i in {1,...,#1}{
  \pgfmathsetmacro\mynext{ifthenelse(\i==#1,int(1),int(\i+1))}
  \draw[/oodgraph/edges@style] (\oodgraph@nodes@prefix->\i) -- (\oodgraph@nodes@prefix->\mynext);
}
}
\newcommand*{\addcycle}[1][]{%
\oodgraph@processkeys[#1]
\oodgraph@drawcycle
}
%
\def\addorigin#1;{%
\pgfutil@ifundefined{pgf@sh@ns@#1}{
\edef\mymsgtmp{No point named #1\space has been found!}
\PackageError{OODGraph}\mymsgtmp
{Please verify that the point has been correctly defined via the standard TikZ interface.}
}{%
\path(#1);\pgfgetlastxy{\XCoord}{\YCoord};
\oodgraph@csxdef{#1}{(\XCoord,\YCoord)}%
\oodgraph@csxdef{#1.origin}{(\XCoord,\YCoord)}%
%\oodgraph@addtolist{oodgraph@points@list}{#1} % added v. 0.48
%\oodgraph@addtolist{oodgraph@points@list}{#1.origin} % added v. 0.48
}}
%
\newcommand{\addbeard}[1][]{%
\oodgraph@processkeys[#1]
\oodgraph@drawbeardlev
}
\def\oodgraph@drawbeardlev#1;{%
%\wlog{list=\oodgraph@points@list}
\ifnum#1=1\oodgraph@drawbeardlev@\else\oodgraph@drawbeardlev@@{#1}\fi
\end{scope}}
\newcommand{\oodgraph@drawbeardlev@}{
\oodgraph@ifcsdef{\oodgraph@attach@node}{%
\expandafter\oodgraph@get@prefix@from@path\expandafter{\oodgraph@attach@node}
\path[reset cm]\oodgraph@tmp;\pgfgetlastxy{\XOCoord}{\YOCoord};
%\path[reset cm]\oodgraph@csuse{\oodgraph@attach@node};\pgfgetlastxy{\XCoord}{\YCoord};
\path[reset cm](\oodgraph@attach@node);\pgfgetlastxy{\XCoord}{\YCoord};
}{% else signal errors
\edef\mymsgtmp{No point named \oodgrap@attach@node\space has been found!}
\PackageError{OODGraph}\mymsgtmp
{Please verify that the attachment node has been correctly defined or that there exists
a addorigin command.}
}%
\begin{scope}[shift={(\XOCoord, \YOCoord)}]
% recompute the coordinates of attach point in the new coordinate system
\pgfmathsetmacro\XCoord{\XCoord-\XOCoord}
\pgfmathsetmacro\YCoord{\YCoord-\YOCoord}
% compute angle wrt attachment point
\pgfmathsetmacro\myalphatmp{atan(\YCoord/(\XCoord+.01))}
\pgfmathsetmacro\myalpha{ifthenelse(\XCoord>=0,\myalphatmp,180+\myalphatmp)}
\pgfmathsetmacro\myalpha{\myalpha+\oodgraph@rota}
%
% draw the new node
\node[/oodgraph/nodes@style](\oodgraph@attach@node->1) at ($(\oodgraph@attach@node)+({\oodgraph@radius*cos(\myalpha)},{\oodgraph@radius*sin(\myalpha)})$){\oodgraph@node@content};
\draw[/oodgraph/edges@style] (\oodgraph@attach@node->1) -- (\oodgraph@attach@node);
% store infos about node
\oodgraph@addtolist{oodgraph@points@list}{\oodgraph@attach@node->1}
\path(\oodgraph@attach@node->1); \pgfgetlastxy{\XCoord}{\YCoord};
\oodgraph@csxdef{\oodgraph@attach@node->1}{(\XCoord,\YCoord)}
\end{scope}
}
\newcommand{\oodgraph@drawbeardlev@@}[1]{
% #1= number of nodes in the level
% check if the attachment node has been previously defined
\oodgraph@ifcsdef{\oodgraph@attach@node}{% then part
% if the attach node has been defined then
% find the root prefix and retrive the origin
\expandafter\oodgraph@get@prefix@from@path\expandafter{\oodgraph@attach@node}
\path[reset cm]\oodgraph@tmp;\pgfgetlastxy{\XOCoord}{\YOCoord};
\path[reset cm](\oodgraph@attach@node);\pgfgetlastxy{\XCoord}{\YCoord};
}% end of then part
{% if it is not defined, print an error message
\edef\mymsgtmp{No point named \oodgrap@attach@node\space has been found!}
\PackageError{OODGraph}\mymsgtmp
{Please verify that the attachment node has been correctly defined or that there exists a addorigin command.}
}%
\begin{scope}[shift={(\XOCoord, \YOCoord)}]
% myangle = angle between two successive points of the beard level
\pgfmathsetmacro\myangle{\oodgraph@opa/#1}
% recompute coordinates of attach point in the new coordinate system
\pgfmathsetmacro\XCoord{\XCoord-\XOCoord}
\pgfmathsetmacro\YCoord{\YCoord-\YOCoord}
% compute angle wrt attachment point
\pgfmathsetmacro\myalphatmp{atan(\YCoord/(\XCoord+.01))}
\pgfmathsetmacro\myalpha{ifthenelse(\XCoord>=0,\myalphatmp,180+\myalphatmp)}
\pgfmathsetmacro\myalpha{\myalpha+\oodgraph@rota}
% compute the offset angle
\pgfmathsetmacro\myofsangle{ifthenelse(mod(#1,2)==1,0.0,\myangle/2.0}
% draw nodes and edges
%\node at (6,6.5){alpha corr=\myalphacorr};
%\node at (6,6){\oodgraph@attach@node=\csuse{\oodgraph@attach@node}};
%\node at (6,5){point=(\XCoord,\YCoord)};
%\node at (6,4.5){myalpha=\myalpha};
%\node at (6,4.5){myangle=\myangle};
%\node at (6,4){myofsangle=\myofsangle};
%\node at (6,3.5){myend=\myend};
\pgfmathsetmacro\myend{int(ceil(#1/2.0))}
\pgfmathsetmacro\myalpha{\myalpha+\myend*\myangle+2*\myofsangle}
\foreach \i in {#1,...,1}{
\pgfmathsetmacro\mycurangle{\myalpha-(#1-\i+1)*\myangle-\myofsangle}
%\node at (6,3.5-\i){mycurangle=\mycurangle};
\node[/oodgraph/nodes@style](\oodgraph@attach@node->\i) at ($(\oodgraph@attach@node)+({\oodgraph@radius*cos(\mycurangle)},{\oodgraph@radius*sin(\mycurangle)})$){\oodgraph@node@content};
  \draw[/oodgraph/edges@style] (\oodgraph@attach@node->\i) -- (\oodgraph@attach@node);
  % save points to points@list
  \path(\oodgraph@attach@node->\i); \pgfgetlastxy{\XCoord}{\YCoord};
 \oodgraph@addtolist{oodgraph@points@list}{\oodgraph@attach@node->\i}
 \oodgraph@csxdef{\oodgraph@attach@node->\i}{(\XCoord,\YCoord)}
}
\end{scope}}
%
\makeatother
%
\endinput