%\iffalse meta-comment
%
% Copyright (c) 2010 by Daniel M\"ullner (Müllner)
% <http://www.math.uni-bonn.de/people/muellner>
% --------------------------------------------------------------------
%
% This program 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 3 of the License, or
% (at your option) any later version.
%
% This program 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.
%
% The GNU General Public License is available at
% <http://www.gnu.org/licenses/>.
%
% --------------------------------------------------------------------
%
% This file is part of the LaTeX2e xypdf package. The package
% consists of the following files:
%
%    README     -  This file, the distribution guide
%    xypdf.dtx  -  Documented source code
%    xypdf.ins  -  Installation script
%    xypdf.pdf  -  Documentation (generated from xypdf.dtx)
%
% The LaTeX style file xypdf.sty is generated by the following command:
%
%    latex xypdf.ins
%
% \fi
%
% \iffalse
%<package>\NeedsTeXFormat{LaTeX2e}
%<package>\ProvidesPackage{xypdf}
%<package> [2010/04/12 v1.3 PDF output for the Xy-pic package]
%
%<*driver>
\documentclass[a4paper]{ltxdoc}
\usepackage{amsmath}
\usepackage{amsfonts}
\newcommand*{\co}{\:{:}\;}
\usepackage{ifpdf}
  \ifpdf
    \newcommand*\driver{}
  \else
    \newcommand*\driver{dvipdfm}
  \fi
\usepackage[hmargin={4.6cm,2.5cm},vmargin={2.5cm,3.5cm},\driver]{geometry}
\usepackage[
  pdfstartview=FitH,
  pdftitle={The xypdf package},
  pdfauthor={Daniel Müllner},
  pdfsubject={PDF output for the Xy-pic package},
  \driver
  ]{hyperref}
