%% xysmart.tex from $Id$
%%
%% Xy-pic ``Smart Path feature'' option.
%% Copyright (c) 1998 George C. Necula <necula@cs.cmu.edu>
%%
%% This file is part of the Xy-pic package for graphs and diagrams in TeX.
%% See the companion README and INSTALL files for further information.
%% Copyright (c) 1991-1998 Kristoffer H. Rose <krisrose@ens-lyon.fr>
%%
%% The Xy-pic package is free software; you can redistribute it and/or modify
%% it under the terms of the GNU General Public License as published by the
%% Free Software Foundation; either version 2 of the License, or (at your
%% option) any later version.
%%
%% The Xy-pic package is distributed in the hope that it will be useful, but
%% WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
%% or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
%% for more details.
%%
%% You should have received a copy of the GNU General Public License along
%% with this package; if not, write to the Free Software Foundation, Inc.,
%% 675 Mass Ave, Cambridge, MA 02139, USA.
%%
\ifx\xyloaded\undefined \input xy \fi
\xyprovide{smartpath}{Smart Path option}{\stripRCS$Revision: 0.0 $}%
 {George C. Necula}{necula@cs.cmu.edu}%
 {School of Computer Science,
 Carnegie Mellon University,
 5000 Forbes Avenue,
 Pittsburgh, PA 15213-3891, USA}
\xyrequire{arrow}\xycatcodes
\let\origPATHturn@=\PATHturn@
\def\PATHturn@{%
 \ifx \space@\next \expandafter\DN@\space{\xyFN@\PATHturn@}%
 \else\ifx s\next
 \let\origPATHturn@i=\PATHturn@i\let\PATHturn@i=\PATHsmartturn@i
 \let\origPATHturn@cir=\PATHturn@cir\let\PATHturn@cir=\PATHsmartturn@cir
 \DN@ s{\xyFN@\origPATHturn@}%
 \else
 \DN@{\origPATHturn@}%
 \fi\fi
 \next@}
\xydef@\PATHsmartturn@cir{%
 \edef\next@{{\CIRin@@}{\expandafter\noexpand\CIRorient@@}{\CIRout@@}}%
 \expandafter\PATHturn@i\next@}
\xydef@\PATHsmartturn@i#1#2#3{%
 \DN@##1{%
 \def\PATHinit@@{%
 \xy@@{%
 \def\sm@CIRin{#1}\def\sm@CIRout{#3}%
 \ifx\sm@CIRout\empty
 \let\sm@CIRout=\sm@CIRin
 \let\sm@CIRin=\PATHlastout@@
 \fi
 ##1\relax}%
 \xy@@{\enter@{\basefromthebase@}}%
 \xy@@{\sm@conn}%
 \xy@@{\X@p=\X@c \Y@p=\Y@c \czeroEdge@% Save the start of the segment
 \count@=\sm@CIRout\count@=\the\count@% Move forward a dash to
 \dimen@=\xydashl@ \ABfromdiag@ \advance\X@c\A@ \advance\Y@c\B@
 \edef\PATHpostpos@@{\X@c=\the\X@c \Y@c=\the\Y@c \noexpand\czeroEdge@
 \noexpand\PATHomitslide@@true}}%
 \xy@@{\leave@
 \edef\PATHlastout@@{\sm@CIRout}%
 \count@=\sm@CIRout \dimen@=\xydashl@ \Directionfromdiag@}}}%
 \expandafter\next@\expandafter{\the\toks@}\toks@={}%
 \let\PATHextra@@=\empty
 \def\PATHpost@@{\xy@@\PATHpostpos@@}%
 \let\PATHlabelsextra@@=\relax
 \let\PATHturn@i=\origPATHturn@i
 \let\PATHturn@cir=\origPATHturn@cir
 \xyFN@\PATHturn@ii}