\renewcommand*\sectionautorefname{Section}
\usepackage[all]{hypcap}
\usepackage[ansinew]{inputenc}
\usepackage{lmodern}
\normalfont
\usepackage[T1]{fontenc}
\usepackage[arrow,curve,rotate]{xy}
\usepackage{xypdf}
\usepackage{shortvrb}
 \MakeShortVerb{\"}
 \AtBeginDocument{\DeleteShortVerb{\|}}% revoke the shortcut from ltxdoc.cls
\usepackage{array}
\usepackage{booktabs}
\usepackage{xcolor}
\selectcolormodel{rgb}
\definecolor{varcolA}{Hsb}{  0,1,.7}
\definecolor{varcolB}{Hsb}{ 40,1,.7}
\definecolor{varcolC}{Hsb}{ 60,1,.7}
\definecolor{varcolD}{Hsb}{120,1,.7}
\definecolor{varcolE}{Hsb}{180,1,.7}
\definecolor{varcolF}{Hsb}{240,1,.7}
\definecolor{varcolG}{Hsb}{300,1,.7}
\newcommand*\BulletA{\textcolor{varcolA}{\textbullet1}}
\newcommand*\BulletB{\textcolor{varcolB}{\textbullet2}}
\newcommand*\BulletC{\textcolor{varcolC}{\textbullet3}}
\newcommand*\BulletD{\textcolor{varcolD}{\textbullet4}}
\newcommand*\BulletE{\textcolor{varcolE}{\textbullet5}}
\newcommand*\BulletF{\textcolor{varcolF}{\textbullet6}}
\newcommand*\BulletG{\textcolor{varcolG}{\textbullet7}}
%\usepackage{showframe}
%\EnableCrossrefs
%\CodelineIndex
%\CodelineNumbered
%\RecordChanges
%\makeatletter
%\def\IndexParms{%
%  \parindent \z@
%  \columnsep 10pt
%  \parskip 0pt plus 1pt
%  \rightskip \z@ % x pt
%  \mathsurround \z@
%  \parfillskip=\z@ % -x pt
%   \small
%  \def\@idxitem{\par\hangindent 20pt}%
%  \def\subitem{\@idxitem\hspace*{15pt}}%
%  \def\subsubitem{\@idxitem\hspace*{25pt}}%
%  \def\indexspace{\par\vspace{10pt plus 2pt minus 3pt}}%
%}
%\makeatother
\settowidth\MacroIndent{\rmfamily\scriptsize 123\ }
\newcommand*\centercolon[1]{\vcenter{\mathsurround0pt\hbox{$#1:$}}}
\newcommand*\coloneq{\ensuremath{\mathrel{\mathpalette\centercolon=}}}
\begin{document}
\DocInput{xypdf.dtx}
\end{document}
%</driver>
% \fi
%
% \CheckSum{5808}
%
% \CharacterTable
%  {Upper-case    \A\B\C\D\E\F\G\H\I\J\K\L\M\N\O\P\Q\R\S\T\U\V\W\X\Y\Z
%   Lower-case    \a\b\c\d\e\f\g\h\i\j\k\l\m\n\o\p\q\r\s\t\u\v\w\x\y\z
%   Digits        \0\1\2\3\4\5\6\7\8\9
%   Exclamation   \!     Double quote  \"     Hash (number) \#
%   Dollar        \$     Percent       \%     Ampersand     \&
%   Acute accent  \'     Left paren    \(     Right paren   \)
%   Asterisk      \*     Plus          \+     Comma         \,
%   Minus         \-     Point         \.     Solidus       \/
%   Colon         \:     Semicolon     \;     Less than     \<
%   Equals        \=     Greater than  \>     Question mark \?
%   Commercial at \@     Left bracket  \[     Backslash     \\
%   Right bracket \]     Circumflex    \^     Underscore    \_
%   Grave accent  \`     Left brace    \{     Vertical bar  \|
%   Right brace   \}     Tilde         \~}
%
%
% \GetFileInfo{xypdf.sty}
%
% ^^A TeX and LaTeX commands
% \DoNotIndex{\@for,\@gobble,\@gtempa,\@ifdefinable,\@ifpackageloaded,\@ne,\@tempa,\@tempcnta,\@tempdima,\@tempdimb,\@tempdimc,\@tempswafalse,\@tempswatrue,\@temptokena,\@undefined}
% \DoNotIndex{\advance,\AtBeginDocument,\AtEndOfPackage}
% \DoNotIndex{\CheckCommand,\count,\count@,\csname}
% \DoNotIndex{\def,\dimen,\dimen@i,\dimexpr,\divide,\do}
% \DoNotIndex{\edef,\egroup,\else,\empty,\endcsname,\expandafter}
% \DoNotIndex{\fi,\fontdimen}
% \DoNotIndex{\gdef,\global}
% \DoNotIndex{\hbox}
% \DoNotIndex{\if@tempswa,\ifcase,\ifdefined,\ifdim,\iffalse,\ifnum,\ifodd,\ifpdf,\ifpdfabsdim,\ifx}
% \DoNotIndex{\kern}
% \DoNotIndex{\let,\loop}
% \DoNotIndex{\m@ne,\maxdimen,\multiply}
% \DoNotIndex{\newcommand,\newcount,\newdimen,\newif,\noexpand,\numexpr}
% \DoNotIndex{\or}
% \DoNotIndex{\p@,\PackageError,\PackageInfo,\pdfliteral}
% \DoNotIndex{\relax,\repeat,\RequirePackage}
% \DoNotIndex{\setbox,\space,\special,\string}
% \DoNotIndex{\textfont,\the,\thr@@,\toks@,\tw@}
% \DoNotIndex{\unexpanded,\usepackage}
% \DoNotIndex{\vrule}
% \DoNotIndex{\wlog}
% \DoNotIndex{\xdef}
% \DoNotIndex{\z@}
%
% ^^A Xy-pic commands which should not be indexed
%
% \DoNotIndex{\bstartPLACE@,\crv@,\crv@defaultshape,\crv@noobject,\crvSTYLE@@,
% \ctipEdge@,\dir,\DN@,\Drop@@,\Hidden@false,\ifInvisible@,\Invisible@false,
% \next@,\removePT@,\repeat@,\splinedefaulttol@,\splinedoubled@,
% \splineribboned@,\splineset@@,\splinetol@,\splinetrebled@,\styledboxz@,\tmp@,
% \xy@@crvaddstack@,\xycrvconn@,\xycrvdrop@}
%
% \title{The \textsf{xypdf} package}
% \author{\href{http://www.math.uni-bonn.de/people/muellner}{Daniel Müllner}}
% \date{\fileversion, dated \filedate}
%
% \maketitle
%
% \begin{abstract}\noindent
% The \textsf{xypdf} package improves the output quality of the \Xy-pic package when PDF documents are generated. It produces generic PDF code for graphical elements like lines, curves and circles instead of approximating these elements with glyphs in special fonts as the original \Xy-pic package does. The \textsf{xypdf} package works both with pdf\LaTeX{} and the two-step compilation \LaTeX${}\to{}$dvipdfm(x).
% \end{abstract}
%
% \section{Introduction}
%
% The \Xy-pic package is a utility for typesetting diagrams in \TeX{} and \LaTeX{} documents. The authors of the \Xy-pic package put much effort into the feature that most graphical elements are coded within the limited possibilities of the device independent file format (DVI). The diagrams can thus be generated with even the most basic \TeX{} systems and displayed universally by all device drivers. For example, diagonal lines are composed of short dashes, which are glyphs in a special font. Since there are dashes in 127 discrete directions in the font \textsf{xydash10}, diagonal lines which do not match one of these slopes look slightly rugged when they are magnified.
%
% For a better output quality in Postscript files, the authors of the \Xy-pic package provided a Postscript backend for DVI-to-Postscript drivers. These extensions draw lines and curves by generic Postscript commands, thus trading a much better output quality against universality of the produced DVI files.
%
% As the most recent version 3.7 of \Xy-pic dates from 1999, there is no support for pdf\TeX. In order to produce PDF files with high-quality \Xy-pic diagrams, users had to use so far the Postscript file format as an intermediate step or embed the diagrams as external graphics. However, since many users directly generate PDF files from the \TeX{} or DVI files (with bookmarks, hyperlinks and other PDF features), it is highly desirable to also have the possibility of directly generating \Xy-pic diagrams with high-quality PDF graphics elements.
%
% The present package \textsf{xypdf} adapts the output routines of the \Xy-pic package to generate high-quality graphics for PDF output. It works with both pdf\LaTeX and the two-step compilation \LaTeX${}\to{}$dvipdfm(x) with an intermediate DVI file. Note that some version of $\varepsilon$-\TeX{} is needed (which is anyway used by default in modern \TeX{} installations). \autoref{Fig1} compares the output quality of a small \Xy-pic diagram.
% \newcommand*\testdiag{\xy *[*10]\hbox{\xy (5,0): 0;
% a(0) **\dir{-},
% a(6.524)**\dir{-},
% a(13.048) **\dir{-},
% a(19.572) **\dir{-},
% a(26.096) **\dir{-},
% a(32.62) **\dir{-},
% a(39.144) **\dir{-},
% @+(-.2,.5),
% @+(.5,.3),
% a(70) *+<.5pt>{} **\crvs{-}
% \endxy}\endxy}
% \begin{figure}\label{Fig1}
% \centering\setlength\tabcolsep{1.5em}
% \begin{tabular}{@{}cc@{}}
% without \textsf{xypdf} & with \textsf{xypdf}\\
% \midrule
% \xypdfoff\testdiag & \testdiag
% \end{tabular}
% \caption{Comparison of \Xy-pic output, magnified 10 times.}
% \end{figure}
%
% The \textsf{xypdf} package is very similar to the Postscript backend to \Xy-pic. It does not have (yet) all features of the Postscript backend (see \autoref{sec:todo}) but is much more powerful in other respects, e.\,g.\ when drawing multiple curves. In general, it greatly improves graphics quality in most circumstances and otherwise leaves graphics elements as they are. Currently, the following features are implemented:
% \newcommand\showline[1]{{\xypdfoff#1}&{\xypdfon#1}}
% \begin{itemize}
% \item
% Both straight lines and curves (solid, dashed, dotted and squiggled) are drawn by generic PDF commands.
%
% \item
% \Xy-pic automatically draws the symbols of which lines and curves are composed at the very beginning and end of a segment. It then distributes the inner symbols evenly across the segment. Since the arc length of a Bézier curve is normally not proportional to its parameter, this is a nontrivial task in the case of curves. The \textsf{xypdf} package handles this better than the original code. Compare the output in \autoref{Fig2}.
%
% \begin{figure}\label{Fig2}
% \centering\setlength\tabcolsep{1.5em}
% \begin{tabular}{@{}ccl@{}}
% without \textsf{xypdf}& with \textsf{xypdf}&\meta{arrow style}\\
% \midrule
% \showline{\xy(0,0) \ar @{|-|}@`{(20,20),(10,-20)} (30,0) \endxy}&"{|-|}"\\[-2.5pc]
% \showline{\xy(0,0) \ar @2{|-|}@`{(20,20),(10,-20)} (30,0) \endxy}&"2{|-|}"\\[-2.5pc]
% \showline{\xy(0,0) \ar @3{|-|}@`{(20,20),(10,-20)} (30,0) \endxy}&"3{|-|}"\\[-2.5pc]
% \showline{\xy(0,0) \ar @{|--|}@`{(20,20),(10,-20)} (30,0) \endxy}&"{|--|}"\\[-2.5pc]
% \showline{\xy(0,0) \ar @2{|--|}@`{(20,20),(10,-20)} (30,0) \endxy}&"2{|--|}"\\[-2.5pc]
% \showline{\xy(0,0) \ar @3{|--|}@`{(20,20),(10,-20)} (30,0) \endxy}&"3{|--|}"\\[-2.5pc]
% \showline{\xy(0,0) \ar @{|.|}@`{(20,20),(10,-20)} (30,0) \endxy}&"{|.|}"\\[-2.5pc]
% \showline{\xy(0,0) \ar @2{|.|}@`{(20,20),(10,-20)} (30,0) \endxy}&"2{|.|}"\\[-2.5pc]
% \showline{\xy(0,0) \ar @3{|.|}@`{(20,20),(10,-20)} (30,0) \endxy}&"3{|.|}"\\[-2.5pc]
% \showline{\xy(0,0) \ar @{|~|}@`{(20,20),(10,-20)} (30,0) \endxy}&"{|~|}"\\[-2.5pc]
% \showline{\xy(0,0) \ar @2{|~|}@`{(20,20),(10,-20)} (30,0) \endxy}&"2{|~|}"\\[-2.5pc]
% \showline{\xy(0,0) \ar @3{|~|}@`{(20,20),(10,-20)} (30,0) \endxy}&"3{|~|}"
% \end{tabular}
% \flushleft
% Code: "\xy (0,0) \ar @"\meta{arrow style}"@`{(20,20),(10,-20)} (30,0) \endxy"
% \caption{Comparison of \Xy-pic output for curves with various line styles.}
% \end{figure}
%
% \item
% As a highlight, \textsf{xypdf} features a Bézier curve offset algorithm, producing high-quality curves with two or three parallel strokes.
% \[
% \xy \ar@3{-}@`{(10,0),(20,8),(10,17),(0,8),(10,0)} (20,0)\endxy
% \]
%
% \item
% The "\cir" object draws circles of arbitrary radius.
% \begin{center}
% \begin{tabular}{@{}ccl@{}}
% without \textsf{xypdf}& with \textsf{xypdf}&code\\
% \midrule
% \showline{\xy *\cir<16pt>{} *\cir<19pt>{} \endxy}&"\xy *\cir<16pt>{} *\cir<19pt>{} \endxy"
% \end{tabular}
% \end{center}
%
% \item
% \textsf{xypdf} supports the “rotate” extension of \Xy-pic.
% \begin{center}
% \begin{tabular}{@{}cl@{}}
% with \textsf{xypdf}&code\\
% \midrule
% \xy *!D[@!15]\hbox{Test text} \endxy\vrule width 0pt height 3ex depth 2ex&"\xy *[@!15]\hbox{Test text} \endxy"\\
% \xy *!D[*1.5]\hbox{Test text} \endxy&"\xy *[*1.5]\hbox{Test text} \endxy"
% \end{tabular}
% \end{center}
% \end{itemize}
%
% If you notice any unwanted behavior, please generate a minimal example and e-mail it to the author of this package. Current contact details are available at \url{http://www.math.uni-bonn.de/people/muellner}. Please report situations where the algorithms produce arithmetic overflows. Also, the code is not really optimized for speed but for accuracy, so feel free to report a significant slowdown of the compiling process for your thesis/paper/book.
%
% \section{Usage}
%
% Simply load the \textsf{xypdf} package after the \Xy-pic package in your \LaTeX{} document.
% \begin{quote}
% "\usepackage"\oarg{options}"{xy}"\\
% "\usepackage{xypdf}"
% \end{quote}
% Do not use one of the driver options to \Xy-pic like \texttt{dvips}, as the \textsf{xypdf} package does an analogous job to the Postscript drivers, and combining two drivers will usually result in mutilated diagrams.
%
% The \textsf{xypdf} functionality can be switched off and on within the document by "\xypdfoff" and "\xypdfon".
%
% If \LaTeX{} complains "! No room for a new \dimen", try to load the \Xy-pic and \textsf{xypdf} packages as early as possible. \textsf{xypdf} assigns 20 new dimension registers which are released at the end of the initialization. Thus, it needs 20 free dimension registers but will effectively not occupy new dimension registers.
%
% \section{Acknowledgements}
%
% Since the \textsf{xypdf} package extends \Xy-pic, some ideas are adopted from this package and its Postscript backend, and the author gratefully acknowledges the service which Kristoffer H.\ Rose and Ross Moore did to the mathematical community with their original package.
%
% \section{To do}\label{sec:todo}
%
% \begin{itemize}
%
% \item
% Support for the “line styles”, “frame” and “color” extensions.
% \end{itemize}
%
% \section{The fine print: curves with multiple segments}\label{beziercont}
%
% Since the dashes in Bézier segments are aligned to the boundary points, this would result in dashes of double length when a curve is composed of several Bézier segments, as shown in the upper left diagram. To avoid this, \textsf{xypdf} records the end point of each segment and adapts the dash pattern whenever the starting point of a segment coincides with the end point of the previous one (see the upper right diagram). Analogous improvements apply to the “dotted” and “squiggled” line styles.
%
% Since this mechanism does not exist in the original \Xy-pic, it can be switched on and off by "\xypdfcontpatternon" and "\xypdfcontpatternoff". By default, it is switched on.
% \newcommand*\mydiag{{\xy(0,0);(50,0)**\crv{~**\dir{--}(10,0)&(20,15)&(30,15)&(40,0)}\endxy}}
% \begin{center}
% \begin{tabular}{@{}cc@{}}
% "\xypdfcontpatternoff"&"\xypdfcontpatternon" (default)\\
% \midrule
% \xypdfcontpatternoff\mydiag&\xypdfcontpatternon\mydiag\\[\bigskipamount]
% \multicolumn{2}{l}{\vbox{\normalbaselines%
% \hbox{code:}
% \vskip\jot
% \hbox{\texttt{\string\xy\space (0,0);(50,0)}}
% \hbox{\texttt{~~**\string\crv\{\textasciitilde**\string\dir\{-{}-\} (10,0)\&(20,15)\&(30,15)\&(40,0)\}}}
% \hbox{\texttt{\string\endxy}}
% }}\\[\bigskipamount]
% similar improvement: dotted curve&squiggled curve\\
% \midrule
% {\xy(0,0);(50,0)**\crv{~**\dir{.}(10,0)&(20,15)&(30,15)&(40,0)}\endxy}&
% {\xy(0,0);(50,0)**\crv{~**\dir{~}(10,0)&(20,15)&(30,15)&(40,0)}\endxy}
% \end{tabular}
% \end{center}
%
% \section{Troubleshooting}\label{sec:trouble}
%
% \begin{itemize}
% \item I get the error message \texttt{pdfTeX version 1.40.0 or higher is needed for the xypdf package with PDF output}
%
% You seem the use an old version of pdf\TeX{}. If you cannot update your \TeX{} system for some reason, you may still use the \textsf{xypdf} package in DVI mode and produce a PDF file via dvipdfm(x). The pathway \LaTeX${}\to{}$dvipdfm(x) is preferable in many cases anyway since it usually produces much smaller PDF files.
%
% \item I get the error message \texttt{eTeX is needed for the xypdf package}.
%
% In some \TeX{} installations, the $\varepsilon$-\TeX{} features are not enabled, although they most certainly can be in any reasonably modern \TeX{} installation. The picture is heterogeneous, e.\,g.\ the author's MiK\TeX{} and \TeX{} Live 2009 have the $\varepsilon$-\TeX{} features enabled without further ado, while another user reported the above error message in his \TeX{} Live 2009. Here is what you can do:
% 
% You must rebuild the (pdf-)\LaTeX{} format file with $\varepsilon$-\TeX{} enabled. If you are an expert, you may know how to do this anyway and may skip the following items. Otherwise, follow the instructions below for \TeX{} Live. For other \TeX{} distributions, please consult the respective documentation on how to build the format files.
% \begin{enumerate}
% \item Locate the file \textsf{fmtutil.cnf} (probably in \textsf{/texmf-var/web2c/}).
% \item Look at the lines starting with "latex" and "pdflatex". They probably end in "latex.ini" and "pdflatex.ini" \emph{without} a star "*" before these last parameters. If there is a star, the problem is somewhere else.
% \item Generate a new file \textsf{fmtutil-local.cnf} in \textsf{/texmf-local/web2c/} with the following content:
% \begin{quote}
% "#!latex"\\
% "latex pdftex" \meta{options} "*latex.ini"\\
% "#!pdflatex"\\
% "pdflatex pdftex" \meta{options} "*pdflatex.ini"
% \end{quote}
% Take the \meta{options} from the corresponding lines in \textsf{fmtutil.cnf}. The important change is the star prefix to the last parameters. This tells \TeX{} to go into extended ($\varepsilon$-\TeX{}) mode.
% \item Run "tlmgr generate fmtutil" to update the configuration file \textsf{fmtutil.cnf}.
% \item Run "fmtutil-sys --all" to generate the \TeX{} format files.
% \end{enumerate}
%
%
% \end{itemize}
%
% \section{Copyright, license and disclaimer}
%
% The copyright for the \textsf{xypdf} package is by its author, Daniel Müllner. Current contact details will be maintained at \url{http://www.math.uni-bonn.de/people/muellner}.
%
% The \textsf{xypdf} 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 3 of the License, or (at your option) any later version. This license is available at \url{http://www.gnu.org/licenses/}.
%
% This program 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.
%
% ^^A \StopEventually{\PrintIndex}
% \StopEventually{}
%
% \section{Implementation}
%
% Test whether the \Xy-pic package has been loaded properly.
%    \begin{macrocode}
\@ifpackageloaded{xy}\relax
  {\PackageError{xypdf}{Load the Xy-pic package before this package}
    {Insert `\string\usepackage[<options>]{xy}' before
    `\string\usepackage{xypdf}'}}
\xywithoption{ps}{%
  \PackageError{xypdf}{Do not load Xy-pic with a Postscript backend}{}%
}
%    \end{macrocode}
% Test for $\varepsilon$-\TeX
%    \begin{macrocode}
\ifx\unexpanded\@undefined
  \PackageError{xypdf}{eTeX is needed for the xypdf package}{}
\fi
%    \end{macrocode}
% Rely on the ifpdf package to test for PDF output.
%    \begin{macrocode}
\RequirePackage{ifpdf}
%    \end{macrocode}
% Test for "\pdfsave", which was introduced in pdf\TeX{} version 1.40.0.
%    \begin{macrocode}
\ifpdf
  \ifx\pdfsave\@undefined
    \PackageError{xypdf}{pdfTeX version 1.40.0 or higher is needed for the %
      xypdf^^J%
      package with PDF output}{}
  \fi
\fi
%    \end{macrocode}
% \begin{macro}{\xypdfon}
% \begin{macro}{\xypdfoff}
% \begin{macro}{\xP@hook}
% Commands for switching the extension on and off.
%    \begin{macrocode}
\newcommand*\xypdfon{}
\newcommand*\xypdfoff{}
\newcommand*\xP@hook[1]{%
  \edef\next@{%
    \let\expandafter\noexpand\csname xP@old@#1\endcsname
      \expandafter\noexpand\csname#1\endcsname}%
  \next@
  \edef\xypdfon{%
    \unexpanded\expandafter{\xypdfon}%
    \let\expandafter\noexpand\csname#1\endcsname
      \expandafter\noexpand\csname xP@#1\endcsname
  }%
  \edef\xypdfoff{%
    \unexpanded\expandafter{\xypdfoff}%
    \let\expandafter\noexpand\csname#1\endcsname
      \expandafter\noexpand\csname xP@old@#1\endcsname
  }%
}
\AtEndOfPackage{%
  \xypdfon
  \let\xP@hook\@undefined
  \let\xP@tempvar\@undefined
  \let\@tempa\@undefined
  \let\next@\undefined
  \let\xP@gobblepart\@undefined
  \let\xP@endgobble\@undefined
}
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
% \begin{macro}{\xP@literal}
% \begin{macro}{\xP@cm}
% Two possibilities to insert literal PDF commands, one for pdftex and one for dvipdfm(x). The command "\xP@cm" changes the current transformation matrix.
%    \begin{macrocode}
\ifpdf
  \newcommand*\xP@literal[1]{\pdfsave\pdfliteral{#1}\pdfrestore}
  \newcommand*\xP@cm[5]{%
    \pdfsave
    \pdfsetmatrix{#1 #2 #3 #4}%
    #5%
    \pdfrestore
  }
\else
  \newcommand*\xP@literal{%
    \PackageWarning{xypdf}{%
    The produced DVI file is NOT PORTABLE. Convert it with^^J%
    dvipdfm(x) to the PDF format but do not expect the DVI file itself to be^^J%
    displayed correctly\@gobble}%
    \global\let\xP@literal\xP@literal@
    \xP@literal
    }
  \newcommand*\xP@literal@[1]{\special{pdf:content #1}}
  \newcommand*\xP@cm[5]{%
    \special{pdf:btrans matrix #1 #2 #3 #4 0 0}%
    #5%
    \special{pdf:etrans}%
  }
\fi
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \begin{macro}{\xP@digits}
% Set the precision for dimension output according to pdf\TeX's "\pdfdecimaldigits". If this number is not defined, use dvipdfm's default precision, which is two decimals.
%    \begin{macrocode}
\ifx\pdfdecimaldigits\@undefined
  \newcommand*\xP@digits{2}
\else
  \@ifdefinable\xP@digits\relax
  \xdef\xP@digits{\the\pdfdecimaldigits}
  \ifnum\pdfdecimaldigits<2
    \PackageWarning{xypdf}{%
      The precision in \string\pdfdecimaldigits\space is only \xP@digits\space
      decimals.^^J%
      It is recommended to set \string\pdfdecimaldigits\space to 2 or 3 for %
      best output quality\@gobble}
  \fi
\fi
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\xP@dim}
% Conversion between \TeX{} points (pt) and PDF/Postscript points (bp)
%    \begin{macrocode}
\newcommand*\xP@dim[1]{%
  \expandafter\xP@removePT\the\dimexpr(#1)*800/803\relax\space}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\xP@precdim}
% Precise conversion between \TeX{} points (pt) and PDF/Postscript points (bp). No truncation.
%    \begin{macrocode}
\newcommand*\xP@precdim[1]{\xP@EARPT\dimexpr(#1)*800/803\relax\space}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\xP@EARPT}
%    \begin{macrocode}
\newcommand*\xP@EARPT{\expandafter\removePT@\the}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\xP@coor}
% Coordinates: two dimensions
%    \begin{macrocode}
\newcommand*\xP@coor[1]{\xP@dim{#1}\xP@dim}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\xP@removePT}
% The following two macros round and truncate a dimension to the desired number of decimal digits.
%    \begin{macrocode}
\@ifdefinable\xP@removePT\relax
{\catcode`\p=12\catcode`\t=12\gdef\xP@removePT#1pt{\xP@removePT@#10000@}}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\xP@removePT@}
%    \begin{macrocode}
\@ifdefinable\xP@removePT@\relax
\ifcase\xP@digits
%    \end{macrocode}
% 0 decimals
%    \begin{macrocode}
  \def\xP@removePT@#1.#2#3@{%
    \ifnum#2<5
      #1%
    \else
      \the\numexpr-\if-#1-\else-#1+\fi\@ne\relax
    \fi
  }
\or
%    \end{macrocode}
% 1 decimal
%    \begin{macrocode}
  \def\xP@removePT@#1#2.#3#4#5@{%
    \ifnum#4<5
      #1#2%
      \if#30%
      \else
        .#3%
      \fi
    \else
      \expandafter\xP@removePT
      \the\dimexpr#1#2.#3pt+\if#1--\fi.12pt\relax
    \fi
  }
\or
%    \end{macrocode}
% 2 decimals
%    \begin{macrocode}
  \def\xP@removePT@#1#2.#3#4#5#6@{%
    \ifnum#5<5
      #1#2%
      \if#40%
        \if#30%
        \else
          .#3%
        \fi
      \else
        .#3#4%
      \fi
    \else
      \expandafter\xP@removePT
      \the\dimexpr#1#2.#3#4pt+\if#1--\fi786sp\relax
    \fi
  }
\or
%    \end{macrocode}
% 3 decimals
%    \begin{macrocode}
  \def\xP@removePT@#1#2.#3#4#5#6#7@{%
    \ifnum#6<5
      #1#2%
      \if#50%
        \if#40%
          \if#30%
          \else
            .#3%
          \fi
        \else
          .#3#4%
        \fi
      \else
        .#3#4#5%
      \fi
    \else
      \expandafter\xP@removePT
      \the\dimexpr#1#2.#3#4#5pt+\if#1--\fi79sp\relax
    \fi
  }
\or
%    \end{macrocode}
% 4 decimals
%    \begin{macrocode}
  \def\xP@removePT@#1#2.#3#4#5#6#7#8@{%
    \ifnum#7<5
      #1#2%
      \if#60%
        \if#50%
          \if#40%
            \if#30%
            \else
              .#3%
            \fi
          \else
            .#3#4%
          \fi
        \else
          .#3#4#5%
        \fi
      \else
        .#3#4#5#6%
      \fi
    \else
      \expandafter\xP@removePT
      \the\dimexpr#1#2.#3#4#5#6pt+\if#1--\fi8sp\relax
    \fi
  }
\else
%    \end{macrocode}
% 5 or more decimals: no truncation
%    \begin{macrocode}
  \let\xP@dim\xP@precdim
\fi
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\xP@lw}
% \begin{macro}{\xP@preclw}
% Find out the default line width in the math fonts. This is done at the beginning of the document, when hopefully all potential changes to math fonts have taken place.
%    \begin{macrocode}
\AtBeginDocument{%
%    \end{macrocode}
% Initialize math fonts
%    \begin{macrocode}
  {\setbox0\hbox{$ $}}%
  \@ifdefinable\xP@lw\relax
  \@ifdefinable\xP@preclw\relax
  \edef\xP@preclw{\the\fontdimen8\textfont3}%
  \edef\xP@lw{\xP@dim\xP@preclw}%
  \PackageInfo{xypdf}{Line width: \xP@preclw}%
}
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \subsection{Straight lines}
%
% \begin{macro}{\line@}
% Also change the code for "\dir{-}" as an object. Now these dashes are not drawn from the dash font any more but by generic PDF line commands.
%    \begin{macrocode}
\xP@hook{line@}
\newcommand*\xP@line@{%
  \setboxz@h{%
    \xP@setsolidpat
    \xP@stroke{0 0 m \xP@coor{\cosDirection\xydashl@}{\sinDirection\xydashl@}l}%
  }%
  \U@c\sinDirection\xydashl@
  \D@c\z@
  \ifdim\U@c<\z@
    \multiply\U@c\m@ne
    \xP@swapdim\U@c\D@c
  \fi
  \ht\z@\U@c
  \dp\z@\D@c
  \R@c\cosDirection\xydashl@
  \L@c\z@
  \ifdim\R@c<\z@
    \multiply\R@c\m@ne
    \xP@swapdim\L@c\R@c
  \fi
  \hskip\L@c\box\z@\hskip\R@c
  \edef\tmp@{\egroup\U@c\the\U@c\D@c\the\D@c\L@c\the\L@c\R@c\the\R@c}%
  \tmp@
  \Edge@c={\rectangleEdge}%
  \edef\Upness@{\ifdim\z@<\U@c1\else0\fi}%
  \edef\Leftness@{\ifdim\z@<\L@c1\else0\fi}%
  \def\Drop@@{\styledboxz@}\def\Connect@@{\solid@}%
}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\solid@}
% \begin{macro}{\xP@solid@}
% This is the hook for solid straight lines. Derived from "\xyPSsolid@" in "xyps.tex".
%    \begin{macrocode}
\xP@hook{solid@}
\newcommand*\xP@solid@{\straight@\xP@solidSpread}
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \begin{macro}{\xP@solidSpread}
%    \begin{macrocode}
\@ifdefinable\xP@solidSpread\relax
\def\xP@solidSpread#1\repeat@{{%
%    \end{macrocode}
% Neglect zero-length lines.
%    \begin{macrocode}
  \@tempswatrue
  \ifdim\X@p=\X@c
  \ifdim\Y@p=\Y@c
    \@tempswafalse
  \fi
  \fi
  \if@tempswa
    \xP@setsolidpat
    \xP@stroke{\xP@coor\X@p\Y@p m \xP@coor\X@c\Y@c l}%
  \fi
}}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\xP@pattern}
%    \begin{macrocode}
\newcommand*\xP@pattern{}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\xP@setsolidpat}
% Pattern for solid lines
%    \begin{macrocode}
\newcommand*\xP@setsolidpat{%
  \def\xP@pattern{1 J 1 j []0 d}%
  \global\let\xP@lastpattern\xP@solidmacro
}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\xP@stroke}
%    \begin{macrocode}
\newcommand*\xP@stroke[1]{\xP@literal{\xP@lw w \xP@pattern\space#1 S}}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\dash@}
% \begin{macro}{\xP@dash@}
% This is the hook for dashed straight lines. Derived from "\xyPSdashed@" in "xyps.tex".
%    \begin{macrocode}
\xP@hook{dash@}
\newcommand\xP@dash@{\line@\def\Connect@@{\straight@\xP@dashedSpread}}
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \begin{macro}{\xP@dashedSpread}
%    \begin{macrocode}
\@ifdefinable\xP@dashedSpread\relax
\def\xP@dashedSpread#1\repeat@{{%
  \xP@veclen
%    \end{macrocode}
% Neglect zero-length lines.
%    \begin{macrocode}
  \ifdim\@tempdimb>\z@
    \xP@setdashpat
    \xP@savec
    \xP@stroke{\xP@coor\X@p\Y@p m \xP@coor\X@c\Y@c l}%
  \fi
}}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\xP@setdashpat}
% The formula for the dash length is the same as in the "dashed" operator in "xypsdict.tex":
% \[
% \textrm{(dash length)} = \frac l{2\cdot\mathop{\textrm{round}}\left(\frac{l+d}{2d}\right)-1},
% \]
% where $l$ is the length of the line and $d$ is the minimal dash length.
%
% The length $l$ must be in "\@tempdimb".
%    \begin{macrocode}
\newcommand*\xP@setdashpat{%
  \xP@testcont\xP@dashmacro
  \ifxP@splinecont
%    \end{macrocode}
% Special pattern in case this line continues another dashed segment.
%    \begin{macrocode}
    {\count@\numexpr2*((\@tempdimb-\xydashl@/3)/(2*\xydashl@))\relax
    \xdef\@gtempa{\ifnum\count@>\z@\xP@dim{\@tempdimb/\count@}\fi}%
    }%
    \edef\xP@pattern{1 J 1 j [\@gtempa]\ifx\@gtempa\empty0 \else\@gtempa\fi d}%
  \else
    \edef\xP@pattern{1 J 1 j [%
    \ifdim\@tempdimb>\xydashl@
      \xP@dim{\@tempdimb/(2*((\@tempdimb+\xydashl@)/(2*\xydashl@))-1)}%
    \fi
    ]0 d}%
  \fi
  \global\let\xP@lastpattern\xP@dashmacro
}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\point@}
% \begin{macro}{\xP@point@}
% This is the hook for points. Derived from "\xyPSpoint@" in "xyps.tex".
%    \begin{macrocode}
\xP@hook{point@}
\newcommand*\xP@point@{\xP@zerodot\egroup\Invisible@false
  \Hidden@false\def\Leftness@{.5}\def\U@pness@{.5}\ctipEdge@
  \def\Drop@@{\styledboxz@}%
  \def\Connect@@{\straight@\xP@dottedSpread}%
}
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \begin{macro}{\xP@zerodot}
%    \begin{macrocode}
\newcommand*\xP@zerodot{%
  \hb@xt@\z@{\hss
    \vbox to\z@{\vss\hrule\@width\xP@preclw\@height\xP@preclw\vss}%
  \hss}%
}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\xP@dottedSpread}
%    \begin{macrocode}
\@ifdefinable\xP@dottedSpread\relax
\def\xP@dottedSpread#1\repeat@{{%
  \xP@veclen
  \ifdim\@tempdimb>\z@
    \xP@setdottedpat
    \xP@savec
    \xP@stroke{\xP@coor\X@p\Y@p m \xP@coor\X@c\Y@c l}%
  \fi
}}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\xP@setdottedpat}
% The formula for the distance between dots is the same as in the "dotted" operator in "xypsdict.tex":
% \[
% \textrm{(dot distance)} = \frac l{\mathop{\textrm{round}}\left(\frac{l}{2\mathrm{pt}}\right)+1},
% \]
% where $l$ is the length of the line.
%
% The length $l$ must be in "\@tempdimb".
%    \begin{macrocode}
\newcommand*\xP@setdottedpat{%
  \xP@testcont\xP@dotmacro
  \ifxP@splinecont
    \@tempdima\dimexpr\@tempdimb/(\@tempdimb/131072+1)-\xP@preclw\relax
    \edef\xP@pattern{%
      0 J [%
%    \end{macrocode}
% Produce a dot pattern only when the segment is long enough.
%    \begin{macrocode}
      \ifdim\@tempdima>\z@
        \xP@precdim\xP@preclw\xP@precdim\@tempdima
      \fi
%    \end{macrocode}
% Advance the offset very slightly by 1sp to really hide the first dot in the viewer. (This improves the display at least in the author's PDF-Xchange viewer.)
%    \begin{macrocode}
      ]\xP@precdim{\xP@preclw+1sp}d}%
  \else
    \advance\@tempdimb-\xP@preclw
    \ifdim\@tempdimb<\z@\@tempdimb\z@\fi
    \@tempdima\dimexpr\@tempdimb/(\@tempdimb/131072+1)-\xP@preclw\relax
    \edef\xP@pattern{%
      0 J [%
%    \end{macrocode}
% Produce a dot pattern only when the segment is long enough.
%    \begin{macrocode}
      \ifdim\@tempdima>\z@
        \xP@lw\xP@dim\@tempdima
      \fi
      ]0 d}%
  \fi
  \global\let\xP@lastpattern\xP@dotmacro
}
%    \end{macrocode}
% \end{macro}
% In contrast to the Postscript drivers for \Xy-pic, where some computations are left to the Postscript code, all arithmetic for the PDF output must be done by \TeX{} itself. With \TeX's rudimentary fixed-point arithmetic, it is still a pain to compute even the length of a line segment, but things have become considerably easier with $\varepsilon$-\TeX.
% \begin{macro}{\xP@abs}
% Absolute value
%    \begin{macrocode}
\newcommand*\xP@abs[1]{\ifdim#1<\z@\multiply#1\m@ne\fi}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\xP@ifabsless}
%    \begin{macrocode}
\newcommand*\xP@ifabsless[2]{\ifpdfabsdim#1<#2}
\ifx\ifpdfabsdim\@undefined
  \renewcommand*\xP@ifabsless[2]{\ifdim\ifdim#1<\z@-\fi#1<\ifdim#2<\z@-\fi#2}
  \@gobble\fi
\fi
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\xP@swapdim}
% Works unless parameter "#2" is "\@tempdima".
%    \begin{macrocode}
\newcommand*\xP@swapdim[2]{\@tempdima#1#1#2#2\@tempdima}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\xP@swapnum}
% Works unless parameter "#2" is "\@tempcnta".
%    \begin{macrocode}
\newcommand*\xP@swapnum[2]{\@tempcnta#1#1#2#2\@tempcnta}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\xP@max}
% Maximum of two lengths
%    \begin{macrocode}
\newcommand*\xP@max[2]{\ifdim#1>#2#1\else#2\fi}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\xP@Max}
% Assigns "#1" the maximum of "#1" and the absolute value of "#2".
%    \begin{macrocode}
\newcommand*\xP@Max[2]{#1\ifdim#2<\z@\xP@max#1{-#2}\else\xP@max#1#2\fi}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\xP@sqrt}
% Square root algorithm. The argument is in "\@tempdima", and the start
% value for the iteration in "\@tempdimc". The result goes into "\@tempdimb".
%    \begin{macrocode}
\newcommand*\xP@sqrt{%
  \loop
    \@tempdimb\dimexpr(\@tempdimc+(\@tempdima*\p@/\@tempdimc))/2\relax
  \ifdim\@tempdimc=\@tempdimb\else
%    \end{macrocode}
% iterate: (old approx.) := (new approx.)
%    \begin{macrocode}
    \@tempdimc\@tempdimb\relax
  \repeat
}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\xP@veclen}
% Absolute length of the vector $("\d@X","\d@Y")$.
% The result goes into the register "\@tempdimb". Several \LaTeX{} registers are used as temporary registers, so this function is called safely within a group.
%
% (Maybe it is not necessary to scale the coordinates so much as it is done here, and a simpler code would be fine as well.)
%    \begin{macrocode}
\newcommand*\xP@veclen{{%
  \xP@veclen@
  \global\dimen@i\@tempdimb
  }\@tempdimb\dimen@i
}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\xP@veclen@}
%    \begin{macrocode}
\newcommand*\xP@veclen@{%
  \xP@abs\d@Y
%    \end{macrocode}
% 1) Strictly vertical vector
%    \begin{macrocode}
  \ifdim\d@X=\z@
    \@tempdimb\d@Y
  \else
    \xP@abs\d@X
%    \end{macrocode}
% 2) Strictly horizontal vector
%    \begin{macrocode}
    \ifdim\d@Y=\z@
      \@tempdimb\d@X
    \else
%    \end{macrocode}
% 3) Diagonal vector. $5931642\mathrm{sp}=\sqrt{"\maxdimen"/2}$. Test whether the components are small enough so that their sum of squares does not generate an arithmetic overflow.
%    \begin{macrocode}
      \@tempswatrue
      \ifdim\d@X>5931641sp\relax\@tempswafalse\fi
      \ifdim\d@Y>5931641sp\relax\@tempswafalse\fi
      \if@tempswa
%    \end{macrocode}
% 3a) Small vector. "\count@" contains a scaling factor for a precise fixed-point arithmetic.
%    \begin{macrocode}
        \count@\@ne
        \loop
          \@tempdima\dimexpr\d@X*\d@X/\p@+\d@Y*\d@Y/\p@\relax
%    \end{macrocode}
% If the coordinates are small enough, scale them up to improve precision.
%    \begin{macrocode}
        \ifdim\@tempdima<4096pt
          \@tempcnta\ifdim\@tempdima<1024pt\ifdim\@tempdima<256pt8\else4\fi%
            \else\tw@\fi
          \multiply\d@X\@tempcnta
          \multiply\d@Y\@tempcnta
          \multiply\count@\@tempcnta
        \repeat
%    \end{macrocode}
% Starting value for the square root algorithm
%    \begin{macrocode}
        \@tempdimc\dimexpr(\d@X+\d@Y)*3/4\relax
        \xP@sqrt
%    \end{macrocode}
% Rescale
%    \begin{macrocode}
        \@tempdimb\dimexpr\@tempdimb/\count@\relax
      \else
        \ifdim\d@X>83042982sp\relax\@tempswatrue\fi
        \ifdim\d@Y>83042982sp\relax\@tempswatrue\fi
        \if@tempswa
%    \end{macrocode}
% 3b) Large vector. Scale the coordinates down to avoid an overflow. $11927552\mathrm{sp}=182\mathrm{pt}$
%    \begin{macrocode}
          \@tempdima\dimexpr\d@X/182*\d@X/11927552+\d@Y/182*\d@Y/11927552\relax
          \@tempdimc\dimexpr(\d@X+\d@Y)*3/728\relax
          \xP@sqrt
          \multiply\@tempdimb182\relax
        \else
%    \end{macrocode}
% 3c) Medium vector. Also scale the coordinates down. $12845056\mathrm{sp}=196\mathrm{pt}=14^2\mathrm{pt}$
%    \begin{macrocode}
          \@tempdima\dimexpr\d@X*\d@X/12845056+\d@Y*\d@Y/12845056\relax
          \@tempdimc\dimexpr(\d@X+\d@Y)*3/56\relax
          \xP@sqrt
          \multiply\@tempdimb14\relax
        \fi
      \fi
    \fi
  \fi
}
%    \end{macrocode}
% \end{macro}
%
% \subsection{Squiggled lines}
%
% \begin{macro}{\squiggledSpread@}
% \begin{macro}{\xP@squiggledSpread@}
% This is the hook for squiggled straight lines.
%    \begin{macrocode}
\xP@hook{squiggledSpread@}
\@ifdefinable\xP@squiggledSpread@\relax
\def\xP@squiggledSpread@#1\repeat@{{%
  \xP@veclen
%    \end{macrocode}
% Neglect zero-length lines.
%    \begin{macrocode}
  \ifdim\@tempdimb>\z@
    \edef\@tempa{\xP@coor\X@p\Y@p m }%
    \toks@\expandafter{\@tempa}%
%    \end{macrocode}
% "\@tempcnta" = number of squiggles
%    \begin{macrocode}
    \@tempcnta\numexpr\@tempdimb/\xybsqll@\relax
    \ifnum\@tempcnta<\tw@\@tempcnta\tw@\fi
    \@tempdima\dimexpr\d@X/\@tempcnta\relax
    \@tempdimc\dimexpr\d@Y/\@tempcnta\relax
%    \end{macrocode}
% Reverse the direction of the little arcs, if the last squiggle from the previous segment makes it necessary.
%    \begin{macrocode}
    \xP@testcont\xP@oddsquigglemacro
    \ifxP@splinecont
      \def\xP@squigsign{-}%
    \else
      \let\xP@squigsign\empty
    \fi
    \count@\z@
    \loop
%    \end{macrocode}
% The fraction is the continuous fraction approximation for the best spline approximation to a quarter circle ($147546029/534618434\approx\frac12\cdot0.55196760761152504532$).
%    \begin{macrocode}
    \xP@append\toks@{%
      \xP@coor{\X@p+\d@X*\count@/\@tempcnta+(\@tempdima
        -\xP@squigsign\ifodd\count@-\fi\@tempdimc)*147546029/534618434}%
      {\Y@p+\d@Y*\count@/\@tempcnta+(\@tempdimc
        +\xP@squigsign\ifodd\count@-\fi\@tempdima)*147546029/534618434}%
    }%
    \advance\count@\@ne
    \xP@append\toks@{%
      \xP@coor{\X@p+\d@X*\count@/\@tempcnta-(\@tempdima
        -\xP@squigsign\ifodd\count@-\fi\@tempdimc)*147546029/534618434}%
      {\Y@p+\d@Y*\count@/\@tempcnta-(\@tempdimc
        +\xP@squigsign\ifodd\count@-\fi\@tempdima)*147546029/534618434}%
      \xP@coor{\X@p+\d@X*\count@/\@tempcnta}%
      {\Y@p+\d@Y*\count@/\@tempcnta}%
      c }%
    \ifnum\count@<\@tempcnta
    \repeat
    \xP@setsolidpat
%    \end{macrocode}
% Record the direction of the last squiggle.
%    \begin{macrocode}
    \global\expandafter\let\expandafter\xP@lastpattern
    \ifodd\numexpr\count@\if\xP@squigsign-+1\fi\relax
      \xP@oddsquigglemacro
    \else
      \xP@evensquigglemacro
    \fi
    \xP@savec
    \xP@stroke{\the\toks@}%
  \fi
}}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\xP@squigsign}
%    \begin{macrocode}
\newcommand*\xP@squigsign{}
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \begin{macro}{\xP@append}
%    \begin{macrocode}
\newcommand*\xP@append[2]{{%
  \edef\@tempa{#1{\the#1#2}}%
  \expandafter}\@tempa
}
%    \end{macrocode}
% \end{macro}
%
% \subsection{Circles}
%
% \begin{macro}{\circhar@@}
% \begin{macro}{\xP@circhar@@}
% Replacement macro for the circle chars.
%    \begin{macrocode}
\xP@hook{circhar@@}
\newcommand*\xP@circhar@@[1]{%
  \expandafter\xP@circhar@@@\ifcase#1 %
%    \end{macrocode}
% Bézier segments for 1/8 circle.
% Let
% \[\tabskip 0pt plus 1fil\openup\jot
% \halign to \displaywidth{$#$\hfill\cr
% \noalign{\vskip-\jot}
% a\coloneq\sqrt{1/2}\approx.707106781,\cr
% b\coloneq\frac83\sqrt2\cos(\pi/8)\left(1-\cos(\pi/8)\right)\approx.2652164898,\cr
% c\coloneq\frac13\left(-3+8\cos(\pi/8)-2\cos^2(\pi/8)\right)\approx.8946431596,\cr
% d\coloneq \frac12b(2+3\cos(\pi/8)-\cos^2(\pi/8))\approx.5195704027.\cr
% }
% \]
% (We have $\cos(\pi/8)=\frac12\sqrt{2+\sqrt2}$.)
%
% The fractions below are best possible rational approximations (obtained by continued fractions) to the following coordinates:
%
% $(0,0)$, $(0,-b)$, $(1-c, -d)$, $(1-a,a)$
%    \begin{macrocode}
    00%
    0{-173517671/654249180}%
    {65307479/619869377}{-34221476/65864945}%
    {225058681/768398401}{-543339720/768398401}%
  \or
%    \end{macrocode}
% $(0,-a)$, $(a-d,-c)$, $(a-b,-1)$, $(a,-1)$
%    \begin{macrocode}
    0{-543339720/768398401}%
    {181455824/967576667}{-554561898/619869377}%
    {826676217/1870772527}{-1}%
    {543339720/768398401}{-1}%
  \or
%    \end{macrocode}
% $(0,-1)$, $(b,-1)$, $(d,-c)$, $(a,-a)$
%    \begin{macrocode}
    0{-1}%
    {173517671/654249180}{-1}%
    {34221476/65864945}{-554561898/619869377}%
    {543339720/768398401}{-543339720/768398401}%
  \or
%    \end{macrocode}
% $(0,-a)$, $(c-a,-d)$, $(1-a,-b)$, $(1-a,0)$
%    \begin{macrocode}
    0{-543339720/768398401}%
    {181455824/967576667}{-34221476/65864945}%
    {225058681/768398401}{-173517671/654249180}%
    {225058681/768398401}0%
  \or
%    \end{macrocode}
% $(0,a)$, $(c-a,d)$, $(1-a,b)$, $(1-a,0)$
%    \begin{macrocode}
    0{543339720/768398401}%
    {181455824/967576667}{34221476/65864945}%
    {225058681/768398401}{173517671/654249180}%
    {225058681/768398401}0%
  \or
%    \end{macrocode}
% $(0,1)$, $(b,1)$, $(d,c)$, $(a,a)$
%    \begin{macrocode}
    01%
    {173517671/654249180}1%
    {34221476/65864945}{554561898/619869377}%
    {543339720/768398401}{543339720/768398401}%
  \or
%    \end{macrocode}
% $(0,a)$, $(a-d,c)$, $(a-b,1)$, $(a,1)$
%    \begin{macrocode}
    0{543339720/768398401}%
    {181455824/967576667}{554561898/619869377}%
    {826676217/1870772527}1%
    {543339720/768398401}1%
  \or
%    \end{macrocode}
% $(0,0)$, $(0,b)$, $(1-c,d)$, $(1-a,a)$
%    \begin{macrocode}
    00%
    0{173517671/654249180}%
    {65307479/619869377}{34221476/65864945}%
    {225058681/768398401}{543339720/768398401}%
  \fi}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\xP@circhar@@@}
% Draw the arc of $1/8$ circle and use the same space as the chars from the circle font do.
%    \begin{macrocode}
\newcommand\xP@circhar@@@[8]{%
  \xP@setsolidpat
  \xP@stroke{\xP@coor{\R@*#1}{\R@*#2}m
  \xP@coor{\R@*#3}{\R@*#4}\xP@coor{\R@*#5}{\R@*#6}%
  \xP@coor{\R@*#7}{\R@*#8}c}%
  \vrule width\z@ height\R@ depth\R@
  \kern\dimexpr\R@*#7\relax
}
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \begin{macro}{\cirrestrict@@}
% \begin{macro}{\xP@cirrestrict@@}
% Basically, "\cirrestrict@@" is turned into a no-op and does not change the radius.
%    \begin{macrocode}
\xP@hook{cirrestrict@@}
\newcommand*\xP@cirrestrict@@{\count@\z@\relax}
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \subsection{Optional code sections}
%
% \begin{macro}{\xP@optionalsection}
% \textbf{Important!} The next sections of the code are executed only if \Xy-pic is loaded with certain extensions. If the extension has not been loaded but is loaded afterwards (e.\,g.\ with "\xyoption{rotate}"), display an error message.
%    \begin{macrocode}
\newcommand*\xP@optionalsection[1]{%
  \expandafter\ifx\csname xy#1loaded\endcsname\relax
    \xywithoption{#1}{\xP@optionerror{#1}}%
    \expandafter\xP@gobblepart
  \else
    \message{`#1' extension support,}%
  \fi
}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\xP@optionerror}
%    \begin{macrocode}
\newcommand*\xP@optionerror[1]{%
  \PackageError{xypdf}{Load the Xy-pic "#1" option before the xypdf package}%
    {}%
}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\xP@gobblepart}
%    \begin{macrocode}
\@ifdefinable\xP@gobblepart\relax
\def\xP@gobblepart#1\xP@endgobble{}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\xP@endgobble}
%    \begin{macrocode}
\newcommand*\xP@endgobble{\relax}
%    \end{macrocode}
% \end{macro}
%
% \subsection{Rotation and scaling}
%
% Execute the following part only if \Xy-pic's “rotate” option was loaded.
%    \begin{macrocode}
\xP@optionalsection{rotate}
%    \end{macrocode}
% \begin{macro}{\xP@scale}
% Scale the box $0$ to the factors in "#1" and "#2".
%    \begin{macrocode}
\newcommand*\xP@scale[2]{%
  \setboxz@h{%
    \hskip\L@p
    \hskip-\R@p
    \lower\U@p\hbox{\xP@cm{#1}00{#2}%
      {\raise\U@p\hb@xt@\z@{\hskip-\L@p\boxz@\hss}}%
    }%
  }%
  \global\let\xP@lastpattern\empty
}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\xP@rotate}
% Rotation in the direction "#1".
%    \begin{macrocode}
\newcommand\xP@rotate{\xP@rotate@\xP@trigfromdir}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\xP@specialrotate}
% Rotation by the angle in "#1".
%    \begin{macrocode}
\@ifdefinable\xP@specialrotate\relax
\def\xP@specialrotate#1@@{\xP@rotate@\xP@trig{#1pt}}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\xP@rotate@}
% Common code for both rotations: rotate the box $0$.
%    \begin{macrocode}
\newcommand*\xP@rotate@[2]{%
  \setboxz@h{%
    #1{#2}%
    \hskip\L@p
    \hskip-\R@p
    \lower\U@p\hbox{\xP@cm\cosDirection\sinDirection
      {\if-\sinDirection\else-\sinDirection\fi}\cosDirection
      {\raise\U@p\hb@xt@\z@{\hskip-\L@p\boxz@\hss}}%
    }%
  }%
  \global\let\xP@lastpattern\empty
}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\xyRotate@@}
% The hooks for planting the code into \Xy-pic.
%    \begin{macrocode}
\CheckCommand*\xyRotate@@[1]{\xyundefinedRotate@{rotate}{#1}@@}
\let\xyRotate@@\xP@rotate
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\doSpecialRotate@@}
%    \begin{macrocode}
\def\@tempa#1@@{\xyundefinedRotate@{special rotate}{#1}@@}
\@check@eq\doSpecialRotate@@\@tempa
\let\doSpecialRotate@@\xP@specialrotate
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\xyscale@}
%    \begin{macrocode}
\CheckCommand*\xyscale@[2]{\xyundefinedRotate@{scale}{#1,#2}@@}
\let\xyscale@@\xP@scale
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\xP@trig}
% Calculate sine and cosine from the angle in "#1".
%    \begin{macrocode}
\newcommand*\xP@trig[1]{%
  \@tempdima\dimexpr#1\relax
%    \end{macrocode}
% Translate the argument into the interval $[0\mathrm{pt},360\mathrm{pt}]$.
%    \begin{macrocode}
  \@tempdimb\@tempdima
%    \end{macrocode}
% $23592960=360\cdot65536$
%    \begin{macrocode}
  \divide\@tempdimb23592960
  \advance\@tempdima-23592960\@tempdimb
  \ifdim\@tempdima<\z@\advance\@tempdima360pt\fi
  \@tempdimb\@tempdima
%    \end{macrocode}
% $5898240=90\cdot65536$
%    \begin{macrocode}
  \divide\@tempdimb5898240
%    \end{macrocode}
% It's enough to know sin between 0\textdegree{} and 90\textdegree{}. The cos and the values in the other quadrants can be derived from that.
%    \begin{macrocode}
  \ifcase\@tempdimb
    \xP@sinpoly
    \edef\sinDirection{\xP@EARPT\@tempdimb}%
    \@tempdima\dimexpr90pt-\@tempdima\relax
    \xP@sinpoly
    \edef\cosDirection{\xP@EARPT\@tempdimb}%
  \or
    \@tempdima\dimexpr180pt-\@tempdima\relax
    \xP@sinpoly
    \edef\sinDirection{\xP@EARPT\@tempdimb}%
    \@tempdima\dimexpr90pt-\@tempdima\relax
    \xP@sinpoly
    \edef\cosDirection{\xP@EARPT\dimexpr-\@tempdimb\relax}%
  \or
    \@tempdima\dimexpr\@tempdima-180pt\relax
    \xP@sinpoly
    \edef\sinDirection{\xP@EARPT\dimexpr-\@tempdimb\relax}%
    \@tempdima\dimexpr90pt-\@tempdima\relax
    \xP@sinpoly
    \edef\cosDirection{\xP@EARPT\dimexpr-\@tempdimb\relax}%
  \or
    \@tempdima\dimexpr360pt-\@tempdima\relax
    \xP@sinpoly
    \edef\sinDirection{\xP@EARPT\dimexpr-\@tempdimb\relax}%
    \@tempdima\dimexpr90pt-\@tempdima\relax
    \xP@sinpoly
    \edef\cosDirection{\xP@EARPT\@tempdimb}%
  \else
    \PackageError{xypdf}{Unexpected case in sin/cos calculation}%
      {Feel free to contact the author of the xypdf package with a minimal %
      example.}%
  \fi
}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\xP@sinpoly}
% Polynomial approximation to the sine in the interval $[0\mathrm{pt},90\mathrm{pt}]$. The deviation should be $\pm1\mathrm{sp}$ maximal (but no guarantee). (3rd order, 4 subintervals, exact values for 0pt and 90pt)
%    \begin{macrocode}
\newcommand*\xP@sinpoly{{%
  \ifdim\@tempdima<49pt
    \ifdim\@tempdima<27pt
      \@tempdimb\dimexpr((\@tempdima*-529771058/16039085-1384933sp)%
        *\@tempdima/268756075+10714164sp)*\@tempdima/613777813\relax
    \else
      \advance\@tempdima-27pt
      \@tempdimb\dimexpr(((\@tempdima*-743101305/20672414-238989613sp)%
        *\@tempdima/80975565+42661556sp)*\@tempdima/622461739+2\p@)%
        *157520747/693945047\relax
    \fi
  \else
    \ifdim\@tempdima<70pt
      \advance\@tempdima-49pt
      \@tempdimb\dimexpr(((\@tempdima*-348406699/107952940-55079229sp)%
        *\@tempdima/866635628+408805sp)*\@tempdima/26926757+\p@)%
        *135751711/179873976\relax
    \else
      \advance\@tempdima-70pt
      \@tempdimb\dimexpr(((\@tempdima*-1015850353/137849442-460519207sp)%
        *\@tempdima/8742349+142263941sp)*\@tempdima/972432199+23\p@)%
        *31253604/764969669\relax
    \fi
  \fi
  \global\dimen@i\@tempdimb
  }\@tempdimb\dimen@i
}
%    \end{macrocode}
% \end{macro}
%
% End of the section for \Xy-pic's “rotate” option. The macro "\xP@trigfromdir" below is also used for the "{-}" directional.
%    \begin{macrocode}
\xP@endgobble
%    \end{macrocode}
%
% \begin{macro}{\xP@trigfromdir}
% Calculate sine and cosine from the direction number in "#1".
%    \begin{macrocode}
\newcommand*\xP@trigfromdir[1]{{%
  \Direction#1\relax
%    \end{macrocode}
% "\Direction" mod 2048
%    \begin{macrocode}
  \count@-\Direction
  \advance\count@4096
  \divide\count@2048
%    \end{macrocode}
% Assign the slope in the right way.
%    \begin{macrocode}
  \ifcase\count@
    \d@X\K@\p@
    \d@Y\numexpr\Direction-3*\K@\relax\p@
  \or
    \d@X\numexpr\Direction-\K@\relax\p@
    \d@Y-\K@\p@
  \or
    \d@X-\K@\p@
    \d@Y\numexpr-\Direction-\K@\relax\p@
  \or
    \d@X\numexpr-\Direction-3*\K@\relax\p@
    \d@Y\K@\p@
  \else
    \PackageError{xypdf}{Unexpected case in direction calculation}%
      {Feel free to contact the author of the xypdf package with a minimal %
      example.}%
  \fi
%    \end{macrocode}
% Bring the pair $("\d@X","\d@Y")$ to norm 1.
%    \begin{macrocode}
  \xP@veclen
  \xdef\@gtempa{%
    \def\noexpand\cosDirection{\xP@EARPT\dimexpr\d@X*\p@/\@tempdimb\relax}%
    \def\noexpand\sinDirection{\xP@EARPT\dimexpr\d@Y*\p@/\@tempdimb\relax}%
  }%
  }\@gtempa
}
%    \end{macrocode}
% \end{macro}
%
% \subsection{Temporary registers}
%
% The next section is for the “curve” extension!
%    \begin{macrocode}
\xP@optionalsection{curve}
%    \end{macrocode}
% In order to save registers, \textsf{xypdf} shares \Xy-pic's dimension and counter registers but uses different, more descriptive names. Every macro that uses these temporary variables must be safely encapsulated in a group so that the registers are not changed from the outside scope!
%
% The \textsf{xypdf} package uses several sets of temporary variable names for different modules. Since it is important that these assignments do not overlap and that the variables are only used encapsulated within groups, the macros which use temporary variables are marked by colored bullets \BulletA, \BulletB, \BulletC, \BulletD, \BulletE, \BulletF, \BulletG\  with one color for each set of variables.
%
% The table in \autoref{Fig3} lists all variable assignments in these sets. It can be seen from the table which sets of variables can be used together. For example, set \BulletA\ consisting of "\xP@bigdim" can be used together with all other temporary variables, while \BulletB\ and \BulletD\ must never be used together.
% \begin{figure}\label{Fig3}
% \centering
% \begin{tabular*}{\textwidth}{@{}l@{\extracolsep{\fill}}%
% >{\color{varcolA}}l<{\hskip-3em}@{\extracolsep{\fill}}%
% >{\color{varcolB}}l@{\extracolsep{\fill}}%
% >{\color{varcolC}}l<{\hskip-4em}@{\extracolsep{\fill}}%
% >{\color{varcolD}}l<{\hskip-.5em}@{\extracolsep{\fill}}%
% >{\color{varcolE}}l<{\hskip-.5em}@{\extracolsep{\fill}}%
% >{\color{varcolF}}l<{\hskip-2.5em}@{\extracolsep{\fill}}%
% >{\color{varcolG}}l@{}}
% \Xy-pic var.&Set 1   &~~~Set 2   &Set 3   &~~~Set 4   &Set 5   &Set 6   &~~~Set 7\\
% \midrule
% "\quotPTK@"&"\xP@bigdim"                                                     \\
% "\L@p"     &&"\xP@parA"      &"\xP@A"          & &("\L@p")  & &("\L@p")      \\
% "\U@p"     &&"\xP@velA"      &"\xP@B"          & &("\U@p")  & &("\U@p")      \\
% "\R@p"     &&"\xP@parB"      &"\xP@C"          & &("\R@p")  & &("\R@p")      \\
% "\D@p"     &&"\xP@velB"      &"\xP@D"          & &("\D@p")  & &("\D@p")      \\
% "\X@origin"&&"\xP@parC"      &"\xP@E"          & &          & &"\xP@temppar" \\
% "\Y@origin"&&"\xP@velC"      &"\xP@F"          & &          & &"\xP@tempvel" \\
% "\X@xbase" &&"\xP@parD"      &"\xP@G"          & &          & &"\xP@posX"    \\
% "\Y@xbase" &&"\xP@velD"      &"\xP@H"          & &          & &"\xP@posY"    \\
% "\X@ybase" &&"\xP@parE"      &$"\xP@I"="\xP@a"$& &"\xP@a"   & &"\xP@oldpar"  \\
% "\Y@ybase" &&"\xP@velE"      &$"\xP@J"="\xP@b"$& &"\xP@b"   & &"\xP@lastpar" \\
% "\X@min"   &&"\xP@lenA"      &"\xP@K"          & &"\xP@c"   & &"\xP@tempvel@"\\
% "\Y@min"   &&"\xP@lenB"      &"\xP@L"          & &"\xP@valA"& &"\xP@parinc"  \\
% "\X@max"   &&"\xP@partlen"   &"\xP@fa"         & &"\xP@valB"                 \\
% "\Y@max"   &&"\xP@oldpartlen"&"\xP@fd"         & &"\xP@devA"                 \\
% "\almostz@"&&"\xP@tolerance" &"\xP@tm"         & &"\xP@devB"& &"\xP@squiglen"\\
% "\K@dXdY"  &&                &"\xP@xm"         & &"\xP@ti"                   \\
% "\K@dYdX"  &&                &"\xP@ym"         & &"\xP@tip"                  \\
% new var.~1 &&                &"\xP@off        "& &("\xP@off")                \\
% new var.~2 &&                &"\xP@ta"         &                             \\
% new var.~3 &&                &"\xP@tb"         &                             \\
% new var.~4 &&                &"\xP@tc"         &                             \\
% new var.~5 &&                &"\xP@M"          &                             \\
% new var.~6 &&                &"\xP@oldobj"     &                             \\
% new var.~7 &&                & &"\xP@Tax"      &          &"\xP@sa"          \\
% new var.~8 &&                & &"\xP@Tay"      &          &"\xP@sb"          \\
% new var.~9 &&                & &"\xP@Tdx"      &          &"\xP@sc"          \\
% new var.~10&&                & &"\xP@Tdy"      &          &"\xP@Ab"          \\
% new var.~11&&                & &"\xP@Tmx"      &          &"\xP@AAb"         \\
% new var.~12&&                & &"\xP@Tmy"      &          &"\xP@Aba"         \\
% new var.~13&&                & &"\xP@xa"       &("\xP@xa")&"\xP@Abb"         \\
% new var.~14&&                & &"\xP@ya"       &("\xP@ya")&"\xP@Abc"         \\
% new var.~15&&                & &"\xP@xb"       &("\xP@xb")&"\xP@AAba"        \\
% new var.~16&&                & &"\xP@yb"       &("\xP@yb")&"\xP@AAbb"        \\
% new var.~17&&                & &"\xP@xc"       &("\xP@xc")&"\xP@AAbc"        \\
% new var.~18&&                & &"\xP@yc"       &("\xP@yc")&"\xP@dta"         \\
% new var.~19&&                & &"\xP@xd"       &("\xP@xd")&"\xP@dtb"         \\
% new var.~20&&                & &"\xP@yd"       &("\xP@yd")&"\xP@dtc"         \\
% \end{tabular*}
% \caption{Temporary dimension registers in \textsf{xypdf}.}
% \end{figure}
%
% \begin{macro}{\xP@tempvar}
%    \begin{macrocode}
\newcommand*\xP@tempvar[2]{%
  \@ifdefinable#1\relax
  \let#1#2%
}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\xP@bigdim}
% \BulletA\ A big constant less than $\frac13"\maxdimen"\approx5461\mathrm{pt}$ and having many small prime factors.
%    \begin{macrocode}
\xP@tempvar\xP@bigdim\quotPTK@
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\xP@parA}
% \begin{macro}{\xP@velA}
% \begin{macro}{\xP@parB}
% \begin{macro}{\xP@velB}
% \begin{macro}{\xP@parC}
% \begin{macro}{\xP@velC}
% \begin{macro}{\xP@parD}
% \begin{macro}{\xP@velD}
% \begin{macro}{\xP@parE}
% \begin{macro}{\xP@velE}
% \begin{macro}{\xP@lenA}
% \begin{macro}{\xP@lenB}
% \begin{macro}{\xP@partlen}
% \begin{macro}{\xP@oldpartlen}
% \begin{macro}{\xP@tolerance}
% \BulletB\ Second set of temporary variables: for the arc length algorithm.
%    \begin{macrocode}
\xP@tempvar\xP@parA\L@p
\xP@tempvar\xP@velA\U@p
\xP@tempvar\xP@parB\R@p
\xP@tempvar\xP@velB\D@p
\xP@tempvar\xP@parC\X@origin
\xP@tempvar\xP@velC\Y@origin
\xP@tempvar\xP@parD\X@xbase
\xP@tempvar\xP@velD\Y@xbase
\xP@tempvar\xP@parE\X@ybase
\xP@tempvar\xP@velE\Y@ybase
\xP@tempvar\xP@lenA\X@min
\xP@tempvar\xP@lenB\Y@min
\xP@tempvar\xP@partlen\X@max
\xP@tempvar\xP@oldpartlen\Y@max
\xP@tempvar\xP@tolerance\almostz@
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \begin{macro}{\xP@A}
% \begin{macro}{\xP@B}
% \begin{macro}{\xP@C}
% \begin{macro}{\xP@D}
% \begin{macro}{\xP@E}
% \begin{macro}{\xP@F}
% \begin{macro}{\xP@G}
% \begin{macro}{\xP@H}
% \begin{macro}{\xP@I}
% \begin{macro}{\xP@J}
% \begin{macro}{\xP@K}
% \begin{macro}{\xP@L}
% \begin{macro}{\xP@fa}
% \begin{macro}{\xP@fd}
% \begin{macro}{\xP@tm}
% \begin{macro}{\xP@xm}
% \begin{macro}{\xP@ym}
% \BulletC\
% Third set of temporary registers: Bézier offset algorithm ans solving linear equations.
%    \begin{macrocode}
\xP@tempvar\xP@A\L@p
\xP@tempvar\xP@B\U@p
\xP@tempvar\xP@C\R@p
\xP@tempvar\xP@D\D@p
\xP@tempvar\xP@E\X@origin
\xP@tempvar\xP@F\Y@origin
\xP@tempvar\xP@G\X@xbase
\xP@tempvar\xP@H\Y@xbase
\xP@tempvar\xP@I\X@ybase
\xP@tempvar\xP@J\Y@ybase
\xP@tempvar\xP@K\X@min
\xP@tempvar\xP@L\Y@min
\xP@tempvar\xP@fa\X@max
\xP@tempvar\xP@fd\Y@max
\xP@tempvar\xP@tm\almostz@
\xP@tempvar\xP@xm\K@dXdY
\xP@tempvar\xP@ym\K@dYdX
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \begin{macro}{\xP@off}
% \begin{macro}{\xP@ta}
% \begin{macro}{\xP@tb}
% \begin{macro}{\xP@tc}
% \begin{macro}{\xP@M}
% \begin{macro}{\xP@oldobj}
% \begin{macro}{\xP@Tax}
% \begin{macro}{\xP@Tay}
% \BulletC\
% Alas, we need 20 more temporary registers. Hopefully, there are still free slots for dimension registers. We take them for the temporary variables but release them afterwards so that other packages can use them.
%    \begin{macrocode}
\@tempcnta\count11\relax
\newdimen\xP@off
\newdimen\xP@ta
\newdimen\xP@tb
\newdimen\xP@tc
\newdimen\xP@M
\newdimen\xP@oldobj
\newdimen\xP@Tax
\newdimen\xP@Tay
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \begin{macro}{\xP@Tdx}
% \begin{macro}{\xP@Tdy}
% \begin{macro}{\xP@Tmx}
% \begin{macro}{\xP@Tmy}
% \begin{macro}{\xP@xa}
% \begin{macro}{\xP@ya}
% \begin{macro}{\xP@xb}
% \begin{macro}{\xP@yb}
% \begin{macro}{\xP@xc}
% \begin{macro}{\xP@yc}
% \begin{macro}{\xP@xd}
% \begin{macro}{\xP@yd}
% \BulletC
%    \begin{macrocode}
\newdimen\xP@Tdx
\newdimen\xP@Tdy
\newdimen\xP@Tmx
\newdimen\xP@Tmy
\newdimen\xP@xa
\newdimen\xP@ya
\newdimen\xP@xb
\newdimen\xP@yb
\newdimen\xP@xc
\newdimen\xP@yc
\newdimen\xP@xd
\newdimen\xP@yd
\count11\@tempcnta
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \begin{macro}{\xP@a}
% \begin{macro}{\xP@b}
% \begin{macro}{\xP@c}
% \begin{macro}{\xP@valA}
% \begin{macro}{\xP@valB}
% \begin{macro}{\xP@devA}
% \begin{macro}{\xP@devB}
% \begin{macro}{\xP@ti}
% \begin{macro}{\xP@tip}
% \BulletE\ Fifth set of temporary variables: Parameters for drawing part of a spline segment.
%    \begin{macrocode}
\xP@tempvar\xP@a\X@ybase
\xP@tempvar\xP@b\Y@ybase
\xP@tempvar\xP@c\X@min
\xP@tempvar\xP@valA\Y@min
\xP@tempvar\xP@valB\X@max
\xP@tempvar\xP@devA\Y@max
\xP@tempvar\xP@devB\almostz@
\xP@tempvar\xP@ti\K@dXdY
\xP@tempvar\xP@tip\K@dYdX
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \begin{macro}{\xP@sa}
% \begin{macro}{\xP@sb}
% \begin{macro}{\xP@sc}
% \begin{macro}{\xP@Ab}
% \begin{macro}{\xP@AAb}
% \begin{macro}{\xP@Aba}
% \begin{macro}{\xP@Abb}
% \begin{macro}{\xP@Abc}
% \begin{macro}{\xP@AAba}
% \begin{macro}{\xP@AAbb}
% \begin{macro}{\xP@AAbc}
% \begin{macro}{\xP@dta}
% \begin{macro}{\xP@dtb}
% \begin{macro}{\xP@dtc}
% \BulletF\
% Sixth set of temporary variables: Solving a linear system approximately.\nopagebreak
%    \begin{macrocode}
\xP@tempvar\xP@sa\xP@Tax
\xP@tempvar\xP@sb\xP@Tay
\xP@tempvar\xP@sc\xP@Tdx
\xP@tempvar\xP@Ab\xP@Tdy
\xP@tempvar\xP@AAb\xP@Tmx
\xP@tempvar\xP@Aba\xP@Tmy
\xP@tempvar\xP@Abb\xP@xa
\xP@tempvar\xP@Abc\xP@ya
\xP@tempvar\xP@AAba\xP@xb
\xP@tempvar\xP@AAbb\xP@yb
\xP@tempvar\xP@AAbc\xP@xc
\xP@tempvar\xP@dta\xP@yc
\xP@tempvar\xP@dtb\xP@xd
\xP@tempvar\xP@dtc\xP@yd
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \begin{macro}{\xP@temppar}
% \begin{macro}{\xP@tempvel}
% \begin{macro}{\xP@posX}
% \begin{macro}{\xP@posY}
% \begin{macro}{\xP@oldpar}
% \begin{macro}{\xP@lastpar}
% \begin{macro}{\xP@tempvel@}
% \begin{macro}{\xP@parinc}
% \begin{macro}{\xP@squiglen}
% \BulletG\
% Seventh set of temporary registers: For multiple dotted splines.
%    \begin{macrocode}
\xP@tempvar\xP@temppar\X@origin
\xP@tempvar\xP@tempvel\Y@origin
\xP@tempvar\xP@posX\X@xbase
\xP@tempvar\xP@posY\Y@xbase
\xP@tempvar\xP@oldpar\X@ybase
\xP@tempvar\xP@lastpar\Y@ybase
\xP@tempvar\xP@tempvel@\X@min
\xP@tempvar\xP@parinc\Y@min
\xP@tempvar\xP@squiglen\almostz@
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \begin{macro}{\xP@scaleone}
% \begin{macro}{\xP@scaletwo}
% \begin{macro}{\xP@scalethree}
% We also use temporary numerical registers for scaling factors in "\xP@solvelinearsystem".
%    \begin{macrocode}
\xP@tempvar\xP@scaleone\K@
\xP@tempvar\xP@scaletwo\KK@
\xP@tempvar\xP@scalethree\Direction
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \subsection{Bézier curves}
%
% \begin{macro}{\splinesolid@}
% \begin{macro}{\splinedashed@}
% \begin{macro}{\splinedotted@}
% These are the hooks for single-stroke splines (solid, dashed and dotted).
%    \begin{macrocode}
\xP@hook{splinesolid@}
\newcommand*\xP@splinesolid@{\xP@spline\xP@setsolidpat}
\xP@hook{splinedashed@}
\newcommand*\xP@splinedashed@{\xP@spline\xP@setdashpat}
\xP@hook{splinedotted@}
\newcommand*\xP@splinedotted@{\xP@spline\xP@setdottedpat}
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
% \begin{macro}{\xP@spline}
% Output a spline segment. Parameter: Macro for the dash pattern generation.
%    \begin{macrocode}
\newcommand*\xP@spline[1]{%
  \readsplineparams@
%    \end{macrocode}
% Neglect splines which are drawn “backwards”. Somehow \Xy-pic draws curves forward and backward, but we need it to be drawn only once.
%    \begin{macrocode}
  \ifdim\dimen5<\dimen7
    \xP@preparespline
%    \end{macrocode}
% Neglect splines of length zero.
%    \begin{macrocode}
    \ifdim\@tempdimb>\z@
%    \end{macrocode}
% Set the dash pattern.
%    \begin{macrocode}
      #1%
%    \end{macrocode}
% Draw the spline.
%    \begin{macrocode}
      \xP@stroke{\xP@coor\X@p\Y@p m %
        \xP@coor\L@c\U@c\xP@coor\R@c\D@c\xP@coor\X@c\Y@c c}%
%    \end{macrocode}
% Record the end point for pattern continuation.
%    \begin{macrocode}
        \xP@savec
    \fi
  \fi
}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\xP@preparespline}
%    \begin{macrocode}
\newcommand*\xP@preparespline{%
%    \end{macrocode}
% If we have a quadratic Bézier segment, convert it to a cubic one.
%    \begin{macrocode}
    \ifx\splineinfo@\squineinfo@
      \L@c\dimexpr(\X@p+2\A@)/3\relax
      \U@c\dimexpr(\Y@p+2\B@)/3\relax
      \R@c\dimexpr(\X@c+2\A@)/3\relax
      \D@c\dimexpr(\Y@c+2\B@)/3\relax
    \fi
%    \end{macrocode}
% Cut the spline according to that start and end parameters in "\dimen5" and "\dimen7".
%    \begin{macrocode}
    \xP@shavespline
%    \end{macrocode}
% Determine the spline length (for the pattern generation; unnecessary for solid splines).
%    \begin{macrocode}
    \xP@bezierlength
}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\xP@inibigdim}
% \BulletA\
% Initialize "\xP@bigdim" every time a macro that uses this register is called. See e.\,g.\ "\xP@shaveprec".
%    \begin{macrocode}
\newcommand*\xP@inibigdim{\xP@bigdim5040pt}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\xP@shavespline}
% Shave a cubic spline at both ends at the parameter values in "\dimen5" and "\dimen7". For normal use, the parameters fulfill $0\mathrm{pt}\leq"\dimen5"<"\dimen7"\leq1\mathrm{pt}$.
%
% (Note that "\xP@bigdim" only occurs in the arguments to "\xP@shaveprec", so this use is safe.)
%    \begin{macrocode}
\newcommand*\xP@shavespline{%
  \xP@shaveprec{\dimen5*\xP@bigdim/\p@}{\dimen7*\xP@bigdim/\p@}%
}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\xP@shaveprec}
% \BulletA\ Shave a cubic spline at both ends at the parameter values in "#1" and "#2". For normal use, the parameters fulfill $0\mathrm{pt}\leq"#1"<"#2"\leq"\xP@bigdim"$. The control points for the cubic Bézier curve are ("\X@p","\Y@p"), ("\L@c","\U@c"), ("\R@c","\D@c"), ("\X@c","\Y@c"). The \Xy-pic registers "\A@", "\B@", "\L@p", "\U@p", "\R@p", "\D@p", "\X@min" and "\Y@min" are used as temporary registers, but safely encapsulated in a group.
%    \begin{macrocode}
\newcommand*\xP@shaveprec[2]{{%
  \xP@inibigdim
  \A@\dimexpr#1\relax
  \B@\dimexpr#2\relax
%    \end{macrocode}
% Shortcut in case the spline is not changed.
%    \begin{macrocode}
  \@tempswatrue
  \ifdim\A@=\z@\ifdim\B@=\xP@bigdim\@tempswafalse\fi\fi
  \if@tempswa
    \L@p\dimexpr\L@c-\X@p\relax
    \U@p\dimexpr\R@c-\L@p-\L@c\relax
    \R@p\dimexpr\X@c-3\R@c+3\L@c-\X@p\relax
    \D@p\dimexpr\U@c-\Y@p\relax
    \X@min\dimexpr\D@c-\D@p-\U@c\relax
    \Y@min\dimexpr\Y@c-3\D@c+3\U@c-\Y@p\relax
    \xdef\@gtempa{%
      \X@p\the\dimexpr\X@p+(3\L@p+(3\U@p+\R@p*\A@/\xP@bigdim)%
        *\A@/\xP@bigdim)*\A@/\xP@bigdim\relax
      \Y@p\the\dimexpr\Y@p+(3\D@p+(3\X@min+\Y@min*\A@/\xP@bigdim)%
        *\A@/\xP@bigdim)*\A@/\xP@bigdim\relax
      \L@c\the\dimexpr\X@p+(2\A@+\B@)*\L@p/\xP@bigdim+((\A@+2\B@)%
        *\U@p/\xP@bigdim+\R@p*\A@/\xP@bigdim*\B@/\xP@bigdim)%
        *\A@/\xP@bigdim\relax
      \U@c\the\dimexpr\Y@p+(2\A@+\B@)*\D@p/\xP@bigdim+((\A@+2\B@)%
        *\X@min/\xP@bigdim+\Y@min*\A@/\xP@bigdim*\B@/\xP@bigdim)%
        *\A@/\xP@bigdim\relax
      \R@c\the\dimexpr\X@p+(2\B@+\A@)*\L@p/\xP@bigdim+((\B@+2\A@)%
        *\U@p/\xP@bigdim+\R@p*\B@/\xP@bigdim*\A@/\xP@bigdim)%
        *\B@/\xP@bigdim\relax
      \D@c\the\dimexpr\Y@p+(2\B@+\A@)*\D@p/\xP@bigdim+((\B@+2\A@)%
        *\X@min/\xP@bigdim+\Y@min*\B@/\xP@bigdim*\A@/\xP@bigdim)%
        *\B@/\xP@bigdim\relax
      \X@c\the\dimexpr\X@p+(3\L@p+(3\U@p+\R@p*\B@/\xP@bigdim)%
        *\B@/\xP@bigdim)*\B@/\xP@bigdim\relax
      \Y@c\the\dimexpr\Y@p+(3\D@p+(3\X@min+\Y@min*\B@/\xP@bigdim)%
        *\B@/\xP@bigdim)*\B@/\xP@bigdim\relax}%
  \else
    \global\let\@gtempa\relax
  \fi
  }\@gtempa
}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\xP@bezierlength}
% \BulletA\ \BulletB\
% Compute the arc length of a cubic Bézier segment.
%
% The following algorithm is used: The velocity for a partial segment is fitted at
% three points (A-C-E) by a quadratic function, and the arc length is approximated by the
% integral over this quadratic function.
%
% Each interval is recursively divided in halves (A-B-C, C-D-E) as long as the result for the
% arc length changes
% more than the precision parameter "\xP@tolerance". If the desired precision is reached,
% the arc length in the small interval is added to the total arc length,
% and the next interval is considered.
%
% The result goes into "\@tempdimb".
%    \begin{macrocode}
\newcommand*\xP@bezierlength{{%
  \xP@inibigdim
  \@tempdimb\z@
  \xP@parA\z@
  \xP@velocity\z@\xP@velA
  \xP@parC.5\xP@bigdim
  \xP@velocity\xP@parC\xP@velC
  \xP@velocity\xP@bigdim\xP@velE
%    \end{macrocode}
% Arc length (integral over the quadratic approximation)
%    \begin{macrocode}
  \xP@oldpartlen\dimexpr(\xP@velA+4\xP@velC+\xP@velE)/6\relax
%    \end{macrocode}
% Tolerance parameter: It is set to $1/100000$ of the approximate arc length, but at least $1\mathrm{sp}$.
%    \begin{macrocode}
  \xP@tolerance\xP@max{1sp}{\dimexpr\xP@oldpartlen/100000\relax}%
%    \end{macrocode}
% Initiate the recursive algorithm with the interval $[0, 1]$.
%    \begin{macrocode}
  \xP@arclength\xP@parC\xP@velC\xP@bigdim\xP@velE\xP@oldpartlen
%    \end{macrocode}
% Pass the result to outside the group.
%    \begin{macrocode}
  \global\dimen@i\@tempdimb
  }\@tempdimb\dimen@i
}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\xP@velocity}
% \BulletA\
% Compute the velocity at the point "#1" on a cubic Bézier curve.
% Needs: Bézier control points "\X@p",\ldots,"\Y@c".
% Parameter "#2": dimension register for the result.
% Temporary: "\L@p", "\U@p", "\d@X", "\d@Y".
%    \begin{macrocode}
\newcommand*\xP@velocity[2]{{%
  \@tempdima\dimexpr#1\relax
  \xP@tangent
  \global\dimen@i\@tempdimb
  }#2\dimen@i
}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\xP@tangent}
% \BulletA\
%    \begin{macrocode}
\newcommand*\xP@tangent{%
  \d@X3\xP@precbeziertan\X@p\L@c\R@c\X@c\@tempdima
  \d@Y3\xP@precbeziertan\Y@p\U@c\D@c\Y@c\@tempdima
  \xP@veclen
}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\xP@tangentvec}
% \BulletA\
% Tangent vector on a Bézier curve. Parameter "#1": Parameter on the segment.
% Needs: Bézier parameters "\X@p",\ldots,"\Y@c". Returns: vector in $("\d@X","\d@Y")$, norm in "\@tempdimb".
%    \begin{macrocode}
\newcommand*\xP@tangentvec[1]{{%
    \@tempdima#1\relax
    \xP@tangent
%    \end{macrocode}
% If the velocity is zero at some point, take the second derivative for the tangent vector.
%    \begin{macrocode}
    \ifdim\@tempdimb=\z@
      \L@p\dimexpr\X@c-\X@p+(\L@c-\R@c)*3\relax
      \U@p\dimexpr\Y@c-\Y@p+(\U@c-\D@c)*3\relax
      \d@X\dimexpr\L@p*\@tempdima/\xP@bigdim+(\X@p-2\L@c+\R@c)\relax
      \d@Y\dimexpr\U@p*\@tempdima/\xP@bigdim+(\Y@p-2\U@c+\D@c)\relax
      \xP@veclen
%    \end{macrocode}
% Or even the third derivative.
%    \begin{macrocode}
      \ifdim\@tempdimb=\z@
        \d@X\L@p
        \d@Y\U@p
        \xP@veclen
        \ifdim\@tempdimb=\z@
          \PackageWarning{xypdf}{Cannot determine a tangent vector to a curve}%
          \@tempdimb\p@
        \fi
      \fi
    \fi
    \global\dimen@i\d@X
    \global\dimen3\d@Y
    \global\dimen5\@tempdimb
  }%
  \d@X\dimen@i
  \d@Y\dimen3\relax
  \@tempdimb\dimen5\relax
}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\xP@arclength}
% \BulletB\
% The recursive step for the arc length computation.\newline
% Needs: "\xP@tolerance", "\xP@parA", "\xP@velA". Parameter: "#1" is the middle parameter, "#2" the velocity at "#1", "#3" the third parameter, "#4" the velocity at "#3", "#5" the approximate arc length in the interval from "\xP@parA" to "#3".
%    \begin{macrocode}
\newcommand*\xP@arclength[5]{%
  \xP@parE#3%
  \xP@velE#4%
  \xP@parC#1%
  \xP@velC#2%
  \xP@oldpartlen#5%
%    \end{macrocode}
% Compute two more pairs (parameter, velocity) at positions $\frac14$ and $\frac34$
% of the interval.
%    \begin{macrocode}
  \xP@parB\dimexpr(\xP@parC+\xP@parA)/2\relax
  \xP@velocity\xP@parB\xP@velB
  \xP@parD\dimexpr(\xP@parE+\xP@parC)/2\relax
  \xP@velocity\xP@parD\xP@velD
%    \end{macrocode}
% Compute the approximations for the arc length on the two smaller parameter intervals (A-B-C) and (C-D-E).
%    \begin{macrocode}
  \xP@lenA
    \dimexpr(\xP@velA+4\xP@velB+\xP@velC)/6*(\xP@parC-\xP@parA)/\xP@bigdim\relax
  \xP@lenB
    \dimexpr(\xP@velC+4\xP@velD+\xP@velE)/6*(\xP@parE-\xP@parC)/\xP@bigdim\relax
  \xP@partlen\dimexpr\xP@lenA+\xP@lenB\relax
%    \end{macrocode}
% Check whether the approximation for the arc length has changed more than the precision parameter.
% The code is a hack to compare the absolute value without occupying another
% dimension register.
%    \begin{macrocode}
  {\@tempdima\dimexpr\xP@oldpartlen-\xP@partlen\relax
  \expandafter}\ifdim\ifdim\@tempdima<\z@-\fi\@tempdima>\xP@tolerance
%    \end{macrocode}
% Yes? Subdivide the interval. The input queue serves as a LIFO stack here!
%    \begin{macrocode}
    \edef\next@{%
      \noexpand\xP@arclength\xP@parB\xP@velB\xP@parC\xP@velC\xP@lenA
      \noexpand\xP@arclength{\the\xP@parD}{\the\xP@velD}{\the\xP@parE}%
      {\the\xP@velE}{\the\xP@lenB}%
    }%
  \else
%    \end{macrocode}
% No? Proceed to the next parameter interval.
%    \begin{macrocode}
    \xP@parA\xP@parE
    \xP@velA\xP@velE
    \advance\@tempdimb\xP@partlen
    \DN@{}%
  \fi
  \next@
}
%    \end{macrocode}
% \end{macro}
%
% \subsection{New improved curve styles}
%
% \begin{macro}{\@crv@}
% Extend the list of curve styles for which special routines exist.
%    \begin{macrocode}
\CheckCommand*\@crv@[2]{\DN@{#1#2}%
  \ifx\next@\empty \edef\next@{\crv@defaultshape}%
  \ifx\bstartPLACE@\empty \xdef\crvSTYLE@@{{\crv@defaultshape}}\fi
  \else
  \ifx\bstartPLACE@\empty \gdef\crvSTYLE@@{#1{#2}}\fi
  \fi
  \ifx\next@\empty \crv@noobject \DN@{\crv@{}{\xy@@crvaddstack@}}%
  \else\def\tmp@{-}\ifx\next@\tmp@ \DN@{\crv@{}{\xy@@crvaddstack@}}%
  \else\def\tmp@{=}\ifx\next@\tmp@
  \DN@{\expandafter\crv@\crv@normaltemplate{\dir{=}}}%
  \else\def\tmp@{2-}\ifx\next@\tmp@
  \DN@{\expandafter\crv@\crv@normaltemplate{\dir{2.}}}%
  \else\def\tmp@{3-}\ifx\next@\tmp@
  \DN@{\expandafter\crv@\crv@normaltemplate{\dir{3.}}}%
  \else\def\tmp@{--}\ifx\next@\tmp@
  \DN@{\expandafter\crv@\crv@specialtemplate@{--}}%
  \else\def\tmp@{==}\ifx\next@\tmp@
  \DN@{\expandafter\crv@\crv@normaltemplate{\dir2{--}}}%
  \else\def\tmp@{2--}\ifx\next@\tmp@
  \DN@{\expandafter\crv@\crv@normaltemplate{\dir2{--}}}%
  \else\def\tmp@{3--}\ifx\next@\tmp@
  \DN@{\expandafter\crv@\crv@normaltemplate{\dir3{--}}}%
  \else\def\tmp@{.}\ifx\next@\tmp@
  \DN@{\expandafter\crv@\crv@specialtemplate@{.}}%
  \else\def\tmp@{:}\ifx\next@\tmp@
  \DN@{\expandafter\crv@\crv@normaltemplate{\dir{:}}}%
  \else\def\tmp@{2.}\ifx\next@\tmp@
  \DN@{\expandafter\crv@\crv@normaltemplate{\dir{:}}}%
  \else\def\tmp@{..}\ifx\next@\tmp@
  \DN@{\expandafter\crv@\crv@specialtemplate@{.}}%
  \else
  \DN@{\expandafter\crv@\crv@othertemplate{\dir#1{#2}}}%
  \fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi \next@}
%    \end{macrocode}
% New curve styles: "3{.}", "{~}", "2{~}", "3{~}"
%    \begin{macrocode}
\xP@hook{@crv@}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\xP@@crv@}
%    \begin{macrocode}
\newcommand*\xP@@crv@[2]{\DN@{#1#2}%
  \ifx\next@\empty \edef\next@{\crv@defaultshape}%
  \ifx\bstartPLACE@\empty \xdef\crvSTYLE@@{{\crv@defaultshape}}\fi
  \else
  \ifx\bstartPLACE@\empty \gdef\crvSTYLE@@{#1{#2}}\fi
  \fi
  \ifx\next@\empty \crv@noobject \DN@{\crv@{}{\xy@@crvaddstack@}}%
  \else\def\tmp@{-}\ifx\next@\tmp@ \DN@{\crv@{}{\xy@@crvaddstack@}}%
  \else\def\tmp@{=}\ifx\next@\tmp@
  \DN@{\expandafter\crv@\crv@normaltemplate{\dir{=}}}%
  \else\def\tmp@{2-}\ifx\next@\tmp@
  \DN@{\expandafter\crv@\crv@normaltemplate{\dir{2.}}}%
  \else\def\tmp@{3-}\ifx\next@\tmp@
  \DN@{\expandafter\crv@\crv@normaltemplate{\dir{3.}}}%
  \else\def\tmp@{--}\ifx\next@\tmp@
  \DN@{\expandafter\crv@\crv@specialtemplate@{--}}%
  \else\def\tmp@{==}\ifx\next@\tmp@
  \DN@{\expandafter\crv@\crv@normaltemplate{\dir2{--}}}%
  \else\def\tmp@{2--}\ifx\next@\tmp@
  \DN@{\expandafter\crv@\crv@normaltemplate{\dir2{--}}}%
  \else\def\tmp@{3--}\ifx\next@\tmp@
  \DN@{\expandafter\crv@\crv@normaltemplate{\dir3{--}}}%
  \else\def\tmp@{.}\ifx\next@\tmp@
  \DN@{\expandafter\crv@\crv@specialtemplate@{.}}%
  \else\def\tmp@{:}\ifx\next@\tmp@
  \DN@{\expandafter\crv@\crv@normaltemplate{\dir{:}}}%
  \else\def\tmp@{2.}\ifx\next@\tmp@
  \DN@{\expandafter\crv@\crv@normaltemplate{\dir{:}}}%
  \else\def\tmp@{3.}\ifx\next@\tmp@
  \DN@{\expandafter\crv@\crv@normaltemplate{\dir3{.}}}%
  \else\def\tmp@{~}\ifx\next@\tmp@
  \DN@{\expandafter\crv@\crv@normaltemplate{\dir{~}}}%
  \else\def\tmp@{2~}\ifx\next@\tmp@
  \DN@{\expandafter\crv@\crv@normaltemplate{\dir2{~}}}%
  \else\def\tmp@{3~}\ifx\next@\tmp@
  \DN@{\expandafter\crv@\crv@normaltemplate{\dir3{~}}}%
  \else\def\tmp@{..}\ifx\next@\tmp@
  \DN@{\expandafter\crv@\crv@specialtemplate@{.}}%
  \else
  \DN@{\expandafter\crv@\crv@othertemplate{\dir#1{#2}}}%
  \fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\next@}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\xysplinespecialcases@}
%    \begin{macrocode}
\CheckCommand*\xysplinespecialcases@{%
  \ifx\empty\xycrvdrop@
  \ifx\empty\xycrvconn@ \DN@{\splinesolid@}%
  \else \DN@{ \dir{-}}\ifx\next@\xycrvconn@ \DN@{\splinesolid@}%
  \else \DN@{ \dir 2{-}}\ifx\next@\xycrvconn@ \DN@{\splinedoubled@}%
  \else \DN@{ \dir{=}}\ifx\next@\xycrvconn@ \DN@{\splineribboned@}%
  \else \DN@{ \dir {2.}}\ifx\next@\xycrvconn@ \DN@{\splinedoubled@}%
  \else \DN@{ \dir 3{-}}\ifx\next@\xycrvconn@ \DN@{\splinetrebled@}%
  \else \DN@{ \dir {3.}}\ifx\next@\xycrvconn@ \DN@{\splinetrebled@}%
  \else \DN@{ \dir{--}}\ifx\next@\xycrvconn@ \DN@{\splinedashed@}%
  \else \DN@{ \dir{.}}\ifx\next@\xycrvconn@ \DN@{\splinedotted@}%
  \else \DN@{ \dir{:}}\ifx\next@\xycrvconn@ \DN@{\splinedbldotted@}%
  \else \ifdim\splinetol@>\z@ \else \splinedefaulttol@ \fi
  \DN@{\splineset@@}\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi
  \else
  \DN@{\splineset@@}%
  \fi \ifInvisible@\DN@{}\fi \next@ }
%    \end{macrocode}
% New:  "\dir3{.}", "\dir2{--}", "\dir3{--}", "\dir{~}", "\dir2{~}", "\dir3{~}"
%    \begin{macrocode}
\xP@hook{xysplinespecialcases@}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\xP@xysplinespecialcases@}
%    \begin{macrocode}
\newcommand*\xP@xysplinespecialcases@{%
  \ifx\empty\xycrvdrop@
  \ifx\empty\xycrvconn@ \DN@{\splinesolid@}%
  \else \DN@{ \dir{-}}\ifx\next@\xycrvconn@ \DN@{\splinesolid@}%
  \else \DN@{ \dir 2{-}}\ifx\next@\xycrvconn@ \DN@{\splinedoubled@}%
  \else \DN@{ \dir{=}}\ifx\next@\xycrvconn@ \DN@{\splineribboned@}%
  \else \DN@{ \dir {2.}}\ifx\next@\xycrvconn@ \DN@{\splinedoubled@}%
  \else \DN@{ \dir 3{-}}\ifx\next@\xycrvconn@ \DN@{\splinetrebled@}%
  \else \DN@{ \dir {3.}}\ifx\next@\xycrvconn@ \DN@{\splinetrebled@}%
  \else \DN@{ \dir{--}}\ifx\next@\xycrvconn@ \DN@{\splinedashed@}%
  \else \DN@{ \dir{.}}\ifx\next@\xycrvconn@ \DN@{\splinedotted@}%
  \else \DN@{ \dir{:}}\ifx\next@\xycrvconn@ \DN@{\splinedbldotted@}%
%    \end{macrocode}
% The next line does not occur in \Xy-pic for an unknown reason. However, it seems reasonable to define the special pattern "\dir2{.}" in the same way as for straight lines.
%    \begin{macrocode}
  \else \DN@{ \dir2{.}}\ifx\next@\xycrvconn@ \DN@{\splinedbldotted@}%
  \else \DN@{ \dir3{.}}\ifx\next@\xycrvconn@ \DN@{\xP@splinetrbldotted}%
  \else \DN@{ \dir2{--}}\ifx\next@\xycrvconn@ \DN@{\xP@splinedbldashed}%
  \else \DN@{ \dir3{--}}\ifx\next@\xycrvconn@ \DN@{\xP@splinetrbldashed}%
  \else \DN@{ \dir{~}}\ifx\next@\xycrvconn@ \DN@{\xP@splinesquiggled}%
  \else \DN@{ \dir2{~}}\ifx\next@\xycrvconn@ \DN@{\xP@splinedblsquiggled}%
  \else \DN@{ \dir3{~}}\ifx\next@\xycrvconn@ \DN@{\xP@splinetrblsquiggled}%
  \else \ifdim\splinetol@>\z@ \else \splinedefaulttol@ \fi
  \DN@{\splineset@@}\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi
  \else
  \DN@{\splineset@@}%
  \fi \ifInvisible@\DN@{}\fi \next@ }
%    \end{macrocode}
% \end{macro}
%
% \subsection{Multiple solid curves}
%
% \begin{macro}{\xP@splinedoubled@}
%    \begin{macrocode}
\xP@hook{splinedoubled@}
\newcommand*\xP@splinedoubled@{%
  \xP@checkspline\xP@splinemultsolid\xP@doublestroke}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\xP@splineribboned@}
%    \begin{macrocode}
\xP@hook{splineribboned@}
\@ifdefinable\xP@splineribboned@\relax
\let\xP@splineribboned@\xP@splinedoubled@
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\xP@splinetrebled@}
%    \begin{macrocode}
\xP@hook{splinetrebled@}
\newcommand*\xP@splinetrebled@{%
  \xP@checkspline\xP@splinemultsolid\xP@trblstroke}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\xP@doublestroke}
% Offset parameters for double lines and curves
%    \begin{macrocode}
\newcommand*\xP@doublestroke{\xydashh@/2,-\xydashh@/2}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\xP@trblstroke}
% Offset parameters for treble lines and curves
%    \begin{macrocode}
\newcommand*\xP@trblstroke{\xydashh@,\z@,-\xydashh@}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\xP@checkspline}
% Get and check spline parameters before the macro in "#1" is executed.
%    \begin{macrocode}
\newcommand*\xP@checkspline[1]{%
  \readsplineparams@
%    \end{macrocode}
% Neglect splines which are drawn “backwards”. Somehow \Xy-pic draws curves forward and backward, but we need it to be drawn only once.
%    \begin{macrocode}
  \let\next@\@gobble
  \ifdim\dimen5<\dimen7
    \xP@preparespline
%    \end{macrocode}
% Neglect splines of zero length.
%    \begin{macrocode}
    \ifdim\@tempdimb>\z@
%    \end{macrocode}
% If the path length is less than twice the line width, just draw a solid path.
%    \begin{macrocode}
      \ifdim\@tempdimb<2\dimexpr\xP@preclw\relax
        \let\next@\xP@splinemultsolid
      \else
        \let\next@#1%
      \fi
    \fi
  \fi
  \next@
}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\xP@splinemultsolid}
% \BulletA
%    \begin{macrocode}
\newcommand*\xP@splinemultsolid[1]{{%
  \xP@inibigdim
  \@temptokena{}%
  \xP@setsolidpat
%    \end{macrocode}
% The "\@for" loop does the multiple strokes. "\@tempa" records the respective offset distance.
%    \begin{macrocode}
  \@for\@tempa:={#1}\do{\xP@paintsolid\z@\xP@bigdim}%
  \xP@stroke{\the\@temptokena}%
}}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\xP@paintsolid}
% \BulletA\ \BulletE\
% Draw a solid spline in the parameter interval $["#1","#2"]\subseteq[0\mathrm{pt},"\xP@bigdim"]$ with a certain offset. The offset distance is expected in "\@tempa".
%    \begin{macrocode}
\newcommand*\xP@paintsolid[2]{{%
%    \end{macrocode}
% Record the original anchor points.
%    \begin{macrocode}
  \xP@savepts
  \xP@a#1\relax
  \xP@c#2\relax
  \xP@movetotrue
  \xP@paintsolid@
  \xdef\@gtempa{\the\@temptokena}%
  }%
  \@temptokena\expandafter{\@gtempa}%
}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\xP@paintsolid@}
% \BulletA\ \BulletE
%    \begin{macrocode}
\newcommand*\xP@paintsolid@{%
%    \end{macrocode}
% These parameters record which part of the spline is currently being offset. They are varied as the spline may be subdivided for a precise offset curve.
%    \begin{macrocode}
  \xP@b\xP@c
%    \end{macrocode}
% Offset distance
%    \begin{macrocode}
  \xP@off\dimexpr\@tempa\relax
  \ifdim\xP@off=\z@
    \xP@shaveprec\xP@a\xP@c
  \else
    \loop
%    \end{macrocode}
% Restore the original anchor points.
%    \begin{macrocode}
      \xP@restorepts
%    \end{macrocode}
% Compute the approximate offset curve. Note that "\xP@a" and "\xP@b" contain the boundary parameters for the partial spline.
%    \begin{macrocode}
      \xP@offsetsegment
%    \end{macrocode}
% Test if the offset curve is good enough.
%    \begin{macrocode}
      \xP@testoffset
%    \end{macrocode}
% If not, shorten the parameter interval by $30\%$.
%    \begin{macrocode}
    \ifxP@offsetok
    \else
      \xP@b\dimexpr\xP@a+(\xP@b-\xP@a)*7/10\relax
    \repeat
  \fi
%    \end{macrocode}
% Append the new segment to the path.
%    \begin{macrocode}
  \xP@append\@temptokena{\ifxP@moveto\xP@coor\X@p\Y@p m \fi
    \xP@coor\L@c\U@c\xP@coor\R@c\D@c\xP@coor\X@c\Y@c c }%
  \xP@movetofalse
%    \end{macrocode}
% Test if the end of the spline has been reached. If not, offset the rest of the curve.
%    \begin{macrocode}
  \ifdim\xP@b<\xP@c\relax
    \xP@a\xP@b
    \expandafter\xP@paintsolid@
  \fi
}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\ifxP@moveto}
% We need a PDF "moveto" operator only for the first partial segment. Additional segments connect seamlessly.
%    \begin{macrocode}
\@ifdefinable\ifxP@moveto\relax
\@ifdefinable\xP@movetotrue\relax
\@ifdefinable\xP@movetofalse\relax
\newif\ifxP@moveto
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\xP@savepts}
% \BulletE\
% Save the anchor points to the second set of reserved variables.
%    \begin{macrocode}
\newcommand*\xP@savepts{%
  \xP@xa\X@p
  \xP@ya\Y@p
  \xP@xb\L@c
  \xP@yb\U@c
  \xP@xc\R@c
  \xP@yc\D@c
  \xP@xd\X@c
  \xP@yd\Y@c
}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\xP@restorepts}
% \BulletE\
% Restore the anchor points from the second set of reserved variables.
%    \begin{macrocode}
\newcommand*\xP@restorepts{%
  \X@p\xP@xa
  \Y@p\xP@ya
  \L@c\xP@xb
  \U@c\xP@yb
  \R@c\xP@xc
  \D@c\xP@yc
  \X@c\xP@xd
  \Y@c\xP@yd
}
%    \end{macrocode}
% \end{macro}
%
% \subsection{A Bézier curve offset algorithm}
%
% First, all control points are offset by the desired distance and in the direction of the normal vectors at the boundary points of the curve. We then adjust the distance of the inner two control points to the boundary control points along the tangents at the boundary points: $x_b = x_a + f_a T_{ax}$, $x_c = x_d + f_d T_{dx}$, and likewise for the $y$-coordinates. In nondegenerate cases, we have $T_{ax}=x_b-x_a$ and $T_{dx}=x_c-x_d$.
%
% Let $P(a,b,c,d,t)$ denote the Bézier polynomial $a(1-t)^3+3bt(1-t)^2+3ct^2(1-t)+dt^3$. In order to determine the factors $f_a$ and $f_d$, we set up a system of three equations.
% \begin{itemize}
% \item Two equations: The old point at parameter $\frac12$ plus offset, $(x_m, y_m)$, is the new point at parameter $t_m$.
%  \begin{align*}
% x_m &= P(x_a, x_a+f_aT_{ax}, x_d+f_dT_{dx}, x_d, t_m)\\
% y_m &= P(y_a, y_a+f_aT_{ay}, y_d+f_dT_{dy}, y_d, t_m)
%  \end{align*}
% \item Third equation: The old tangent at parameter $\frac12$ is in the same direction as the new tangent at $t_m$.
% \begin{align*}
%      &\tfrac\partial{\partial t_m}P(x_a, x_a+f_aT_{ax}, x_d+f_dT_{dx}, x_d, t_m)\cdot T_{my}\\
% {}={}&\tfrac\partial{\partial t_m}P(y_a, y_a+f_aT_{ay}, y_d+f_dT_{dy}, y_d, t_m)\cdot T_{mx}
%\end{align*}
%\end{itemize}
%
% Up to a scalar factor of $-3/4$, $(T_{mx},T_{my})$ is the velocity vector to the original curve at parameter $\frac12$. We have $T_{mx}=(X_a+X_b-X_c-X_d)/2$ (in the old coordinates!) and $T_{my}$ analogously. The system above is a nonlinear system of three equations in three variables, which we solve by Newton's method. Let $f_a$, $f_d$, and $t_m$ be approximate solutions, and denote by $\Delta f_a$, $\Delta f_d$, and $\Delta t_m$ the increments to the next approximation. In the first order, the three equations become:
% \begin{gather*}
% x_m = P(x_a, x_b, x_c, x_d, t_m)+ \Delta f_a\cdot T_{ax}\cdot 3t_m(1-t_m)^2+\Delta f_d\cdot T_{dx}\cdot 3t_m^2(1-t_m)\\
% \qquad{}+\Delta t_m \tfrac\partial{\partial t_m}P(x_a, x_b, x_c, x_d, t_m)\\
% y_m = P(y_a, y_b, y_c, y_d, t_m)+ \Delta f_a\cdot T_{ay}\cdot 3t_m(1-t_m)^2+\Delta f_d\cdot T_{dy}\cdot 3t_m^2(1-t_m)\\
% \qquad{}+\Delta t_m \tfrac\partial{\partial t_m}P(y_a, y_b, y_c, y_d, t_m)\\
% \Big(\tfrac\partial{\partial t_m}P(x_a, x_b, x_c, x_d, t_m)+\Delta f_a\cdot T_{ax}\cdot 3(1-4t_m+3t_m^2)+\Delta f_d\cdot T_{dx}\cdot 3(2t_m-3t_m^2)\\
% \qquad{}+\Delta t_m \cdot6\left((x_a-2x_b+x_c)+t_m(x_d-x_a+3(x_b-x_c))\right)\Big)\cdot T_{my}\\
% {} = \Big(\tfrac\partial{\partial t_m}P(y_a, y_b, y_c, y_d, t_m)+\Delta f_a \cdot T_{ay}\cdot 3(1-4t_m+3t_m^2)+\Delta f_d\cdot T_{dy}\cdot 3(2t_m-3t_m^2)\\
% \qquad{}+\Delta t_m \cdot6\left((y_a-2y_b+y_c)+t_m(y_d-y_a+3(y_b-y_c))\right)\Big)\cdot T_{mx}
% \end{gather*}
%
% Rewrite the equations so that they resemble the \TeX{} code.
% \begin{gather*}
% 8P(x_a, x_b, x_c, x_d, t_m)-8x_m = -\Delta f_a\cdot 3T_{ax}\cdot 2t_m\cdot(2(1-t_m))^2\\
% \qquad{}-\Delta f_d\cdot 3T_{dx}\cdot 4t_m^2\cdot2(1-t_m)-\Delta t_m\cdot8\tfrac\partial{\partial t_m}P(x_a, x_b, x_c, x_d, t_m)\\
% 8P(y_a, y_b, y_c, y_d, t_m)-8y_m = -\Delta f_a\cdot 3T_{ay}\cdot 2t_m\cdot(2(1-t_m))^2\\
% \qquad{}-\Delta f_d\cdot 3T_{dy}\cdot 4t_m^2\cdot2(1-t_m)-\Delta t_m\cdot8\tfrac\partial{\partial t_m}P(y_a, y_b, y_c, y_d, t_m)\\
% T_{mx}\cdot8\tfrac\partial{\partial t_m}P(y_a, y_b, y_c, y_d, t_m)-T_{my}\cdot8\tfrac\partial{\partial t_m}P(x_a, x_b, x_c, x_d, t_m)\\
% {}=-\Delta f_a\cdot(3T_{ay}\cdot2T_{mx}-3T_{ax}\cdot2T_{my})\cdot 2(1-3t_m)\cdot2(1-t_m)\\
% {}-\Delta f_d\cdot (3T_{dy}\cdot2T_{mx}-3T_{dx}\cdot2T_{my})\cdot2(2-3t_m)\cdot2t_m\\
% -\Delta t_m \cdot (((y_d-y_a+3(y_b-y_c))\cdot 2t_m+2(y_a-2y_b+y_c))\cdot3\cdot8T_{mx}\\
% \qquad{}-((x_d-x_a+3(x_b-x_c))\cdot 2t_m+2(x_a-2x_b+x_c))\cdot3\cdot8T_{my})\\
% \end{gather*}
%
% Substitute $2t_m=\tau_m$.
% \begin{gather*}
% 8P(x_a, x_b, x_c, x_d, t_m)-8x_m = -\Delta f_a\cdot 3T_{ax}\cdot \tau_m(2-\tau_m)^2\\
% \qquad{}-\Delta f_d\cdot 3T_{dx}\cdot\tau_m^2(2-\tau_m)-\tfrac12\Delta\tau_m\cdot8\tfrac\partial{\partial t_m}P(x_a, x_b, x_c, x_d, t_m)\\
% 8P(y_a, y_b, y_c, y_d, t_m)-8y_m = -\Delta f_a\cdot 3T_{ay}\cdot \tau_m\cdot(2-\tau_m)^2\\
% \qquad{}-\Delta f_d\cdot 3T_{dy}\cdot\tau_m^2(2-\tau_m)-\tfrac12\Delta\tau_m\cdot8\tfrac\partial{\partial t_m}P(y_a, y_b, y_c, y_d, t_m)\\
% T_{mx}\cdot8\tfrac\partial{\partial t_m}P(y_a, y_b, y_c, y_d, t_m)-T_{my}\cdot8\tfrac\partial{\partial t_m}P(x_a, x_b, x_c, x_d, t_m)\\
% {}=-\Delta f_a\cdot(3T_{ay}\cdot2T_{mx}-3T_{ax}\cdot2T_{my})\cdot(2-3\tau_m)(2-\tau_m)\\
% {}-\Delta f_d\cdot (3T_{dy}\cdot2T_{mx}-3T_{dx}\cdot2T_{my})\cdot(4-3\tau_m)\tau_m\\
% -\Delta \tau_m \cdot (((y_d-y_a+3(y_b-y_c))\cdot\tau_m+2(y_a-2y_b+y_c))\cdot12T_{mx}\\
% \qquad{}-((x_d-x_a+3(x_b-x_c))\cdot\tau_m+2(x_a-2x_b+x_c))\cdot12T_{my})\\
% \end{gather*}
%
% The translation into \TeX{} dimensions:
% \begin{itemize}
% \item $f_a="\xP@fa"$, $f_d="\xP@fd"$
% \item $\tau_m="\xP@tm"$
% \item $x_a="\xP@xa",\ldots, x_d="\xP@xd",\ldots, y_d="\xP@yd"$
% \item $8P(x_1,x_2,x_3,x_4,\frac12x_5) = "\xP@bezierpoly#1#2#3#4#5"$
% \item $8x_m="\xP@xm"$, $8y_m="\xP@ym"$
% \item $3T_{ax} = "\xP@Tax"$, $3T_{dx} = "\xP@Tdx"$, $3T_{ay} = "\xP@Tay"$, $3T_{dy} = "\xP@Tdy"$
% \item $8\tfrac\partial{\partial x_5}P(x_1, x_2, x_3, x_4, \frac12x_5) = "\xP@beziertan#1#2#3#4#5"$
%\end{itemize}
% Temporary:
% \begin{itemize}
% \item $2-\tau_m="\xP@ta"$
% \item $\tau_m(2-\tau_m)="\xP@tb"$
% \item $T_{mx} = "\xP@Tmx"$, $T_{my} = "\xP@Tmy"$
% \item $2-3\tau_m="\xP@tb"$
% \item $4-3\tau_m="\xP@tc"$
%\end{itemize}
%
% Since the linear system above tends to be singular or ill-conditioned (think about the frequent case when all control points are nearly collinear!), the Gauss algorithm "\xP@solvelinearsystem" does not always return a valid solution. In these cases, the system is not solved exactly but approximated iteratively in "\xP@applinsys".
% \begin{macro}{\xP@tmx}
% \begin{macro}{\xP@tmy}
%    \begin{macrocode}
\@ifdefinable\xP@tmx\relax
\@ifdefinable\xP@tmy\relax
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \begin{macro}{\xP@Tmxy}
% \begin{macro}{\xP@Tmyx}
% \BulletD
%    \begin{macrocode}
\newcommand*\xP@Tmxy{*\xP@Tmx/\xP@Tmy}
\newcommand*\xP@Tmyx{*\xP@Tmy/\xP@Tmx}
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \begin{macro}{\xP@Tmzero}
%    \begin{macrocode}
\newcommand*\xP@Tmzero{*\z@}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\xP@offsetsegment}
% \BulletA\ \BulletC\ \BulletD\ Offset a cubic segment. The offset distance is given in "\xP@off". The anchor points are given in "\X@p",\ldots,"\Y@c". The partial spline in the parameter interval $["\xP@a","\xP@b"]\subseteq[0\mathrm{pt},"\xP@bigdim"]$ is offset. The new Bézier curve is returned in "\xP@xa",\ldots,"\xP@yd".
%    \begin{macrocode}
\newcommand*\xP@offsetsegment{{%
%    \end{macrocode}
% New first anchor point and tangent vector at $0$
%    \begin{macrocode}
  \xP@tangentvec\xP@a
  \xP@xa\dimexpr\xP@precbezierpoly\X@p\L@c\R@c\X@c\xP@a/8%
    +\d@Y*\xP@off/\@tempdimb\relax
  \xP@ya\dimexpr\xP@precbezierpoly\Y@p\U@c\D@c\Y@c\xP@a/8%
    -\d@X*\xP@off/\@tempdimb\relax
  \xP@scaleT
  \xP@Tax\d@X
  \xP@Tay\d@Y
  \xP@E\@tempdimb
%    \end{macrocode}
% New last anchor point and tangent vector at $1$
%    \begin{macrocode}
  \xP@tangentvec\xP@b
  \xP@xd\dimexpr\xP@precbezierpoly\X@p\L@c\R@c\X@c\xP@b/8%
    +\d@Y*\xP@off/\@tempdimb\relax
  \xP@yd\dimexpr\xP@precbezierpoly\Y@p\U@c\D@c\Y@c\xP@b/8%
    -\d@X*\xP@off/\@tempdimb\relax
  \xP@scaleT
  \xP@Tdx-\d@X
  \xP@Tdy-\d@Y
  \xP@F\@tempdimb
%    \end{macrocode}
% Scalar product of the tangent vectors
%    \begin{macrocode}
  \xP@M\z@
  \xP@Max\xP@M\xP@Tdx
  \xP@Max\xP@M\xP@Tdy
  \xP@L\dimexpr\xP@Tax*\xP@Tdx/\xP@M+\xP@Tay*\xP@Tdy/\xP@M\relax
  \xP@tm\dimexpr(\xP@a+\xP@b)/2\relax
  \ifdim\xP@L>\dimexpr\xP@E*\xP@F/\xP@M*49/50\relax
%    \end{macrocode}
% Trick to improve the offset algorithm near sharp bends and cusps: If the tangent vectors $(T_{ax},T_{ay})$ and $(T_{dx},T_{dy})$ point nearly in the same direction, we do not use the true tangent vector for $(T_{mx},T_{my})$ at the middle point but a fake one. (The exact condition is that their normed scalar product is greater that $49/50$. For a straight line, the vectors would point in opposite directions.) The fake tangent vector is defined to be $(T_{ax}+T_{dx},T_{ay}+T_{dy})$ rotated by $\pm 90\textrm{\textdegree}$. Its direction is chosen such that the scalar product with $(X_d-X_a, Y_d-Y_a)$ is nonnegative. (Use $(X_c-X_b, Y_c-Y_b)$ in the degenerate case $(X_d-X_a, Y_d-Y_a)=(0,0)$.)
%
% Rationale: In the presence of a sharp bend or cusp, the offset algorithm will hardly meet the tip. Since the tangent/normal at the tip is needed for a good offset curve, we provide this artificially.
%    \begin{macrocode}
    \d@X-\dimexpr\xP@Tay+\xP@Tdy\relax
    \d@Y\dimexpr\xP@Tax+\xP@Tdx\relax
    \xP@veclen
    \xP@A\dimexpr\X@c-\X@p\relax
    \xP@B\dimexpr\Y@c-\Y@p\relax
    \xP@M\z@
    \xP@Max\xP@M\xP@A
    \xP@Max\xP@M\xP@B
    \ifdim\xP@M=\z@
      \xP@A\dimexpr\R@c-\L@c\relax
      \xP@B\dimexpr\D@c-\U@c\relax
      \xP@Max\xP@M\xP@A
      \xP@Max\xP@M\xP@B
    \fi
    \xP@M\dimexpr\d@X*\xP@A/\xP@M+\d@Y*\xP@B/\xP@M\relax
    \ifdim\xP@M<\z@
      \multiply\d@X\m@ne
      \multiply\d@Y\m@ne
    \fi
  \else
%    \end{macrocode}
% Normal case: tangent vector at the middle point.
%    \begin{macrocode}
  \xP@tangentvec\xP@tm
  \fi
%    \end{macrocode}
% From here on, "\xP@a" and "\xP@b" will not be used any more, so these variables can be used under their other names "\xP@I", "\xP@J" for the linear systems below.
%
% 8 times (middle point plus offset)
%    \begin{macrocode}
  \xP@xm\dimexpr\xP@precbezierpoly\X@p\L@c\R@c\X@c\xP@tm
    +8\d@Y*\xP@off/\@tempdimb\relax
  \xP@ym\dimexpr\xP@precbezierpoly\Y@p\U@c\D@c\Y@c\xP@tm
    -8\d@X*\xP@off/\@tempdimb\relax
%    \end{macrocode}
% Tangent at middle point
%    \begin{macrocode}
  \xP@Tmx\d@X
  \xP@Tmy\d@Y
  \xP@ifabsless\xP@Tmy\xP@Tmx
    \let\xP@tmy\xP@Tmyx
    \let\xP@tmx\empty
  \else
    \ifdim\xP@Tmy=\z@
      \let\xP@tmx\xP@Tmzero
      \let\xP@tmy\xP@Tmzero
    \else
      \let\xP@tmy\empty
      \let\xP@tmx\xP@Tmxy
    \fi
  \fi
%    \end{macrocode}
% Initial guesses for the tangent vector scalings "\xP@fa", "\xP@fd" and the near-middle position "\xP@tm"
%    \begin{macrocode}
  \xP@fa\p@
  \xP@fd\p@
  \xP@tm\p@
%    \end{macrocode}
% The main loop for finding the offset curve
%    \begin{macrocode}
  \count@\z@
  \loop
%    \end{macrocode}
% Set the new control points up.
%    \begin{macrocode}
    \xP@offsetpoints
    \@tempswafalse
%    \end{macrocode}
% At most $10$ iterations
%    \begin{macrocode}
    \ifnum10>\count@
%    \end{macrocode}
% Determine the quality of the approximation by an objective function.
%    \begin{macrocode}
      \xP@objfun\xP@oldobj
      \ifdim\xP@oldobj>\xP@maxobjfun\relax\@tempswatrue\fi
    \fi
  \if@tempswa
    \xP@offsetloop
  \repeat
%    \end{macrocode}
% Return the new anchor points.
%    \begin{macrocode}
  \xdef\@gtempa{\X@p\the\xP@xa\Y@p\the\xP@ya
    \L@c\the\xP@xb\U@c\the\xP@yb\R@c\the\xP@xc\D@c\the\xP@yc
    \X@c\the\xP@xd\Y@c\the\xP@yd\relax}%
  }%
  \@gtempa
}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\xP@scaleT}
% \BulletA\ \BulletC\ \BulletD\
% This macro contains another trick to improve the offset algorithm around sharp bends and cusps. It adjusts the length of the tangent/velocity vectors. Let $("\d@X","\d@Y")$ be the velocity vector to the original curve at some point with velocity $v_0$. The velocity at the same point, considered on a partial segment scales linearly with the length of the parameter interval. Hence, the velocity $v_1$ in the partial segment is $v_1=v_0\cdot("\xP@b"-"\xP@a")/"\xP@bigdim"$. Additionally the offset curve goes with a radius of $r+"\xP@off"$ around bends with radius $r$ in the original curve. As an approximation to the velocity in the offset curve, we therefore scale the velocity vector in the end to the norm $v_1 + 2\pi\cdot|"\xP@off"|$.
%    \begin{macrocode}
\newcommand*\xP@scaleT{%
  \xP@B6.28\xP@off
  \xP@abs\xP@B
  \xP@C\dimexpr\d@X*\xP@B/\@tempdimb\relax
  \xP@D\dimexpr\d@Y*\xP@B/\@tempdimb\relax
  \xP@A\dimexpr\xP@b-\xP@a\relax
  \d@X\dimexpr\xP@C+\d@X*\xP@A/\xP@bigdim\relax
  \d@Y\dimexpr\xP@D+\d@Y*\xP@A/\xP@bigdim\relax
%    \end{macrocode}
% Also record the change to the norm of the vector.
%    \begin{macrocode}
  \@tempdimb\dimexpr\xP@B+\@tempdimb*\xP@A/\xP@bigdim\relax
}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\xP@offsetloop}
% \BulletA\ \BulletC\ \BulletD\ The iteration in the offset loop: set up and solve (or approximate) the linear system.
%    \begin{macrocode}
\newcommand*\xP@offsetloop{%
  \xP@C\dimexpr\xP@C/2\relax
  \xP@G\dimexpr\xP@G/2\relax
%    \end{macrocode}
% 1st linear equation
%    \begin{macrocode}
  \xP@ta\dimexpr2\p@-\xP@tm\relax
  \xP@tb\dimexpr\xP@tm*\xP@ta/\p@\relax
  \xP@A\dimexpr\xP@Tax*\xP@tb/\p@*\xP@ta/\p@\relax
  \xP@B\dimexpr\xP@Tdx*\xP@tb/\p@*\xP@tm/\p@\relax
%    \end{macrocode}
% 2nd linear equation
%    \begin{macrocode}
  \xP@E\dimexpr\xP@Tay*\xP@tb/\p@*\xP@ta/\p@\relax
  \xP@F\dimexpr\xP@Tdy*\xP@tb/\p@*\xP@tm/\p@\relax
%    \end{macrocode}
% 3rd linear equation
%    \begin{macrocode}
  \xP@tb\dimexpr2\p@-3\xP@tm\relax
  \xP@tc\dimexpr\xP@tb+2\p@\relax
  \xP@I\dimexpr(2\xP@Tay\xP@tmx-2\xP@Tax\xP@tmy)*\xP@tb/\p@*\xP@ta/\p@\relax
  \xP@J\dimexpr(2\xP@Tdy\xP@tmx-2\xP@Tdx\xP@tmy)*\xP@tc/\p@*\xP@tm/\p@\relax
  \xP@K\dimexpr((\xP@yd-\xP@ya+(\xP@yb-\xP@yc)*3)
    *\xP@tm/\p@+(\xP@yc-2\xP@yb+\xP@ya)*2)*12\xP@tmx
    -((\xP@xd-\xP@xa+(\xP@xb-\xP@xc)*3)
    *\xP@tm/\p@+(\xP@xc-2\xP@xb+\xP@xa)*2)*12\xP@tmy\relax
%    \end{macrocode}
% Solve the system.
%    \begin{macrocode}
  \xP@solvelinearsystem
  \ifxP@validsol
%    \end{macrocode}
% Check whether the result is feasible and whether it actually improves the approximation.
%    \begin{macrocode}
    \xP@correctsol
    \ifdim\xP@ta=\z@
    \ifdim\xP@tb=\z@
    \ifdim\xP@tc=\z@
      \xP@validsolfalse
    \fi\fi\fi
  \fi
%    \end{macrocode}
% If the exact solution is not valid, try to at least approximate a solution.
%    \begin{macrocode}
  \ifxP@validsol
  \else
    \xP@applinsys
%    \end{macrocode}
% This time, the solution is not checked but applied immediately.
%    \begin{macrocode}
    \advance\xP@fa-\xP@ta
    \advance\xP@fd-\xP@tb
    \advance\xP@tm-\xP@tc
%    \end{macrocode}
% The near-middle parameter on the curve must not lie outside the segment.
%    \begin{macrocode}
    \ifdim\xP@tm<\z@\xP@tm\z@\fi
    \ifdim\xP@tm>2\p@\xP@tm2\p@\fi
  \fi
  \advance\count@\@ne
}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\xP@maxsol}
% Heuristic: maximal solution so that no arithmetic overflow is produced.
%    \begin{macrocode}
\newcommand*\xP@maxsol{3pt}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\xP@correctsol}
% \BulletC\ \BulletD\
% Check whether the solution is feasible and actually improves the objective function.
%    \begin{macrocode}
\newcommand*\xP@correctsol{%
%    \end{macrocode}
% If the solution is too big, scale all variables uniformly.
%    \begin{macrocode}
  \xP@M\z@
  \xP@Max\xP@M\xP@ta
  \xP@Max\xP@M\xP@tb
  \xP@Max\xP@M\xP@tc
  \ifdim\xP@M>\xP@maxsol
    \xP@ta\dimexpr\xP@maxsol*\xP@ta/\xP@M\relax
    \xP@tb\dimexpr\xP@maxsol*\xP@tb/\xP@M\relax
    \xP@tc\dimexpr\xP@maxsol*\xP@tc/\xP@M\relax
  \fi
%    \end{macrocode}
% Apply the solution. Save the old value of "\xP@tm" to be able to restore it.
%    \begin{macrocode}
  \advance\xP@fa-\xP@ta
  \advance\xP@fd-\xP@tb
  \xP@M\xP@tm
  \advance\xP@tm-\xP@tc
%    \end{macrocode}
% The near-middle parameter must lie on the segment.
%    \begin{macrocode}
  \ifdim\xP@tm<\z@\xP@tm\z@\fi
  \ifdim\xP@tm>2\p@\xP@tm2\p@\fi
%    \end{macrocode}
% Check whether the solution actually improves the objective function.
%    \begin{macrocode}
  {\xP@offsetpoints
    \xP@objfun\xP@M
  \expandafter}%
%    \end{macrocode}
% If not, restore the old values and declare the solution invalid.
%    \begin{macrocode}
  \ifdim\xP@M>\xP@oldobj
    \advance\xP@fa\xP@ta
    \advance\xP@fd\xP@tb
    \xP@tm\xP@M
    \xP@validsolfalse
  \fi
}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\xP@objfun}
% \BulletC\ \BulletD\
% The objective function: sum of squares of the deviation in $x$- and $y$-direction and the angular deviation at the middle point. We also compute some terms which will be used in the linear system.
%    \begin{macrocode}
\newcommand*\xP@objfun[1]{%
  \xP@D\dimexpr\xP@bezierpoly\xP@xa\xP@xb\xP@xc\xP@xd\xP@tm-\xP@xm\relax
  \xP@H\dimexpr\xP@bezierpoly\xP@ya\xP@yb\xP@yc\xP@yd\xP@tm-\xP@ym\relax
  \xP@C\xP@beziertan\xP@xa\xP@xb\xP@xc\xP@xd\xP@tm
  \xP@G\xP@beziertan\xP@ya\xP@yb\xP@yc\xP@yd\xP@tm
  \xP@L\dimexpr\xP@G\xP@tmx-\xP@C\xP@tmy\relax
%    \end{macrocode}
% If the deviation is too big, let the objective function be "\maxdimen". Otherwise, compute the sum of squares.
%    \begin{macrocode}
  #1\z@
  \xP@Max#1\xP@D
  \xP@Max#1\xP@H
  \xP@Max#1\xP@L
  #1\ifdim#1>4843165sp
    \maxdimen
  \else
    \dimexpr\xP@D*\xP@D/\p@+\xP@H*\xP@H/\p@+\xP@L*\xP@L/\p@\relax
  \fi
}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\xP@offsetpoints}
% \BulletC\ \BulletD\
% Compute the new control points from the factors "\xP@fa", "\xP@fd".
%    \begin{macrocode}
\newcommand*\xP@offsetpoints{%
  \xP@xb\dimexpr\xP@xa+\xP@Tax*\xP@fa/196608\relax
  \xP@yb\dimexpr\xP@ya+\xP@Tay*\xP@fa/196608\relax
  \xP@xc\dimexpr\xP@xd+\xP@Tdx*\xP@fd/196608\relax
  \xP@yc\dimexpr\xP@yd+\xP@Tdy*\xP@fd/196608\relax
}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\xP@bezierpoly}
% Formula for the polynomial $8\left( "#1"\cdot(1-t)^3
% +3\cdot"#2"\cdot t(1-t)^2+3\cdot"#3"\cdot t^2(1-t)+"#4"\cdot t^3\right)$,
% $t=\frac12"#5"$.
%    \begin{macrocode}
\newcommand*\xP@bezierpoly[5]{%
  \dimexpr(((#4-#1+(#2-#3)*3)*#5/\p@+(#1-2#2+#3)*6)*#5/\p@+(#2-#1)*12)*#5/\p@
    +#1*8\relax
}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\xP@precbezierpoly}
% Formula for the polynomial $8\left( "#1"\cdot(1-t)^3
% +3\cdot"#2"\cdot t(1-t)^2+3\cdot"#3"\cdot t^2(1-t)+"#4"\cdot t^3\right)$,
% $t="#5"/"\xP@bigdim"$.
%    \begin{macrocode}
\newcommand*\xP@precbezierpoly[5]{%
  \dimexpr(((#4-#1+(#2-#3)*3)*2*#5/\xP@bigdim+(#1-2#2+#3)*6)*2*#5/\xP@bigdim
    +(#2-#1)*12)*2*#5/\xP@bigdim+#1*8\relax
}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\xP@beziertan}
% Formula for the polynomial
% \[
% 24\left( -"#1"\cdot(1-t)^2+"#2"\cdot(3t^2 -4t+1)+"#3"\cdot(-3t^2+2t)+"#4"\cdot t^2\right),\quad t=\tfrac12"#5".
% \]
% Up to a scalar factor, this is the derivative of the third order Bézier polynomial above.
%    \begin{macrocode}
\newcommand*\xP@beziertan[5]{%
  \dimexpr((#4-#1+(#2-#3)*3)*3*#5/32768+(#1-2#2+#3)*24)*#5/\p@+(#2-#1)*24\relax
}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\xP@precbeziertan}
% Formula for the polynomial
% \[
% \left( -"#1"\cdot(1-t)^2+"#2"\cdot(3t^2 -4t+1)+"#3"\cdot(-3t^2+2t)+"#4"\cdot t^2\right),\quad t="#5"/"\xP@bigdim".
% \]
% This is $\tfrac13$ times the derivative of the third order Bézier polynomial.
%    \begin{macrocode}
\newcommand*\xP@precbeziertan[5]{%
  \dimexpr((#4-#1+(#2-#3)*3)*#5/\xP@bigdim+(#1-2#2+#3)*2)*#5/\xP@bigdim
  +#2-#1\relax
}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\xP@solvelinearsystem}
% \BulletC\
% The macro "\xP@solvelinearsystem" solves a system of three linear equations by the Gauss algorithm. The coefficients and desired values are passed in the extended matrix
% \[
% \left(\begin{array}{lll|l}
% "\xP@A" & "\xP@B" & "\xP@C" & "\xP@D" \\
% "\xP@E" & "\xP@F" & "\xP@G" & "\xP@H" \\
% "\xP@I" & "\xP@J" & "\xP@K" & "\xP@L"
% \end{array}\right)
% \]
% The solution is returned in the vector $("\xP@ta","\xP@tb","\xP@tc")$.
% \begin{macro}{\xP@varone}
% \begin{macro}{\xP@vartwo}
% \begin{macro}{\xP@varthree}
% With column swapping in the Gauss algorithm, variable names might be changed. These macros record the variables.
%    \begin{macrocode}
\@ifdefinable\xP@varone\relax
\@ifdefinable\xP@vartwo\relax
\@ifdefinable\xP@varthree\relax
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
% \begin{macro}{\ifxP@validsol}
% Records if a valid solution to the linear system is returned.
%    \begin{macrocode}
\@ifdefinable\ifxP@validsol\relax
\@ifdefinable\xP@validsoltrue\relax
\@ifdefinable\xP@validsolfalse\relax
\newif\ifxP@validsol
%    \end{macrocode}
% \end{macro}
%    \begin{macrocode}
\newcommand*\xP@solvelinearsystem{{%
%    \end{macrocode}
% Scale the matrix so that the highest absolute value in each row and each column is $\geq2048\mathrm{pt}$ and $<4096\mathrm{pt}$.
%    \begin{macrocode}
  \xP@scalerow\xP@A\xP@B\xP@C\xP@D
  \xP@scalerow\xP@E\xP@F\xP@G\xP@H
  \xP@scalerow\xP@I\xP@J\xP@K\xP@L
  \xP@scalecol\xP@A\xP@E\xP@I\xP@scaleone
  \xP@scalecol\xP@B\xP@F\xP@J\xP@scaletwo
  \xP@scalecol\xP@C\xP@G\xP@K\xP@scalethree
%    \end{macrocode}
% Record the initial variable-to-column assignment.
%    \begin{macrocode}
  \let\xP@varone\xP@ta
  \let\xP@vartwo\xP@tb
  \let\xP@varthree\xP@tc
%    \end{macrocode}
% Find the pivot position. "\xP@M" is used temporarily.
%    \begin{macrocode}
  \count@\m@ne
  \@tempcnta\m@ne
  \xP@ifabsless\xP@A\xP@B\@tempcnta\z@\xP@M\xP@B
             \else\xP@M\xP@A\fi
  \xP@ifabsless\xP@M\xP@C\@tempcnta\@ne\xP@M\xP@C\fi
  \xP@ifabsless\xP@M\xP@E\@tempcnta\m@ne\count@\z@\xP@M\xP@E\fi
  \xP@ifabsless\xP@M\xP@F\@tempcnta\z@\count@\z@\xP@M\xP@F\fi
  \xP@ifabsless\xP@M\xP@G\@tempcnta\@ne\count@\z@\xP@M\xP@G\fi
  \xP@ifabsless\xP@M\xP@I\@tempcnta\m@ne\count@\@ne\xP@M\xP@I\fi
  \xP@ifabsless\xP@M\xP@J\@tempcnta\z@\count@\@ne\xP@M\xP@J\fi
  \xP@ifabsless\xP@M\xP@K\@tempcnta\@ne\count@\@ne\fi
%    \end{macrocode}
% Swap rows
%    \begin{macrocode}
  \ifcase\count@
    \xP@swapdim\xP@A\xP@E
    \xP@swapdim\xP@B\xP@F
    \xP@swapdim\xP@C\xP@G
    \xP@swapdim\xP@D\xP@H
  \or
    \xP@swapdim\xP@A\xP@I
    \xP@swapdim\xP@B\xP@J
    \xP@swapdim\xP@C\xP@K
    \xP@swapdim\xP@D\xP@L
  \fi
%    \end{macrocode}
% Swap columns
%    \begin{macrocode}
  \ifcase\@tempcnta
    \xP@swapdim\xP@A\xP@B
    \xP@swapdim\xP@E\xP@F
    \xP@swapdim\xP@I\xP@J
    \let\xP@varone\xP@tb
    \let\xP@vartwo\xP@ta
    \xP@swapnum\xP@scaleone\xP@scaletwo
  \or
    \xP@swapdim\xP@A\xP@C
    \xP@swapdim\xP@E\xP@G
    \xP@swapdim\xP@I\xP@K
    \let\xP@varone\xP@tc
    \let\xP@varthree\xP@ta
    \xP@swapnum\xP@scaleone\xP@scalethree
  \fi
%    \end{macrocode}
% First elimination
%    \begin{macrocode}
  \multiply\xP@E\m@ne
  \multiply\xP@I\m@ne
%    \end{macrocode}
% Absolute values below are $<8192\mathrm{pt}$.
%    \begin{macrocode}
  \ifdim\xP@A=\z@
  \else
    \advance\xP@F\dimexpr\xP@B*\xP@E/\xP@A\relax
    \advance\xP@G\dimexpr\xP@C*\xP@E/\xP@A\relax
    \advance\xP@H\dimexpr\xP@D*\xP@E/\xP@A\relax
    \advance\xP@J\dimexpr\xP@B*\xP@I/\xP@A\relax
    \advance\xP@K\dimexpr\xP@C*\xP@I/\xP@A\relax
    \advance\xP@L\dimexpr\xP@D*\xP@I/\xP@A\relax
  \fi
%    \end{macrocode}
% Find the second pivot element. "\xP@M" is used temporarily.
%    \begin{macrocode}
  \count@\m@ne
  \xP@ifabsless\xP@F\xP@G\@tempcnta\z@\xP@M\xP@G
    \else\@tempcnta\m@ne\xP@M\xP@F\fi
  \xP@ifabsless\xP@M\xP@J\@tempcnta\m@ne\count@\z@\xP@M\xP@J\fi
  \xP@ifabsless\xP@M\xP@K\@tempcnta\z@\count@\z@\fi
%    \end{macrocode}
% Swap rows
%    \begin{macrocode}
  \ifnum\count@=\z@
    \xP@swapdim\xP@F\xP@J
    \xP@swapdim\xP@G\xP@K
    \xP@swapdim\xP@H\xP@L
  \fi
%    \end{macrocode}
% Swap columns
%    \begin{macrocode}
  \ifnum\@tempcnta=\z@
    \xP@swapdim\xP@B\xP@C
    \xP@swapdim\xP@F\xP@G
    \xP@swapdim\xP@J\xP@K
    \let\@tempa\xP@varthree
    \let\xP@varthree\xP@vartwo
    \let\xP@vartwo\@tempa
    \xP@swapnum\xP@scaletwo\xP@scalethree
  \fi
%    \end{macrocode}
% Second elimination. Absolute values are $<16384\mathrm{pt}$.
%    \begin{macrocode}
  \ifdim\xP@F=\z@
  \else
    \advance\xP@K\dimexpr-\xP@G*\xP@J/\xP@F\relax
    \advance\xP@L\dimexpr-\xP@H*\xP@J/\xP@F\relax
  \fi
%    \end{macrocode}
% Compute the result from the upper triagonal form. Since the matrix can be singular, we have to ensure in every step that no overflow occurs. In general, we do not allow any solution greater than $60\mathrm{pt}$.
%    \begin{macrocode}
  \xP@ifabsless{\dimexpr\xP@L/60\relax}{\dimexpr\xP@K/\xP@scalethree\relax}%
    \xP@validsoltrue
    \xP@varthree\dimexpr\xP@L*(\xP@scalethree*\p@)/\xP@K\relax
  \else
    \xP@validsolfalse
  \fi
  \xP@checkabs{\xP@H/8191}{\xP@F/\xP@scaletwo}%
  \xP@checkabs{\xP@G/\xP@scalethree/136}{\xP@F/\xP@scaletwo}%
  \ifxP@validsol
    \xP@vartwo\dimexpr\xP@H*(\xP@scaletwo*\p@)/\xP@F
      -\xP@varthree*\xP@scaletwo/\xP@scalethree*\xP@G/\xP@F\relax
    \xP@checkabs\xP@vartwo{60pt}%
  \fi
  \xP@checkabs{\xP@D/5461}{\xP@A/\xP@scaleone}%
  \xP@checkabs{\xP@B/\xP@scaletwo/91}{\xP@A/\xP@scaleone}%
  \xP@checkabs{\xP@C/\xP@scalethree/91}{\xP@A/\xP@scaleone}%
  \ifxP@validsol
    \xP@varone\dimexpr\xP@D*(\xP@scaleone*\p@)/\xP@A
      -\xP@vartwo*\xP@scaleone/\xP@scaletwo*\xP@B/\xP@A
      -\xP@varthree*\xP@scaleone/\xP@scalethree*\xP@C/\xP@A\relax
    \xP@checkabs\xP@varone{60pt}%
  \fi
%    \end{macrocode}
% Return the result.
%    \begin{macrocode}
  \xdef\@gtempa{%
    \ifxP@validsol
      \xP@ta\the\xP@ta\relax
      \xP@tb\the\xP@tb\relax
      \xP@tc\the\xP@tc\relax
      \noexpand\xP@validsoltrue
    \else
      \noexpand\xP@validsolfalse
    \fi
  }%
  }\@gtempa
}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\xP@scalerow}
% \BulletC\
% Scale a row of the matrix to improve numerical precision. We scale by a power of two such that the maximal length is between 2048pt and 4096pt.
%    \begin{macrocode}
\newcommand*\xP@scalerow[4]{%
  \xP@M\z@
  \xP@Max\xP@M#1%
  \xP@Max\xP@M#2%
  \xP@Max\xP@M#3%
  \xP@Max\xP@M#4%
%    \end{macrocode}
% $134217727=2048\cdot 65536-1$
%    \begin{macrocode}
  \count@134217727
  \loop
    \divide\xP@M\tw@
  \ifdim\xP@M>\z@
    \divide\count@\tw@
  \repeat
  \advance\count@\@ne
  \multiply#1\count@
  \multiply#2\count@
  \multiply#3\count@
  \multiply#4\count@
}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\xP@scalecol}
% \BulletC\
% Scale a column of the matrix to improve numerical precision. The scaling factor has to be recorded for the solution assignment later.
%    \begin{macrocode}
\newcommand*\xP@scalecol[4]{%
  \xP@M\z@
  \xP@Max\xP@M#1%
  \xP@Max\xP@M#2%
  \xP@Max\xP@M#3%
%    \end{macrocode}
% $16777215=2048\cdot 8192-1$
%    \begin{macrocode}
  #416777215
  \loop
    \divide\xP@M\tw@
  \ifdim\xP@M>\z@
    \divide#4\tw@
  \repeat
  \advance#4\@ne
  \multiply#1#4%
  \multiply#2#4%
  \multiply#3#4%
}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\xP@checkabs}
%    \begin{macrocode}
\newcommand*\xP@checkabs[2]{%
  \xP@ifabsless{\dimexpr#1\relax}{\dimexpr#2\relax}\else\xP@validsolfalse\fi}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\xP@applinsys}
% \BulletA\ \BulletC\ \BulletF\ This is the second, alternative algorithm for Newton's method in the offset algorithm. Approximate a solution $x$ for the linear system $Ax=b$ for a $(3\times3)$-matrix $A$. The aim is to make the norm $\|Ax-b\|$ small with small values of $\|x\|$. The approach: Set $x=\lambda A^tb$ since the normed scalar product $\langle Ax,b\rangle/\|x\|$ is maximal in this case. The norm $\|Ax-b\|$ is then minimal for $\lambda = \|A^tb\|^2/\|AA^tb\|^2$.
%
% This approximation is performed between one and three times.
%    \begin{macrocode}
\newcommand*\xP@applinsys{{%
%    \end{macrocode}
% First iteration: approximate a solution and record the result.
%    \begin{macrocode}
  \xP@applinsys@
  \xP@ta\xP@dta
  \xP@tb\xP@dtb
  \xP@tc\xP@dtc
%    \end{macrocode}
% If the result is nonzero\ldots
%    \begin{macrocode}
  \xP@checkapp
  \if@tempswa
%    \end{macrocode}
% \ldots modify the objective function by the estimated change, approximate again,\ldots
%    \begin{macrocode}
    \xP@modobj
    \xP@applinsys@
%    \end{macrocode}
% \ldots and test for a nonzero result. If it is nonzero, repeat it a third time.
%    \begin{macrocode}
    \xP@checkapp
    \if@tempswa
      \xP@modsol
      \xP@modobj
      \xP@applinsys@
      \xP@modsol
    \fi
  \fi
%    \end{macrocode}
% Return the accumulated approximation from one to three iterations.
%    \begin{macrocode}
  \xdef\@gtempa{%
    \xP@ta\the\xP@ta\relax
    \xP@tb\the\xP@tb\relax
    \xP@tc\the\xP@tc\relax
  }}\@gtempa
}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\xP@checkapp}
% \BulletF\
% Check whether the solution is nonzero.
%    \begin{macrocode}
\newcommand*\xP@checkapp{%
  \@tempswatrue
  \ifdim\xP@dta=\z@
  \ifdim\xP@dtb=\z@
  \ifdim\xP@dtc=\z@
    \@tempswafalse
  \fi\fi\fi
}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\xP@modobj}
% \BulletC\ \BulletF\
% Modify the objective function by the estimated difference, according to the first-order approximation.
%    \begin{macrocode}
\newcommand*\xP@modobj{%
  \advance\xP@D
    \dimexpr-\xP@A*\xP@dta/\p@-\xP@B*\xP@dtb/\p@-\xP@C*\xP@dtc/\p@\relax
  \advance\xP@H
    \dimexpr-\xP@E*\xP@dta/\p@-\xP@F*\xP@dtb/\p@-\xP@G*\xP@dtc/\p@\relax
  \advance\xP@L
    \dimexpr-\xP@I*\xP@dta/\p@-\xP@J*\xP@dtb/\p@-\xP@K*\xP@dtc/\p@\relax
}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\xP@modsol}
% \BulletC\ \BulletF\
% Modify the solution vector by the approximation.
%    \begin{macrocode}
\newcommand*\xP@modsol{%
  \advance\xP@ta\xP@dta
  \advance\xP@tb\xP@dtb
  \advance\xP@tc\xP@dtc
}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\xP@applinsys@}
% \BulletA\ \BulletC\ \BulletF\ The heart of the approximation routine.
%    \begin{macrocode}
\newcommand*\xP@applinsys@{{%
%    \end{macrocode}
% Determine scaling factors "\xP@sa" and "\xP@sb" to improve numerical precision.
%    \begin{macrocode}
  \xP@sa\z@
  \xP@Max\xP@sa\xP@A
  \xP@Max\xP@sa\xP@B
  \xP@Max\xP@sa\xP@C
  \xP@Max\xP@sa\xP@E
  \xP@Max\xP@sa\xP@F
  \xP@Max\xP@sa\xP@G
  \xP@Max\xP@sa\xP@I
  \xP@Max\xP@sa\xP@J
  \xP@Max\xP@sa\xP@K
  \xP@sa\ifdim\xP@sa<5460pt\thr@@\xP@sa\else\maxdimen\fi
  \xP@sb\z@
  \xP@Max\xP@sb\xP@D
  \xP@Max\xP@sb\xP@H
  \xP@Max\xP@sb\xP@L
%    \end{macrocode}
% Scale the vector $b$.
%    \begin{macrocode}
  \ifdim\xP@sb>\z@
    \xP@D\dimexpr\xP@D*\maxdimen/\xP@sb\relax
    \xP@H\dimexpr\xP@H*\maxdimen/\xP@sb\relax
    \xP@L\dimexpr\xP@L*\maxdimen/\xP@sb\relax
  \fi
%    \end{macrocode}
% Vector $A^t b$ (scaled)
%    \begin{macrocode}
  \xP@Aba\dimexpr\xP@A*\xP@D/\xP@sa+\xP@E*\xP@H/\xP@sa+\xP@I*\xP@L/\xP@sa\relax
  \xP@Abb\dimexpr\xP@B*\xP@D/\xP@sa+\xP@F*\xP@H/\xP@sa+\xP@J*\xP@L/\xP@sa\relax
  \xP@Abc\dimexpr\xP@C*\xP@D/\xP@sa+\xP@G*\xP@H/\xP@sa+\xP@K*\xP@L/\xP@sa\relax
%    \end{macrocode}
% Vector $AA^t b$ (scaled)
%    \begin{macrocode}
  \xP@AAba\dimexpr\xP@A*\xP@Aba/\xP@sa+\xP@B*\xP@Abb/\xP@sa
    +\xP@C*\xP@Abc/\xP@sa\relax
  \xP@AAbb\dimexpr\xP@E*\xP@Aba/\xP@sa+\xP@F*\xP@Abb/\xP@sa
    +\xP@G*\xP@Abc/\xP@sa\relax
  \xP@AAbc\dimexpr\xP@I*\xP@Aba/\xP@sa+\xP@J*\xP@Abb/\xP@sa
    +\xP@K*\xP@Abc/\xP@sa\relax
%    \end{macrocode}
% Another scaling factor.
%    \begin{macrocode}
  \xP@sc\z@
  \xP@Max\xP@sc\xP@Aba
  \xP@Max\xP@sc\xP@Abb
  \xP@Max\xP@sc\xP@Abc
  \xP@Max\xP@sc\xP@AAba
  \xP@Max\xP@sc\xP@AAbb
  \xP@Max\xP@sc\xP@AAbc
%    \end{macrocode}
% $\|A^tb\|^2$ and $\|AA^tb\|^2$
%    \begin{macrocode}
  \ifdim\xP@sc=\z@
    \xP@AAb\z@
  \else
    \xP@Ab\dimexpr\xP@Aba*\xP@bigdim/\xP@sc*\xP@Aba/\xP@sc
                 +\xP@Abb*\xP@bigdim/\xP@sc*\xP@Abb/\xP@sc
                 +\xP@Abc*\xP@bigdim/\xP@sc*\xP@Abc/\xP@sc
    \relax
    \xP@AAb\dimexpr\xP@AAba*\xP@bigdim/\xP@sc*\xP@AAba/\xP@sc
                  +\xP@AAbb*\xP@bigdim/\xP@sc*\xP@AAbb/\xP@sc
                  +\xP@AAbc*\xP@bigdim/\xP@sc*\xP@AAbc/\xP@sc
    \relax
  \fi
%    \end{macrocode}
% The approximation $x=\lambda A^tb$ with $\lambda = \|A^tb\|^2/\|AA^tb\|^2$.
%    \begin{macrocode}
  \xdef\@gtempa{%
    \ifdim\xP@AAb=\z@
      \xP@dta\z@
      \xP@dtb\z@
      \xP@dtc\z@
    \else
      \xP@dta\the\dimexpr\xP@Aba*\xP@sb/\xP@sa*\p@/\xP@AAb*\xP@Ab/\maxdimen
        \relax
      \xP@dtb\the\dimexpr\xP@Abb*\xP@sb/\xP@sa*\p@/\xP@AAb*\xP@Ab/\maxdimen
        \relax
      \xP@dtc\the\dimexpr\xP@Abc*\xP@sb/\xP@sa*\p@/\xP@AAb*\xP@Ab/\maxdimen
        \relax
    \fi
  }%
  }\@gtempa
}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\ifxP@offsetok}
% Switch whether the offset curve is enough
%    \begin{macrocode}
\@ifdefinable\ifxP@offsetok\relax
\@ifdefinable\xP@offsetoktrue\relax
\@ifdefinable\xP@offsetokfalse\relax
\newif\ifxP@offsetok
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\xP@maxdev}
% Maximal deviation, measured at $19$ points on the curve. The actual tolerance is $1/8$ of "\xP@maxdev". With the current value $0.1\mathrm{pt}$, the tolerance is $0.0125\mathrm{pt}$, which is about $1/32$ of the line width for the Computer Modern fonts.
%    \begin{macrocode}
\newcommand*\xP@maxdev{.1pt}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\xP@maxobjfun}
% Tolerance for the objective function. Recommended value is $\tfrac12("\xP@maxdev")^2$.
%    \begin{macrocode}
\newcommand*\xP@maxobjfun{.005pt}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\xP@testoffset}
% \BulletA\ \BulletE\ Test procedure for the offset curve. It tests whether the Bézier curve defined by the control points "\X@p",\ldots,"\Y@c" is a good approximation for the offset curve of the partial curve defined by "\xP@xa",\ldots,"\xP@yd" in the parameter interval $["\xP@a","\xP@b"]\subseteq[0\mathrm{pt},"\xP@bigdim"]$.
%
% The parameter interval is uniformly divided by $20$, and the deviation is measured at the $19$ inner positions. (Since the boundary points are offset exactly by the algorithm, they do not need to be checked.)
%
% For simplicity, the parameter interval for both curves is normalized to $[0,1]$ in the following explanations. Denote the original curve by $c_1\co[0,1]\to\mathbb{R}^2$ and the offset curve by $c_2$. The quality test is passed if the offset curve fulfills at each of the $19$ test points $t_i\in\{\tfrac1{20},\ldots,\tfrac{19}{20}\}$ one of the following two conditions:
% \begin{itemize}
% \item Let $v$ be the tangent vector $c'_1(t_i)$. For $w\coloneq c_1(t_i)-c_2(t_i)$, denote by $w_{\mathit{par}}$ the component parallel to $v$ and by $w_{\mathit{orth}}$ the component orthogonal to $v$. The test is passed if $|w_{\mathit{par}}|+|w_{\mathit{orth}}-"\xP@off"|\leq\tfrac18"\xP@maxdev"$. If $\|v\|$ is very small so that the direction cannot be determined precisely, the condition is $\bigl|\|c_1(t_i)-c_2(t_i)\|-|"\xP@off"|\bigr|\leq \tfrac18"\xP@maxdev"$.
%
% \item Compute the normal line at $t_i$ to the curve $c_1$ and intersect it with $c_2$. The intersection point is allowed to have a different parameter $\tilde t_i\in[t_i-0.5,t_i+0.5]\cap[0,1]$. Then let $w\coloneq c_1(t_i)-c_2(\tilde t_i)$ and test whether $|w_{\mathit{par}}|+|w_{\mathit{orth}}-"\xP@off"|\leq\tfrac18"\xP@maxdev"$. ($|w_{\mathit{par}}|$ is very small in this case and is nonzero only because of limited precision, in particular since $\tilde t_i$ is determined with an error of $\approx 2^{-17}$ ($=\frac12\mathrm{sp}$).)
% \end{itemize}
%    \begin{macrocode}
\newcommand*\xP@testoffset{{%
%    \end{macrocode}
% Default values for the return statement and the loop continuation.
%    \begin{macrocode}
  \gdef\xP@afteroffsetok{\xP@offsetoktrue}%
  \def\xP@offsetokif{\ifdim\xP@ti<1.85pt}%
  \xP@ti.1pt
  \loop
%    \end{macrocode}
% $"\xP@tip"=t_i$, denormalized for $c_1$
%    \begin{macrocode}
    \xP@tip\dimexpr\xP@a+(\xP@b-\xP@a)*\xP@ti/131072\relax
%    \end{macrocode}
% Point on the original curve $c_1$ (scaled by $-8$)
%    \begin{macrocode}
    \L@p-\xP@precbezierpoly\xP@xa\xP@xb\xP@xc\xP@xd\xP@tip
    \U@p-\xP@precbezierpoly\xP@ya\xP@yb\xP@yc\xP@yd\xP@tip
%    \end{macrocode}
% $8c_2(t_i)-8c_1(t_i)$
%    \begin{macrocode}
    \xP@valA\dimexpr\xP@bezierpoly\X@p\L@c\R@c\X@c\xP@ti+\L@p\relax
    \xP@valB\dimexpr\xP@bezierpoly\Y@p\U@c\D@c\Y@c\xP@ti+\U@p\relax
%    \end{macrocode}
% $v$
%    \begin{macrocode}
    \d@X3\xP@precbeziertan\xP@xa\xP@xb\xP@xc\xP@xd\xP@tip
    \d@Y3\xP@precbeziertan\xP@ya\xP@yb\xP@yc\xP@yd\xP@tip
    \xP@veclen
%    \end{macrocode}
% Decide if $v$ is big enough (heuristically, may be changed in the future)
%    \begin{macrocode}
    \@tempdimc\dimexpr(\xP@b-\xP@a)*\@tempdimb/\xP@bigdim\relax
    \xP@abs\@tempdimc
    \ifdim.01pt<\@tempdimc
%    \end{macrocode}
% $8w_{\mathit{par}}$, $8w_{\mathit{orth}}-8"\xP@off"$,
%    \begin{macrocode}
      \xP@devA\dimexpr\xP@valA*\d@X/\@tempdimb+\xP@valB*\d@Y/\@tempdimb\relax
      \xP@devB\dimexpr\xP@valA*\d@Y/\@tempdimb-\xP@valB*\d@X/\@tempdimb-8\xP@off
        \relax
      \xP@abs\xP@devA
      \xP@abs\xP@devB
      \@tempdima\dimexpr\xP@devA+\xP@devB\relax
    \else
%    \end{macrocode}
% If the velocity is zero, just pass the test.
%    \begin{macrocode}
      \ifdim\@tempdimc=\z@
        \@tempdima\z@
      \else
%    \end{macrocode}
% $8\|c_1(t_i)-c_2(t_i)\|$
%    \begin{macrocode}
        {%
        \d@X\xP@valA
        \d@Y\xP@valB
        \xP@veclen@
        \global\dimen@i\@tempdimb
        }\@tempdima\dimen@i
        \advance\@tempdima\ifdim\xP@off>\z@-\fi8\xP@off
        \xP@abs\@tempdima
      \fi
    \fi
%    \end{macrocode}
% If the first condition is not fulfilled, test the second one.
%    \begin{macrocode}
    \ifdim\@tempdima>\xP@maxdev
%    \end{macrocode}
% $c_1(t_i)$
%    \begin{macrocode}
      \divide\L@p8\relax
      \divide\U@p8\relax
%    \end{macrocode}
% Affine transformation of the offset curve: translate by $-c_1(t_i)$ and rotate so that the tangent $v$ to $c_1(t_i)$ becomes the $x$-axis.
%    \begin{macrocode}
      {%
      \xP@transformcoor\X@p\Y@p
      \xP@transformcoor\L@c\U@c
      \xP@transformcoor\R@c\D@c
      \xP@transformcoor\X@c\Y@c
%    \end{macrocode}
% Find the parameter $\tilde t_i$ and decide whether the approximation at $\tilde t_i$ is good.
%    \begin{macrocode}
      \xP@findzero
      }%
    \fi
  \xP@offsetokif
    \advance\xP@ti.1pt
  \repeat
  \expandafter}\xP@afteroffsetok
}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\xP@afteroffsetok}
%    \begin{macrocode}
\newcommand*\xP@afteroffsetok{}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\xP@offsetokif}
%    \begin{macrocode}
\newcommand*\xP@offsetokif{}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\xP@transformcoor}
% \BulletE\
% Affine coordinate transformation. First, translate the coordinates in $("#1","#2")$ by the vector $-("\L@p","\U@p")$, then rotate by the angle between $v\coloneq("\d@X","\d@Y")$ and $(1,0)$. The register "\@tempdimb" must contain the length $\|v\|$.
%    \begin{macrocode}
\newcommand*\xP@transformcoor[2]{%
  \advance#1\L@p
  \advance#2\U@p
  \@tempdima\dimexpr#1*\d@X/\@tempdimb+#2*\d@Y/\@tempdimb\relax
  #2\dimexpr#2*\d@X/\@tempdimb-#1*\d@Y/\@tempdimb\relax
  #1\@tempdima
}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\xP@findzero}
% \BulletE\
% Find the parameter $\tilde t_i$ by nested intervals/intermediate value theorem.
%    \begin{macrocode}
\newcommand*\xP@findzero{%
  \xP@setleftvalue{.05}%
  \xP@setrightvalue{.05}%
%    \end{macrocode}
% Normalize: function value ($x$-coordinate) should be nonnegative at the upper end.
%    \begin{macrocode}
  \ifdim\xP@valB<\z@\xP@reversecoeff\fi
%    \end{macrocode}
% If the function value at the lower end is also positive, try a smaller parameter interval $t_i\pm\delta\,\mathrm{pt}$ for $\delta\in\{.5,.35,.25,.2,.15,.1,.05\}$. Maybe we have different signs for the $x$-coordinate for the larger boundary parameters.
%    \begin{macrocode}
  \ifdim\xP@valA>\z@
    \@tempswatrue
    \@for\@tempa:={.1,.15,.2,.25,.35,.5,1.1}\do{%
      \if@tempswa
        \xP@setleftvalue\@tempa
        \ifdim\xP@valA<\z@\@tempswafalse\fi
        \if@tempswa
          \xP@setrightvalue\@tempa
          \ifdim\xP@valB<\z@
            \@tempswafalse
            \xP@reversecoeff
          \fi
        \fi
      \fi
    }%
%    \end{macrocode}
% Last resort: Try the midpoint.
%    \begin{macrocode}
    \if@tempswa
      \L@p\xP@ti
      \xP@valA\xP@bezierpoly\X@p\L@c\R@c\X@c\L@p
%    \end{macrocode}
% If the midpoint leads to a negative value, we can proceed with a small interval. Otherwise, set both boundary points to the midpoint and effectively skip nested intervals.
%    \begin{macrocode}
      \ifdim\xP@valA<\z@
%    \end{macrocode}
% We had this before, so we know that the value is positive.
%    \begin{macrocode}
        \xP@setrightvalue{.05}%
      \else
        \U@p\L@p
        \xP@valB\xP@valA
      \fi
    \fi
  \fi
%    \end{macrocode}
% The actual nested interval algorithm
%    \begin{macrocode}
  \loop
  \ifnum\numexpr\U@p-\L@p\relax>\@ne
    \xP@ti\dimexpr(\L@p+\U@p)/2\relax
    \xP@devA\xP@bezierpoly\X@p\L@c\R@c\X@c\xP@ti
    \ifdim\xP@devA>\z@
      \U@p\xP@ti
      \xP@valB\xP@devA
    \else
      \L@p\xP@ti
      \xP@valA\xP@devA
    \fi
  \repeat
%    \end{macrocode}
% Take the left or right boundary point (only $1\mathrm{sp}$ apart), depending on which one yields the smaller $x$-coordinate.
%    \begin{macrocode}
  \xP@ifabsless\xP@valB\xP@valA
    \L@p\U@p
    \xP@valA\xP@valB
  \fi
%    \end{macrocode}
% Compare the $y$-coordinate with "\xP@off".
%    \begin{macrocode}
  \xP@valB\dimexpr\xP@bezierpoly\Y@p\U@c\D@c\Y@c\L@p+8\xP@off\relax
  \xP@abs\xP@valA
  \xP@abs\xP@valB
  \ifdim\dimexpr\xP@valA+\xP@valB\relax>\xP@maxdev\relax
    \xP@failed
  \fi
}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\xP@failed}
% Break the loop for the $t_i$ in "\xP@testoffset". Set the return value to false.
%    \begin{macrocode}
\newcommand*\xP@failed{%
  \global\let\xP@offsetokif\iffalse
  \gdef\xP@afteroffsetok{\xP@offsetokfalse}%
}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\xP@reversecoeff}
% Reverse the function for the nested interval algorithm.
%    \begin{macrocode}
\newcommand*\xP@reversecoeff{%
    \multiply\X@p\m@ne
    \multiply\L@c\m@ne
    \multiply\R@c\m@ne
    \multiply\X@c\m@ne
    \multiply\xP@valA\m@ne
    \multiply\xP@valB\m@ne
}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\xP@setleftvalue}
% \BulletE
%    \begin{macrocode}
\newcommand*\xP@setleftvalue[1]{%
  \L@p\dimexpr\xP@ti-#1\p@\relax
  \ifdim\L@p<-.1pt\L@p-.1pt\fi
  \xP@valA\xP@bezierpoly\X@p\L@c\R@c\X@c\L@p
}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\xP@setrightvalue}
% \BulletE
%    \begin{macrocode}
\newcommand*\xP@setrightvalue[1]{%
  \U@p\dimexpr\xP@ti+#1\p@\relax
  \ifdim\U@p>2.1\p@\U@p2.1\p@\fi
  \xP@valB\xP@bezierpoly\X@p\L@c\R@c\X@c\U@p
}
%    \end{macrocode}
% \end{macro}
%
% \subsection{Multiple dashed curves}
%
% \begin{macro}{\xP@splinedbldashed}
%    \begin{macrocode}
\newcommand*\xP@splinedbldashed{%
  \xP@checkspline\xP@splinemultdashed\xP@doublestroke}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\xP@splinetrbldashed}
%    \begin{macrocode}
\newcommand*\xP@splinetrbldashed{%
  \xP@checkspline\xP@splinemultdashed\xP@trblstroke}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\xP@splinemultdashed}
%    \begin{macrocode}
\newcommand*\xP@splinemultdashed[1]{%
%    \end{macrocode}
% Expected dash number. It is an even number if the spline is the continuation of the previous one, otherwise (default case) an odd number.
%    \begin{macrocode}
  \xP@testcont\xP@dashmacro
  \@tempcnta
  \ifxP@splinecont
    \numexpr2*((\@tempdimb-\xydashl@/3)/(2*\xydashl@))\relax
  \else
    \numexpr2*((\@tempdimb+\xydashl@)/(2*\xydashl@))-1\relax
  \fi
  \ifnum\@tempcnta>\@ne
    \xP@splinemultdashed@#1%
  \else
%    \end{macrocode}
% One dash: paint a solid line. Less than one dash: Leave the segment out, just record the end point.
%    \begin{macrocode}
    \ifnum\@tempcnta=\@ne
      \xP@splinemultsolid#1
    \else
      \xP@savec
    \fi
  \fi
  \global\let\xP@lastpattern\xP@dashmacro
}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\xP@splinemultdashed@}
% \BulletA\ \BulletG\ Make a list of parameter pairs for the start and end point of a dash.
%    \begin{macrocode}
\newcommand*\xP@splinemultdashed@[1]{{%
  \xP@inibigdim
%    \end{macrocode}
% Dash length
%    \begin{macrocode}
  \@tempdima\dimexpr\@tempdimb/\@tempcnta\relax
  \xP@temppar\z@
  \toks@{}%
  \xP@savec
  \ifodd\@tempcnta
  \else
    \xP@slide
  \fi
  \@tempcnta\z@
  \loop
    \advance\@tempcnta\@ne
    \xP@append\toks@{\ifodd\@tempcnta\noexpand\xP@paintdash\fi
      {\the\xP@temppar}}%
    \xP@oldpar\xP@temppar
    \xP@slide
  \ifdim\xP@temppar<\xP@bigdim
  \repeat
%    \end{macrocode}
% The last position is kept as a scaling factor so that the last dot can be drawn at exactly the parameter $1$. Use the last or the next-to-last position, depending on the parity of segments.
%    \begin{macrocode}
  \xP@lastpar
    \ifodd\@tempcnta
      \xP@temppar
      \xP@append\toks@{{\the\xP@temppar}}%
    \else
      \xP@oldpar
    \fi
%    \end{macrocode}
% Convert the list of parameters to a list of PDF tokens.
%    \begin{macrocode}
  \@temptokena{}%
  \xP@setsolidpat
  \global\let\xP@lastpattern\xP@dashmacro
  \@for\@tempa:={#1}\do{\the\toks@}%
  \xP@stroke{\the\@temptokena}%
}}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\xP@paintdash}
% \BulletA\ \BulletG
%    \begin{macrocode}
\newcommand*\xP@paintdash[2]{%
  \xP@paintsolid{\dimexpr#1*\xP@bigdim/\xP@lastpar\relax}%
    {\dimexpr#2*\xP@bigdim/\xP@lastpar\relax}%
}
%    \end{macrocode}
% \end{macro}
%
% \subsection{Multiple dotted curves}
%
% \begin{macro}{\splinedbldotted@}
% \begin{macro}{\xP@splinedbldotted@}
%    \begin{macrocode}
\xP@hook{splinedbldotted@}
\newcommand*\xP@splinedbldotted@{%
  \let\xP@normalmult\@ne
  \xP@checkspline\xP@splinemultdotted\xP@doublestroke}
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \begin{macro}{\xP@splinetrbldotted}
%    \begin{macrocode}
\newcommand*\xP@splinetrbldotted{%
  \let\xP@normalmult\tw@
  \xP@checkspline\xP@splinemultdotted\xP@trblstroke}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\xP@multidottedpat}
% Dotted lines with multiple strokes are drawn in a different way from single-stroked lines. They are composed of many small, straight lines normal to the curve at every dot position. Hence, the dot pattern for multiple curves has dots which are spaced by the normal distance between strokes.
%    \begin{macrocode}
\newcommand*\xP@multidottedpat{%
  \def\xP@pattern{0 J [\xP@lw\xP@dim{\xydashh@-\xP@preclw}]0 d}%
  \global\let\xP@lastpattern\xP@dotmacro
}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\xP@normalmult}
%    \begin{macrocode}
\@ifdefinable\xP@normalmult\relax
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\xP@splinemultdotted}
% \BulletA\ \BulletG
%    \begin{macrocode}
\newcommand\xP@splinemultdotted[1]{{%
  \xP@inibigdim
%    \end{macrocode}
% Make a list of dot positions on the spline segment.
%    \begin{macrocode}
  \xP@temppar\z@
  \xP@testcont\xP@dotmacro
  \ifxP@splinecont
%    \end{macrocode}
% Expected dot distance (see the formula in "\xP@setdottedpat")
%    \begin{macrocode}
    \@tempdimc\dimexpr\@tempdimb/(\@tempdimb/131072+1)\relax
    \@tempdima\dimexpr\@tempdimc-\xP@preclw/2\relax
    \xP@slide
    \@tempdima\@tempdimc
  \else
    \@tempdima\dimexpr\xP@preclw/2\relax
    \xP@slide
%    \end{macrocode}
% Expected dot distance (see the formula in "\xP@setdottedpat")
%    \begin{macrocode}
    \@tempdima\dimexpr\@tempdimb-\xP@preclw\relax
    \ifdim\@tempdima<\z@\@tempdima\z@\fi
    \@tempdima\dimexpr\@tempdima/(\@tempdima/131072+1)\relax
  \fi
  \xP@savec
  \toks@{}%
%    \end{macrocode}
% If the end of the segment is reached before the first dot position, leave the segment out.
%    \begin{macrocode}
  \ifdim\xP@temppar<\xP@bigdim
    \loop
      \xP@append\toks@{\noexpand\xP@paintdot{\the\xP@temppar}}%
      \xP@oldpar\xP@temppar
      \xP@slide
    \ifdim\xP@temppar<\xP@bigdim
    \repeat
    \xP@velocity\xP@bigdim\xP@tempvel
%    \end{macrocode}
% Test whether the last or the next-to-last dot is closer to "\xP@bigdim". Measure from the end of the dot, hence the contribution of "\xP@preclw". Also consider the case that the velocity at the end point is very small. In this case, always choose the next-to-last dot as the final one.
%    \begin{macrocode}
    \ifdim
      \ifdim\xP@preclw<\xP@tempvel
        \dimexpr2\xP@bigdim-\xP@oldpar-\xP@preclw*\xP@bigdim/\xP@tempvel\relax
      \else
        -\maxdimen
      \fi<\xP@temppar
      \xP@temppar\xP@oldpar
    \else
      \xP@append\toks@{\noexpand\xP@paintdot{\the\xP@temppar}}%
    \fi
    \@tempdima\dimexpr\xP@preclw/2\relax
    \xP@slide
    \xP@lastpar\xP@temppar
%    \end{macrocode}
% Convert the list of parameters to a list of PDF tokens.
%    \begin{macrocode}
    \@temptokena{}%
    \the\toks@
%    \end{macrocode}
% Actually draw the points in the list.
%    \begin{macrocode}
    \xP@multidottedpat
    \xP@stroke{\the\@temptokena}%
  \else
%    \end{macrocode}
% Leave the segment out because it is too short.
%    \begin{macrocode}
    \global\let\xP@lastpattern\empty
  \fi
}}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\xP@slide}
% \BulletA\ \BulletG\ Slide along the Bézier segment by "\@tempdima". Needs: \Xy-pic spline parameter, current position parameter "\xP@temppar", total spline length "\@tempdimb".
%    \begin{macrocode}
\newcommand*\xP@slide{{%
  \xP@slide@
%    \end{macrocode}
% Return the new spline parameter after sliding.
%    \begin{macrocode}
  \global\dimen@i\xP@temppar
  }\xP@temppar\dimen@i
}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\xP@slide@}
% \BulletA\ \BulletG
%    \begin{macrocode}
\newcommand*\xP@slide@{%
%    \end{macrocode}
% Compute the velocity at two points, the starting point and an estimate for the end point.
%    \begin{macrocode}
  \xP@velocity\xP@temppar\xP@tempvel
%    \end{macrocode}
% The first estimate for the parameter increment is based on the total spline length.
%    \begin{macrocode}
  \@tempdimc\dimexpr\xP@bigdim*\@tempdima/\@tempdimb\relax
  \count@\z@
  \@tempswatrue
%    \end{macrocode}
% Improve the parameter increment iteratively.
%    \begin{macrocode}
  \loop
%    \end{macrocode}
% Velocity at the estimated end point.
%    \begin{macrocode}
    \xP@velocity{\xP@temppar+\@tempdimc}\xP@tempvel@
%    \end{macrocode}
% Prevent arithmetic overflow.
%    \begin{macrocode}
    \ifdim\dimexpr\@tempdima*4/13\relax>\xP@tempvel@
      \@tempswafalse
    \else
%    \end{macrocode}
% Difference to the old parameter increment. This is Newton's method, applied to the estimated spline length based on the velocities "\xP@tempvel" and "\xP@tempvel@" at "\xP@temppar" and $("\xP@temppar"+"\@tempdimc")$.
%    \begin{macrocode}
      \xP@parinc\dimexpr\@tempdima*\xP@bigdim/\xP@tempvel@
        -(\xP@tempvel+\xP@tempvel@)/2*\@tempdimc/\xP@tempvel@\relax
      \advance\@tempdimc\xP@parinc
%    \end{macrocode}
% If the estimated parameter increment is bigger than $.12$, increase the parameter by $.1$ and slide only partially. This increases the precision if the parameter increment is big.
%    \begin{macrocode}
      \ifdim\@tempdimc>.12\xP@bigdim
        \@tempswafalse
      \else
%    \end{macrocode}
% If the estimate is not improved, break the loop.
%    \begin{macrocode}
        \ifdim\xP@parinc=\z@
          \@tempswafalse
        \else
%    \end{macrocode}
% Also break the loop after $10$ iterations.
%    \begin{macrocode}
           \ifnum\count@=9\relax
             \@tempswafalse
           \fi
        \fi
      \fi
    \fi
  \if@tempswa
    \advance\count@\@ne
  \repeat
%    \end{macrocode}
% Note that "\if@tempswa" is always false here.
%
% If the parameter increment would be more than $.1$ and if the parameter is not too big already, increase the parameter by $.1$ and slide again.
%    \begin{macrocode}
  \ifdim\xP@temppar<5461pt
  \ifdim\@tempdimc>.1\xP@bigdim
    \@tempswatrue
  \fi
  \fi
  \if@tempswa
    {%
      \dimen5\xP@temppar
      \advance\xP@temppar.1\xP@bigdim
%    \end{macrocode}
% Cap the end parameter to prevent arithmetic overflows.
%    \begin{macrocode}
      \ifdim\xP@temppar>5461pt\xP@temppar5461pt\fi
      \dimen7\xP@temppar
%    \end{macrocode}
% Determine the exact distance of the partial slide.
%    \begin{macrocode}
      \xP@shaveprec{\dimen5}{\dimen7}%
      \xP@bezierlength
      \global\dimen@i\dimexpr\@tempdima-\@tempdimb\relax
      \global\dimen3\xP@temppar
    }%
    \@tempdima\dimen@i
    \xP@temppar\dimen3\relax
%    \end{macrocode}
% Slide again.
%    \begin{macrocode}
    \expandafter\xP@slide@
  \else
%    \end{macrocode}
% Finish the slide and return the new parameter.
%    \begin{macrocode}
    \advance\xP@temppar\@tempdimc
  \fi
}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\xP@paintdot}
% \BulletA\ \BulletG
%    \begin{macrocode}
\newcommand*\xP@paintdot[1]{%
%    \end{macrocode}
% Scale the parameter with a correction factor
%    \begin{macrocode}
  \@tempdima\dimexpr#1*\xP@bigdim/\xP@lastpar\relax
%    \end{macrocode}
% Position at parameter value "\xP@temppar"
%    \begin{macrocode}
  \xP@tangent
  \xP@posX\dimexpr\xP@precbezierpoly\X@p\L@c\R@c\X@c\@tempdima/8\relax
  \xP@posY\dimexpr\xP@precbezierpoly\Y@p\U@c\D@c\Y@c\@tempdima/8\relax
%    \end{macrocode}
% Normal vector to the curve with length "\xydashh@"
%    \begin{macrocode}
  \@tempdima\dimexpr(\xydashh@+\xP@preclw/\xP@normalmult)/2\relax
  \L@p\dimexpr\d@Y*\@tempdima/\@tempdimb\relax
  \U@p\dimexpr-\d@X*\@tempdima/\@tempdimb\relax
%    \end{macrocode}
% Append two points on both sides of the curve to the list. (The “multidottedpat” pattern is made to draw points with distance "\xydashh@".)
%    \begin{macrocode}
  \xP@append\@temptokena{\xP@coor{\xP@posX+\L@p*\xP@normalmult}%
      {\xP@posY+\U@p*\xP@normalmult}m %
    \xP@coor{\xP@posX-\L@p*(\xP@normalmult+\@ne)}%
      {\xP@posY-\U@p*(\xP@normalmult+\@ne)}l }%
}
%    \end{macrocode}
% \end{macro}
%
% \subsection{Squiggled curves}
%
% \begin{macro}{\xP@splinesquiggled}
%    \begin{macrocode}
\newcommand*\xP@splinesquiggled{%
  \xP@checkspline\xP@splinesquiggled@\z@}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\xP@splinedblsquiggled}