\xydef@\sm@nil{}
\xydef@\sm@nnil{\sm@nil}
\xydef@\sm@maxcost{1000mm}%
\xydef@\sm@conn{
 \enter@{\cfromthec@ \DirectionfromtheDirection@}\cfromp@% Adjust p
 \count@=\sm@CIRin\count@=\the\count@
 \dimen@=\xydashl@ \ABfromdiag@ \advance\X@p\A@\advance\Y@p\B@
 \setupDirection@ \the\Edge@c\z@ \czeroEdge@
 \pfromc@
 \reverseDirection@
 \count@=\sm@CIRin\count@=\the\count@
 \dimen@=\xydashl@ \ABfromdiag@
 \edef\tmp@{\noexpand\dir\artail@@}\expandafter\sm@drop@\tmp@
 \X@c=\X@p\advance\X@c\A@ \Y@c=\Y@p\advance\Y@c\B@ \czeroEdge@
 \sm@stri
 \X@p=\X@c \Y@p=\Y@c
 \leave@
 \enter@{\pfromthep@ \DirectionfromtheDirection@}\pfromc@% Adjust c
 \count@=\sm@CIRout\count@=\the\count@
 \dimen@=\xydashl@ \ABfromdiag@ \advance\X@p-\A@\advance\Y@p-\B@
 \setupDirection@ \the\Edge@c\z@
 \advance\X@c-\A@\advance\Y@c-\B@% Leave room for a dash to terminate the seg
 \czeroEdge@
 \def\PATHlabelsnext@@{}%
 \leave@
 \R@=\turnradius@
 \cirrestrict@@%Adjust the radius to fit the circles
 \let\sm@circles=\sm@nil
 \edef\sm@bestcost{\sm@maxcost}%
 \sm@trycircles 1%Try counter clockwise first
 \sm@trycircles{-1}%
 \ifdim\sm@bestcost<\sm@maxcost
 \cfromp@
 \expandafter\sm@conndraw\sm@bestconn
 \else
 \xyerror@{Cannot draw the smart connector}{}%
 \fi
}
\xydef@\sm@trycircles#1{%
 \ifnum #1>0% Compute the opposite orientation
 \def\sm@CIRorienti{-1}%
 \else
 \def\sm@CIRorienti{1}%
 \fi
 \edef\tmp@{{{\sm@CIRin}{#1}{\sm@CIRout}}}%
 \expandafter\sm@trycirclelist\expandafter{\tmp@\sm@nil}%
 \count@@=\sm@CIRin\count@@=\the\count@@\count@=\count@@
 \sm@roundcount@{#1}%
 \edef\sm@savecount@{\the\count@}%
 \ifnum\the\count@=\the\count@@ \else
 \edef\tmp@{{{\sm@CIRin}{#1}{\the\count@}}%
 {{\the\count@}{\sm@CIRorienti}{\sm@CIRout}}}%
 \expandafter\sm@trycirclelist\expandafter{\tmp@\sm@nil}%
 \fi
 \count@=\sm@savecount@\count@=\the\count@
 \sm@advancecount@ 2{#1}\edef\sm@savecount@{\the\count@}%
 \edef\tmp@{{{\sm@CIRin}{#1}{\the\count@}}%
 {{\the\count@}{\sm@CIRorienti}{\sm@CIRout}}}%
 \expandafter\sm@trycirclelist\expandafter{\tmp@\sm@nil}%
 \count@=\sm@savecount@\count@=\the\count@
 \sm@advancecount@ 2{#1}\edef\sm@savecount@{\the\count@}%
 \edef\tmp@{{{\sm@CIRin}{#1}{\the\count@}}%
 {{\the\count@}{\sm@CIRorienti}{\sm@CIRout}}}%
 \expandafter\sm@trycirclelist\expandafter{\tmp@\sm@nil}%
 \count@=\sm@savecount@\count@=\the\count@
 \sm@advancecount@ 2{#1}\edef\sm@savecount@{\the\count@}%
 \edef\tmp@{{{\sm@CIRin}{#1}{\the\count@}}%
 {{\the\count@}{\sm@CIRorienti}{\sm@CIRout}}}%
 \expandafter\sm@trycirclelist\expandafter{\tmp@\sm@nil}%
}
\xydef@\sm@advancecount@#1#2{%
 \ifnum #2>0
 \edef\tmp@{#1}%
 \else
 \edef\tmp@{-#1}%
 \fi
 \advance\count@\tmp@\count@=\the\count@
 \ifnum\the\count@<0 \advance\count@ 8\fi
 \ifnum\the\count@>7 \advance\count@ -8\fi
 \count@=\the\count@
}
\xydef@\sm@roundcount@#1{%
 \ifcase\the\count@
 \advance\count@ #1\or
 \or \advance\count@ #1\or
 \or \advance\count@ #1\or
 \or \advance\count@ #1\fi
 \count@=\the\count@
 \ifnum\the\count@<0 \advance\count@ 8\fi
 \ifnum\the\count@>7 \advance\count@ -7\fi
 \count@=\the\count@
}
\newif\ifsm@firstseg
\newif\ifsm@acceptable
\xydef@\sm@trycirclelist#1{%
 \R@p=\z@\U@p=\R@p% Clear the deltas
 \def\sm@exthp{0}\def\sm@exthm{0}%
 \def\sm@extvp{0}\def\sm@extvm{0}%
 \def\sm@dxp{0pt}\def\sm@dxm{0pt}%
 \def\sm@dyp{0pt}\def\sm@dym{0pt}%
 \def\sm@segs{}%
 \sm@firstsegtrue
 \def\sm@connlen{0pt}%
 \let\sm@tryclcont=\sm@trycirclelist@i
 \sm@trycirclelist@i #1%Strip {} to expose the list elements
 \count@@=\sm@CIRout\count@@=\the\count@\count@=\the\count@
 \sm@roundcount@{1}%
 \ifnum\count@=\count@@
 \edef\sm@segs{\sm@segs{{\the\count@}{1}{\the\count@}}}%
 \fi
 \A@=\X@p\advance\A@\R@p\advance\A@ -\X@c\A@=-\A@
 \B@=\Y@p\advance\B@\U@p\advance\B@ -\Y@c\B@=-\B@
 \sm@acceptabletrue
 \ifdim\A@>0pt
 \ifnum\sm@exthp>0 \dimen@=\A@ \divide\dimen@\sm@exthp
 \edef\sm@dxp{\the\dimen@}%
 \else \sm@acceptablefalse\fi\fi
 \ifdim\A@<0pt
 \ifnum\sm@exthm>0 \dimen@=\A@ \divide\dimen@\sm@exthm
 \edef\sm@dxm{\the\dimen@}%
 \else \sm@acceptablefalse\fi
 \A@=-\A@%Make it positive
 \fi
 \ifdim\B@>0pt
 \ifnum\sm@extvp>0 \dimen@=\B@ \divide\dimen@\sm@extvp
 \edef\sm@dyp{\the\dimen@}%
 \else \sm@acceptablefalse\fi\fi
 \ifdim\B@<0pt
 \ifnum\sm@extvm>0 \dimen@=\B@ \divide\dimen@\sm@extvm
 \edef\sm@dym{\the\dimen@}%
 \else \sm@acceptablefalse\fi
 \B@=-\B@
 \fi
 \ifsm@acceptable
 \dimen@=\sm@connlen\advance\dimen@\A@\advance\dimen@\B@
 \ifdim\dimen@<\sm@bestcost
 \edef\sm@bestcost{\the\dimen@}%
 \edef\sm@bestconn{{\sm@dxp}{\sm@dxm}{\sm@dyp}{\sm@dym}{\sm@segs}}%
 \fi
 \fi
}
\xydef@\sm@showext#1{%
 \W@{#1\space hp=\sm@exthp,hm=\sm@exthm,vp=\sm@extvp
 ,vm=\sm@extvm,len=\sm@connlen}}
\xydef@\sm@trycirclelist@i#1{%
 \def\@tmp{#1}%
 \ifx \@tmp\sm@nnil \let\sm@tryclcont=\relax\else
 \expandafter\sm@tryclcar\@tmp \fi
 \sm@tryclcont}
\xydef@\sm@tryclcar#1#2#3{%
 \dimen@=\ifnum #2<0 -\fi\R@
 \count@=#1\count@=\the\count@ \ABfromdiag@
 \advance\R@p -\B@ \advance\U@p \A@
 \count@=#3\count@=\the\count@ \ABfromdiag@
 \advance\R@p \B@ \advance\U@p -\A@
 \sm@computeext{#1}{#2}{#3}%
}
\xydef@\sm@computeext#1#2#3{%
 \ifsm@firstseg
 \sm@accumext#1%
 \sm@firstsegfalse
 \fi
 \count@@=#1\count@@=\the\count@@\count@=\count@@
 \dimen@=\sm@connlen
 \sm@roundcount@{#2}%
 \ifnum \count@=\count@@
 \sm@advancecount@ 1{#2}%
 \advance\dimen@ 0.7854\R@% It was incremented with 1/8 circle
 \ifnum \count@=#3% Check if done
 \else
 \sm@advancecount@ 1{#2}%
 \advance\dimen@ 0.7854\R@% It was incremented with 1/8 circle
 \fi
 \else
 \advance\dimen@ 0.7854\R@% It was incremented with 1/8 circle
 \fi
 \edef\sm@connlen{\the\dimen@}%
 \sm@accumext{\the\count@}%
 \edef\sm@segs{\sm@segs{{#1}{#2}{\the\count@}}}%
 \ifnum\the\count@=#3 \else
 \edef\tmp@{{\the\count@}{#2}{#3}}%
 \expandafter\sm@computeext\tmp@
 \fi
}
\xydef@\sm@accumext#1{%
 \ifcase #1%
 \or \count@@=\sm@extvm\advance\count@@ by1%
 \edef\sm@extvm{\the\count@@}%
 \or\or \count@@=\sm@exthp\advance\count@@ by1%
 \edef\sm@exthp{\the\count@@}%
 \or\or \count@@=\sm@extvp\advance\count@@ by1%
 \edef\sm@extvp{\the\count@@}%
 \or\or \count@@=\sm@exthm\advance\count@@ by1%
 \edef\sm@exthm{\the\count@@}%
 \fi
}
\xydef@\sm@conndraw#1#2#3#4#5{%
 \def\sm@contlist{\sm@drawseglist}%
 \edef\sm@dxp{#1}%
 \edef\sm@dxm{#2}%
 \edef\sm@dyp{#3}%
 \edef\sm@dym{#4}%
 \sm@drawseglist #5\sm@nil}
\xydef@\sm@drawseglist#1{%
 \ifx #1\sm@nil \def\sm@contlist{}\else
 \sm@drawseg #1\fi
 \sm@contlist}
\xydef@\sm@drawseg#1#2#3{%
 \def\CIRin@@{#1}\def\CIRout@@{#3}%
 \sm@straight%See if a straight line is needed here. Insert it and
 \ifnum\CIRin@@=\CIRout@@ \else
 \count@=\CIRin@@
 \dimen@=\ifnum #2<0 -\fi\R@
 \ABfromdiag@
 \advance\X@c -\B@ \advance\Y@c \A@
 \ifnum #2>0 \def\CIRorient@@{\CIRacw@}%
 \else \def\CIRorient@@{\CIRcw@}\fi
 \drop@\literal@{\hbox\bgroup\cir@i}%
 \dimen@=\ifnum #2<0 -\fi\R@
 \count@=\CIRout@@\count@=\count@%Wierd. If I remove this last assignm
 \ABfromdiag@
 \advance\X@c\B@ \advance\Y@c-\A@
 \fi
}
\xydef@\sm@straight{%
 \U@c=\z@\D@c=\U@c\L@c=\U@c\R@c=\U@c
 \pfromc@
 \ifcase \CIRin@@ \or% 1 is V-
 \A@=\sm@dym\advance \Y@c\A@
 \or\or
 \A@=\sm@dxp\advance \X@c\A@
 \or\or
 \A@=\sm@dyp\advance \Y@c\A@
 \or\or
 \A@=\sm@dxm\advance \X@c\A@ \fi
 \ifdim\X@c=\X@p\ifdim\Y@c=\Y@p\else \sm@stri \fi\else \sm@stri \fi
}
\xydef@\sm@stri{%
 \edef\tmp@{\expandafter\noexpand\arstemprefix@@\arstem@@}%
 \expandafter\sm@connect@\tmp@}
\xydef@\sm@connect@#1#{%
 \DN@##1{\connect@{#1}{##1}}\next@}
\xydef@\sm@drop@#1#{%
 \DN@##1{\drop@{#1}{##1}}\next@}
\xydef@\smconn#1#2#3{%
 \edef\sm@CIRin{#1}\edef\sm@CIRout{#2}%
 \R@=#3\R@=\the\R@
 \sm@conn}
\xyendinput