%    \begin{macrocode}
\newcommand*\xP@splinedblsquiggled{%
  \xP@checkspline\xP@splinesquiggled@\xP@doublestroke}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\xP@splinetrblsquiggled}
%    \begin{macrocode}
\newcommand*\xP@splinetrblsquiggled{%
  \xP@checkspline\xP@splinesquiggled@\xP@trblstroke}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\xP@splinesquiggled@}
% \BulletA\ \BulletG
%    \begin{macrocode}
\newcommand*\xP@splinesquiggled@[1]{{%
      \xP@inibigdim
%    \end{macrocode}
% Reverse the direction of the little arcs, if the last squiggle from the previous segment makes it necessary.
%    \begin{macrocode}
      \xP@testcont\xP@oddsquigglemacro
      \ifxP@splinecont
        \def\xP@squigsign{-}%
      \else
        \let\xP@squigsign\empty
      \fi
      \xP@savec
%    \end{macrocode}
% Expected squiggle length
%    \begin{macrocode}
      \@tempcnta=\numexpr\@tempdimb/\xybsqll@\relax
      \ifnum\@tempcnta<\tw@\@tempcnta\tw@\fi
      \multiply\@tempcnta\tw@
      \@tempdima\dimexpr\@tempdimb/\@tempcnta\relax
      \xP@squiglen\@tempdima
%    \end{macrocode}
% Make a list of dot positions on the spline segment.
%    \begin{macrocode}
      \xP@temppar\z@
      \toks@{}%
      \@tempcnta\z@
      \loop
        \advance\@tempcnta\@ne
        \xP@append\toks@{\noexpand\xP@paintsquiggle{\the\xP@temppar}}%
        \xP@oldpar\xP@temppar
        \xP@slide
      \ifdim\xP@temppar<\xP@bigdim
      \repeat
%    \end{macrocode}
% The last position is kept as a scaling factor so that the last dot can be drawn at exactly the parameter $1$. Use the last or the next-to-last position, on the parity of the number of positions.
%    \begin{macrocode}
      \xP@lastpar
        \ifodd\@tempcnta
          \xP@oldpar
          \advance\@tempcnta\m@ne
        \else
          \xP@temppar
          \xP@append\toks@{\noexpand\xP@paintsquiggle{\the\xP@temppar}}%
        \fi
%    \end{macrocode}
% Convert the list of parameters to a list of PDF tokens.
%    \begin{macrocode}
      \@temptokena{}%
      \xP@setsolidpat
%    \end{macrocode}
% Record the direction of the last squiggle.
%    \begin{macrocode}
      \global\expandafter\let\expandafter\xP@lastpattern
      \ifodd\numexpr\@tempcnta/2\if\xP@squigsign-+1\fi\relax
        \xP@oddsquigglemacro
      \else
        \xP@evensquigglemacro
      \fi
%    \end{macrocode}
% Draw the squiggles.
%    \begin{macrocode}
      \@for\@tempa:={#1}\do{%
        \let\xP@dosquiggle\xP@dosquiggle@
        \count@\z@
        \the\toks@
      }%
      \xP@stroke{\the\@temptokena}%
}}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\xP@paintsquiggle}
% \BulletA\ \BulletG
%    \begin{macrocode}
\newcommand*\xP@paintsquiggle[1]{%
%    \end{macrocode}
% Scale the parameter with a correction factor
%    \begin{macrocode}
  \@tempdima\dimexpr#1*\xP@bigdim/\xP@lastpar\relax
%    \end{macrocode}
% Position at parameter value "\xP@temppar", offset for multiple curves.
%    \begin{macrocode}
  \xP@tangent
  \xP@posX\dimexpr\xP@precbezierpoly\X@p\L@c\R@c\X@c\@tempdima/8%
    -\d@Y*(\@tempa)/\@tempdimb\relax
  \xP@posY\dimexpr\xP@precbezierpoly\Y@p\U@c\D@c\Y@c\@tempdima/8%
    +\d@X*(\@tempa)/\@tempdimb\relax
%    \end{macrocode}
% Tangent vector to the curve with correct length
%    \begin{macrocode}
  \L@p\dimexpr\d@X*\xP@squiglen/\@tempdimb\relax
  \U@p\dimexpr\d@Y*\xP@squiglen/\@tempdimb\relax
  \R@p\dimexpr\L@p*543339720/1311738121\relax
  \D@p\dimexpr\U@p*543339720/1311738121\relax
  \X@min\dimexpr\L@p*362911648/967576667\relax
  \Y@min\dimexpr\U@p*362911648/967576667\relax
  \X@max\dimexpr(\L@p+\xP@squigsign\U@p)*173517671/654249180\relax
  \Y@max\dimexpr(\L@p-\xP@squigsign\U@p)*173517671/654249180\relax
%    \end{macrocode}
%    \begin{macrocode}
  \xP@dosquiggle
  \ifnum\count@=\thr@@\relax\count@\z@\else\advance\count@\@ne\fi
}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\xP@dosquiggle}
% \BulletG
%    \begin{macrocode}
\@ifdefinable\xP@dosquiggle@\relax
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\xP@dosquiggle@}
% \BulletG
%    \begin{macrocode}
\newcommand*\xP@dosquiggle@{%
  \edef\next@{\xP@coor{\xP@posX}{\xP@posY}m
    \xP@coor{\xP@posX+\Y@max}{\xP@posY+\xP@squigsign\X@max}%
  }%
  \let\xP@dosquiggle\xP@dosquiggle@@
}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\xP@dosquiggle@@}
% \BulletG
%    \begin{macrocode}
\newcommand*\xP@dosquiggle@@{%
  \xP@append\@temptokena{\next@\expandafter\xP@coor
    \ifcase\count@
      {\xP@posX-\Y@max}{\xP@posY-\xP@squigsign\X@max}%
      \xP@coor\xP@posX\xP@posY
    \or
      {\xP@posX-\xP@squigsign\D@p-\X@min}{\xP@posY+\xP@squigsign\R@p-\Y@min}%
      \xP@coor{\xP@posX-\xP@squigsign\D@p}{\xP@posY+\xP@squigsign\R@p}%
    \or
      {\xP@posX-\X@max}{\xP@posY+\xP@squigsign\Y@max}%
      \xP@coor\xP@posX\xP@posY
    \or
      {\xP@posX+\xP@squigsign\D@p-\X@min}{\xP@posY-\xP@squigsign\R@p-\Y@min}%
      \xP@coor{\xP@posX+\xP@squigsign\D@p}{\xP@posY-\xP@squigsign\R@p}%
    \fi c }%
  \edef\next@{\expandafter\xP@coor
    \ifcase\count@
      {\xP@posX+\Y@max}{\xP@posY+\xP@squigsign\X@max}%
    \or
      {\xP@posX-\xP@squigsign\D@p+\X@min}{\xP@posY+\xP@squigsign\R@p+\Y@min}%
    \or
      {\xP@posX+\X@max}{\xP@posY-\xP@squigsign\Y@max}%
    \or
      {\xP@posX+\xP@squigsign\D@p+\X@min}{\xP@posY-\xP@squigsign\R@p+\Y@min}%
    \fi
  }%
}
%    \end{macrocode}
% \end{macro}
%
% End of the section for \Xy-pic's “curve” option.
%    \begin{macrocode}
\xP@endgobble
%    \end{macrocode}
%
% \subsection{Spline continuation}
%
% The following code handles the spline continuation (see \autoref{beziercont}). We introduce global macros which store the last end point of a Bézier segment. If the next segment continues at exactly the same coordinates, the dash/dot/squiggle patterns recognize the continuation.
% \begin{macro}{\xP@lastX}
% \begin{macro}{\xP@lastY}
% \begin{macro}{\xP@lastpattern}
%    \begin{macrocode}
\newcommand*\xP@lastX{}
\newcommand*\xP@lastY{}
\newcommand*\xP@lastpattern{}
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
% \begin{macro}{\xP@solidmacro}
% \begin{macro}{\xP@dotmacro}
% \begin{macro}{\xP@dashmacro}
% \begin{macro}{\xP@evensquigglemacro}
% \begin{macro}{\xP@oddsquigglemacro}
%    \begin{macrocode}
\newcommand*\xP@solidmacro{solid}
\newcommand*\xP@dotmacro{dot}
\newcommand*\xP@dashmacro{dash}
\newcommand*\xP@evensquigglemacro{evensquiggle}
\newcommand*\xP@oddsquigglemacro{oddsquiggle}
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \begin{macro}{\xy}
% Reset the last position with every new diagram.
%    \begin{macrocode}
\CheckCommand*\xy{\ifmmode\expandafter\xymath@\else\expandafter\xynomath@\fi}
\renewcommand*\xy{%
  \global\let\xP@lastpattern\empty
  \ifmmode\expandafter\xymath@\else\expandafter\xynomath@\fi}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\xP@savec}
% Save the current end point
%    \begin{macrocode}
\newcommand*\xP@savec{%
  \xdef\xP@lastX{\the\X@c}%
  \xdef\xP@lastY{\the\Y@c}%
}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\ifxP@splinecont}
% Switch: does the next line/spline continue at the end point of the last one?
%    \begin{macrocode}
\@ifdefinable\ifxP@splinecont\relax
\@ifdefinable\xP@splineconttrue\relax
\@ifdefinable\xP@splinecontfalse\relax
\newif\ifxP@splinecont
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\xP@testcont}
% Test for "\ifxP@splinecont"
%    \begin{macrocode}
\newcommand*\xP@testcont[1]{%
  \xP@splinecontfalse
  \ifxP@cont
    \ifx\xP@lastpattern#1%
      \ifdim\xP@lastX=\X@p
        \ifdim\xP@lastY=\Y@p
          \xP@splineconttrue
        \fi
      \fi
    \fi
  \fi
}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\ifxP@cont}
% Switch: shall the spline hack be applied? 
%    \begin{macrocode}
\@ifdefinable\ifxP@cont\relax
\@ifdefinable\xP@conttrue\relax
\@ifdefinable\xP@contfalse\relax
\newif\ifxP@cont
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\xypdfcontpatternon}
% \begin{macro}{\xypdfcontpatternoff}
%    \begin{macrocode}
\newcommand*\xypdfcontpatternon{\xP@conttrue}
\newcommand*\xypdfcontpatternoff{\xP@contfalse}
\xP@conttrue
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \section{Changelog}
%
% \begin{description}
% \item[v1.0] 2010/03/24
%
% Initial version
%
% \item[v1.1] 2010/03/30
% \begin{itemize}
% \item Added support for the \Xy-pic “rotate” extension.
%
% \item The parts of the style file dealing with \Xy-pic extensions (currently “curve” and “rotate”) are only executed when those extension were loaded.
%
% \item \textsf{xypdf} does not give an error message when used with \Xy-pic options which query the Postscript drivers (e.\,g.\ “all” or “color”).
%
% \item In DVI mode, a warning is issued that the DVI file is not portable, like \Xy-pic does when a Postscript driver is in use.
%
% \end{itemize}
%
% \item[v1.2] 2010/04/08
% \begin{itemize}
% \item Improved precision and numerical stability for the offset algorithm around cusps.
% \item Improved slide algorithm "\xP@slide@"
% \item Respect "\pdfdecimaldigits" when dimensions are written to the PDF file.
% \item Correct continuation for dashed/dotted/squiggled curves consisting of more than one segment.
% \item Code cleanup
% \end{itemize}
%
% \item[v1.3] 2010/04/12
% \begin{itemize}
% \item Bug fix: No “"Extra \fi"” if "\ifpdfabsdim" is not defined.
% \item Bug fix: Moved the code for the spline continuation out of the optional section for curves since it is also needed for straight lines.
% \item Check the version of pdf\TeX{} since "\pdfsave" is not defined prior to pdf\TeX{} 1.40.0.
% \item \hyperref[sec:trouble]{“Troubleshooting”} paragraph for \TeX{} Live without the $\varepsilon$-\TeX{} features enabled.
% \item Generic PDF code for the "{-}" directional object.
% \end{itemize}
% \end{description}
% \Finale
\endinput 