summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/source
diff options
context:
space:
mode:
authorKarl Berry <karl@freefriends.org>2010-03-28 00:39:37 +0000
committerKarl Berry <karl@freefriends.org>2010-03-28 00:39:37 +0000
commit6173c05a5e76ce42b153a2e7664ad2ddba566112 (patch)
tree3d8d5fd513abb93b76cbf5227bd29479a724eba8 /Master/texmf-dist/source
parent49b4790fd92979a66a8024fe83a0338c0c0b3949 (diff)
new latex package xypdf 1.0 (27mar10)
git-svn-id: svn://tug.org/texlive/trunk@17580 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist/source')
-rw-r--r--Master/texmf-dist/source/latex/xypdf/xypdf.dtx3399
-rw-r--r--Master/texmf-dist/source/latex/xypdf/xypdf.ins117
2 files changed, 3516 insertions, 0 deletions
diff --git a/Master/texmf-dist/source/latex/xypdf/xypdf.dtx b/Master/texmf-dist/source/latex/xypdf/xypdf.dtx
new file mode 100644
index 00000000000..01609dd9048
--- /dev/null
+++ b/Master/texmf-dist/source/latex/xypdf/xypdf.dtx
@@ -0,0 +1,3399 @@
+%\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 - The distribution guide
+% xypdf.dtx - Documented source code
+% xypdf.ins - Installation script
+% xypdf.sty - LaTeX style file
+% xypdf.pdf - Documentation
+%
+% \fi
+%
+% \iffalse
+%<package>\NeedsTeXFormat{LaTeX2e}
+%<package>\ProvidesPackage{xypdf}
+%<package> [2010/03/24 v1.0 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]{xy}
+\usepackage{xypdf}
+\newsavebox\mybox
+\makeatletter
+% Parameter #1: scaling factor
+% Parameter #2: Box content
+\newcommand*\scalebox[2]{%
+ \sbox\mybox{#2}%
+ \xP@literal{q #1 0 0 #1 0 0 cm}%
+ % Zero-sized box with the scaled content
+ \vbox to\z@{\vss\hbox to \z@{\usebox\mybox\hss}}%
+ \xP@literal{Q}%
+ % Dummy box for correct spacing
+ \hbox to#1\wd\mybox{\vrule width\z@ height#1\ht\mybox depth#1\dp\mybox\hss}%
+}
+\makeatother
+\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{4941}
+%
+% \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,\@gtempb,\@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,
+% \line@,\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) and 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 figure.
+% \newcommand*\testdiag{\scalebox{10}{\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}}
+% \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:
+% \makeatletter
+% \newcommand\showline[1]{{\xypdfoff#1}&{\xypdfon#1}}
+% \makeatother
+% \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}
+% \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
+% Code for the “line styles” extension.
+%
+% \item
+% Code for scaling and rotating diagrams.
+%
+% \end{itemize}
+%
+% \section{Caveat}
+%
+% Since the dashes in Bézier segments are aligned to the boundary points, this results in dashes of double length when a curve is composed of several Bézier segments. The original \Xy-pic draws two dashes on top of each other at these positions.
+% \newcommand*\mydiag{}
+% \begin{center}
+% \begin{tabular}{@{}cc@{}}
+% without \textsf{xypdf}& with \textsf{xypdf}\\
+% \midrule
+% \showline{\xy(0,0);(50,0)**\crv{~**\dir{--}(10,0)&(20,15)&(30,15)&(40,0)}\endxy}\\
+% \end{tabular}
+% \end{center}
+% code:
+% \begin{verbatim}
+%\xy (0,0);(50,0)
+% **\crv{~**\dir{--} (10,0)&(20,15)&(30,15)&(40,0)}
+%\endxy
+% \end{verbatim}
+%
+% ^^A \StopEventually{\PrintIndex}
+% \StopEventually{}
+%
+% \section{Copyright, license and disclaimer}
+%
+% The copyright for the \textsf{xypdf} package is by its author, Daniel Müllner.
+% You may find current contact details 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 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. This license is available at \url{http://www.gnu.org/licenses/}.
+%
+% \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}'}}
+\ifdefined\xypsloaded
+ \PackageError{xypdf}{Do not load Xy-pic with a Postscript backend}{}
+\fi
+% \end{macrocode}
+% Rely on the ifpdf package to test for PDF output.
+% \begin{macrocode}
+\RequirePackage{ifpdf}
+% \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}
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \begin{macro}{\xP@literal}
+% Two possibilities to insert literal PDF commands, one for pdftex and one for dvipdfm(x)
+% \begin{macrocode}
+\@ifdefinable\xP@literal\relax
+\ifpdf
+ \let\xP@literal\pdfliteral
+\else
+ \def\xP@literal#1{\special{pdf:literal #1}}
+\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\removePT@\the\dimexpr(#1)*800/803\relax\space}
+% \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@lw}
+% 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
+ \edef\xP@lw{\xP@dim{\fontdimen8\textfont3}}%
+ \PackageInfo{xypdf}{Line width: \the\fontdimen8\textfont3 }%
+}
+% \end{macrocode}
+% \end{macro}
+% \subsection{Straight lines}
+% \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 }}
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\xP@stroke}
+% \begin{macrocode}
+\newcommand*\xP@stroke[1]{\xP@literal{q \xP@lw w \xP@pattern#1 S Q}}
+% \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@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{%
+ \edef\xP@pattern{1 J 1 j [%
+ \ifdim\@tempdimb>\xydashl@
+ \xP@dim{\@tempdimb/(2*\numexpr(\@tempdimb+\xydashl@)%
+ /(2*\xydashl@)\relax-1)}%
+ \fi
+ ]0 d }}
+% \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@zerodotpattern}
+% \begin{macrocode}
+\newcommand*\xP@zerodotpattern{\def\xP@pattern{2 J [0 2]0 d }}
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\xP@zerodot}
+% \begin{macrocode}
+\newcommand*\xP@zerodot{%
+ \xP@zerodotpattern
+ \xP@stroke{0 0 m 1 0 l}}
+% \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@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{\edef\xP@pattern{%
+ 2 J [%
+% \end{macrocode}
+% Produce a dot pattern only when the segment length is greater than the line width.
+% \begin{macrocode}
+ \ifdim\@tempdimb>\xP@lw bp
+ 0 \xP@dim{\@tempdimb/\numexpr\@tempdimb/131072+1\relax}%
+ \fi
+ ]0 d
+}}
+% \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}
+\ifx\ifpdfabsdim\@undefined
+ \newcommand*\xP@ifabsless[2]{\ifdim\ifdim#1<\z@-\fi#1<\ifdim#2<\z@-\fi#2}
+ \@gobble\fi
+\else
+ \newcommand*\xP@ifabsless[2]{\ifpdfabsdim#1<#2}
+ \@gobble\fi
+\fi
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\xP@ifabsless@}
+% \begin{macrocode}
+\newcommand*\xP@ifabsless@[4]{%
+ \xP@ifabsless{\dimexpr#1\relax}{\dimexpr#2\relax}#3\else#4\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
+ \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
+ -\ifodd\count@-\fi\@tempdimc)*147546029/534618434}%
+ {\Y@p+\d@Y*\count@/\@tempcnta+(\@tempdimc
+ +\ifodd\count@-\fi\@tempdima)*147546029/534618434}%
+ }%
+ \advance\count@\@ne
+ \xP@append\toks@{%
+ \xP@coor{\X@p+\d@X*\count@/\@tempcnta-(\@tempdima
+ -\ifodd\count@-\fi\@tempdimc)*147546029/534618434}%
+ {\Y@p+\d@Y*\count@/\@tempcnta-(\@tempdimc
+ +\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
+ \xP@stroke{\the\toks@}%
+ \fi
+}}
+% \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{Temporary registers}
+%
+% 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@oldpar" \\
+% "\Y@ybase" &&"\xP@velE" &"\xP@J" & &"\xP@b" & &"\xP@lastpar" \\
+% "\X@min" &&"\xP@lenA" &"\xP@K" & &"\xP@c" & &"\xP@tempvel@"\\
+% "\Y@min" &&"\xP@lenB" &"\xP@L" & &"\xP@valA" \\
+% "\X@max" &&"\xP@partlen" &"\xP@fa" & &"\xP@valB" \\
+% "\Y@max" &&"\xP@oldpartlen"&"\xP@fd" & &"\xP@devA" \\
+% "\almostz@"&&"\xP@tolerance" &"\xP@tm" & &"\xP@devB" \\
+% "\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}
+% \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{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}
+% \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}
+\@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
+\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}
+% \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.
+% \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@}
+% \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
+% \end{macrocode}
+% \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 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@
+ \ifdim\dimen5<\dimen7
+ \xP@preparespline
+ \ifdim\@tempdimb>\z@
+ #1%
+ \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}%
+ \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
+ \xP@shavespline
+ \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
+ \@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}
+% \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{{%
+ \@tempdimb\z@
+ \xP@parA\z@
+ \xP@velocity\z@\xP@velA
+ \xP@parC.5\p@
+ \xP@velocity\xP@parC\xP@velC
+ \xP@velocity\p@\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/65536$ of the approximate arc length, but at least $1\mathrm{sp}$ (e.\,g.\ for closed arcs).
+% \begin{macrocode}
+ \xP@tolerance\xP@max{1sp}{\dimexpr\xP@oldpartlen/\p@\relax}%
+% \end{macrocode}
+% Initiate the recursive algorithm with the interval $[0, 1]$.
+% \begin{macrocode}
+ \xP@arclength\xP@parC\xP@velC\p@\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}
+% \BulletE\
+% 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@velocity@
+ \global\dimen@i\@tempdimb
+ }#2\dimen@i
+}
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\xP@velocity@}
+% \BulletE\
+% \begin{macrocode}
+\newcommand*\xP@velocity@{%
+ \L@p\dimexpr\L@c-\X@p\relax
+ \U@p\dimexpr\U@c-\Y@p\relax
+ \d@X3\dimexpr((\X@c+(\L@c-\R@c)*3-\X@p)*\@tempdima/\p@
+ +(\R@c-\L@p-\L@c)*2)*\@tempdima/\p@+\L@p\relax
+ \d@Y3\dimexpr((\Y@c+(\U@c-\D@c)*3-\Y@p)*\@tempdima/\p@
+ +(\D@c-\U@p-\U@c)*2)*\@tempdima/\p@+\U@p\relax
+ \xP@veclen
+}
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\xP@velocity@@}
+% \BulletE
+% \begin{macrocode}
+\newcommand*\xP@velocity@@{%
+ \R@p\dimexpr\xP@xb-\xP@xa\relax
+ \D@p\dimexpr\xP@yb-\xP@ya\relax
+ \d@X3\dimexpr((\xP@xd+(\xP@xb-\xP@xc)*3-\xP@xa)*\@tempdima/\p@
+ +(\xP@xc-\R@p-\xP@xb)*2)*\@tempdima/\p@+\R@p\relax
+ \d@Y3\dimexpr((\xP@yd+(\xP@yb-\xP@yc)*3-\xP@ya)*\@tempdima/\p@
+ +(\xP@yc-\D@p-\xP@yb)*2)*\@tempdima/\p@+\D@p\relax
+ \xP@veclen
+}
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\xP@normalvec}
+% \BulletE\
+% Normal vector on a Bézier curve. Parameter: Parameter on segment, normal distance.
+% Needs: Bézier parameters "\X@p",\ldots,"\Y@c"
+% \begin{macrocode}
+\newcommand*\xP@normalvec[2]{{%
+ \@tempdima#1\relax
+ \@tempdimc#2\relax
+ \xP@velocity@
+% \end{macrocode}
+% If the velocity is zero at some point, take the third derivative for the tangent vector.
+% \begin{macrocode}
+ \ifdim\@tempdimb=\z@
+ \d@X\dimexpr\xP@xd+(\xP@xb-\xP@xc)*3-\xP@xa\relax
+ \d@Y\dimexpr\xP@yd+(\xP@yb-\xP@yc)*3-\xP@ya\relax
+ \xP@veclen
+ \ifdim\@tempdimb=\z@
+ \PackageError{xypdf}{Cannot determine a tangent vector to a curve}{}%
+ \@tempdimb\p@
+ \fi
+ \fi
+ \global\dimen@i\dimexpr\@tempdimc*\d@Y/\@tempdimb\relax
+ \global\dimen3\dimexpr-\@tempdimc*\d@X/\@tempdimb\relax
+ }%
+ \d@X\dimen@i
+ \d@Y\dimen3\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)*(\xP@parC-\xP@parA)/393216\relax
+ \xP@lenB
+ \dimexpr(\xP@velC+4\xP@velD+\xP@velE)*(\xP@parE-\xP@parC)/393216\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@}%
+ \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
+ \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 the line width, just draw a solid path.
+% \begin{macrocode}
+ \ifdim\@tempdimb<\xP@lw bp
+ \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
+ \@for\@tempa:={#1}\do{\xP@paintsolid\z@\xP@bigdim}%
+ \xP@stroke{\the\@temptokena}%
+}}
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\xP@paintsolid}
+% \BulletA\ \BulletE
+% \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}
+% Cut out the current portion of the spline.
+% \begin{macrocode}
+ \xP@shaveprec\xP@a\xP@b
+% \end{macrocode}
+% Compute the approximate offset curve.
+% \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}
+\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 new Bézier curve is returned in "\xP@xa",\ldots,"\xP@yd".
+% \begin{macrocode}
+\newcommand*\xP@offsetsegment{{%
+% \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}
+% 8 times (middle point plus offset)
+% \begin{macrocode}
+ \xP@normalvec{.5pt}\xP@off
+ \xP@xm\dimexpr(\X@p+\X@c+(\L@c+\R@c)*3)+8\d@X\relax
+ \xP@ym\dimexpr(\Y@p+\Y@c+(\U@c+\D@c)*3)+8\d@Y\relax
+% \end{macrocode}
+% New first anchor point
+% \begin{macrocode}
+ \xP@normalvec\z@\xP@off
+ \xP@xa\dimexpr\X@p+\d@X\relax
+ \xP@ya\dimexpr\Y@p+\d@Y\relax
+% \end{macrocode}
+% New last anchor point
+% \begin{macrocode}
+ \xP@normalvec\p@\xP@off
+ \xP@xd\dimexpr\X@c+\d@X\relax
+ \xP@yd\dimexpr\Y@c+\d@Y\relax
+% \end{macrocode}
+% Tangent vector at $0$. This also handles degenerate cases.
+% \begin{macrocode}
+ \xP@Tax\dimexpr\L@c-\X@p\relax
+ \xP@Tay\dimexpr\U@c-\Y@p\relax
+ \ifdim\xP@Tax=\z@
+ \ifdim\xP@Tay=\z@
+ \xP@Tax\dimexpr\R@c-\X@p\relax
+ \xP@Tay\dimexpr\D@c-\Y@p\relax
+ \ifdim\xP@Tax=\z@
+ \ifdim\xP@Tay=\z@
+ \xP@Tax\dimexpr\X@c-\X@p\relax
+ \xP@Tay\dimexpr\Y@c-\Y@p\relax
+ \fi
+ \fi
+ \fi
+ \fi
+ \multiply\xP@Tax\thr@@
+ \multiply\xP@Tay\thr@@
+% \end{macrocode}
+% Tangent vector at $1$.
+% \begin{macrocode}
+ \xP@Tdx\dimexpr\R@c-\X@c\relax
+ \xP@Tdy\dimexpr\D@c-\Y@c\relax
+ \ifdim\xP@Tdx=\z@
+ \ifdim\xP@Tdy=\z@
+ \xP@Tdx\dimexpr\L@c-\X@c\relax
+ \xP@Tdy\dimexpr\U@c-\Y@c\relax
+ \ifdim\xP@Tdx=\z@
+ \ifdim\xP@Tdy=\z@
+ \xP@Tdx\dimexpr\X@p-\X@c\relax
+ \xP@Tdy\dimexpr\Y@p-\Y@c\relax
+ \fi
+ \fi
+ \fi
+ \fi
+ \multiply\xP@Tdx\thr@@
+ \multiply\xP@Tdy\thr@@
+% \end{macrocode}
+% The main loop for finding the offset curve
+% \begin{macrocode}
+ \count@\z@
+ \loop
+ \@tempswafalse
+% \end{macrocode}
+% At most $10$ iterations
+% \begin{macrocode}
+ \ifnum10>\count@
+% \end{macrocode}
+% Set the new control points up.
+% \begin{macrocode}
+ \xP@offsetpoints
+% \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@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>\tw@\p@\xP@tm\tw@\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>\tw@\p@\xP@tm\tw@\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\xP@bezierpoly\xP@xa\xP@xb\xP@xc\xP@xd\xP@tm
+ \xP@D\dimexpr\xP@D-\xP@xm\relax
+ \xP@H\xP@bezierpoly\xP@ya\xP@yb\xP@yc\xP@yd\xP@tm
+ \xP@H\dimexpr\xP@H-\xP@ym\relax
+ \xP@Tmx\dimexpr\X@p-\X@c+\L@c-\R@c\relax
+ \xP@Tmy\dimexpr\Y@p-\Y@c+\U@c-\D@c\relax
+ \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
+ \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
+ \ifdim#1>4843165sp
+ #1\maxdimen
+ \else
+ #1\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@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@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}
+\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}
+ \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
+% \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}
+ \advance\xP@K\dimexpr-\xP@G*\xP@J/\xP@F\relax
+ \advance\xP@L\dimexpr-\xP@H*\xP@J/\xP@F\relax
+% \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}
+\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{.1\p@}
+% \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{.005\p@}
+% \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\@gtempa{\xP@offsetoktrue}%
+ \def\@gtempb{\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*131072/\xP@bigdim+(\xP@b-\xP@a)*\xP@ti/\xP@bigdim\relax
+% \end{macrocode}
+% Point on the original curve $c_1$ (scaled by $-8$)
+% \begin{macrocode}
+ \L@p-\xP@bezierpoly\xP@xa\xP@xb\xP@xc\xP@xd\xP@tip
+ \U@p-\xP@bezierpoly\xP@ya\xP@yb\xP@yc\xP@yd\xP@tip
+% \end{macrocode}
+% $8c_2(t_i)-8c_1(t_i)$
+% \begin{macrocode}
+ \xP@valA\xP@bezierpoly\X@p\L@c\R@c\X@c\xP@ti
+ \advance\xP@valA\L@p
+ \xP@valB\xP@bezierpoly\Y@p\U@c\D@c\Y@c\xP@ti
+ \advance\xP@valB\U@p
+% \end{macrocode}
+% $v$
+% \begin{macrocode}
+ \@tempdima\dimexpr\xP@tip/2\relax
+ \xP@velocity@@
+% \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 \textit{really} too small, just pass the test.
+% \begin{macrocode}
+ \ifdim.0005pt>\@tempdimc
+ \@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
+%\@tempdima\z@
+ \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
+ \@gtempb
+ \advance\xP@ti.1pt
+ \repeat
+ \expandafter}\@gtempa
+}
+% \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\tw@
+ \xP@setrightvalue\tw@
+% \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\frac1n$ for $n\in\{3,4,5,7,10,20\}$. Maybe we have different signs for the $x$-coordinate for the smaller boundary parameters.
+% \begin{macrocode}
+ \ifdim\xP@valA>\z@
+ \@tempswatrue
+ \@for\@tempa:={\thr@@,4,5,7,10,20}\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\dimexpr\xP@bezierpoly\X@p\L@c\R@c\X@c\L@p\relax
+ \ifdim\xP@valA>\z@
+ \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 (onyl $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
+ \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\@gtempb\iffalse
+ \gdef\@gtempa{\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-\p@/#1\relax
+ \ifdim\L@p<\z@\L@p\z@\fi
+ \xP@valA\dimexpr\xP@bezierpoly\X@p\L@c\R@c\X@c\L@p\relax
+}
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\xP@setrightvalue}
+% \BulletE
+% \begin{macrocode}
+\newcommand*\xP@setrightvalue[1]{%
+ \U@p\dimexpr\xP@ti+\p@/#1\relax
+ \ifdim\U@p>2\p@\U@p2\p@\fi
+ \xP@valB\dimexpr\xP@bezierpoly\X@p\L@c\R@c\X@c\U@p\relax
+}
+% \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{%
+% \end{macrocode}
+% Expected dash number
+% \begin{macrocode}
+ \@tempcnta\numexpr2*\numexpr(\@tempdimb+\xydashl@)/(2*\xydashl@)\relax-1\relax
+ \ifnum\@tempcnta>\@ne
+ \expandafter\xP@splinemultdashed@
+ \else
+% \end{macrocode}
+% One dash: paint a solid line
+% \begin{macrocode}
+ \expandafter\xP@splinemultsolid
+ \fi
+}
+% \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@{}%
+ \@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
+ \@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{2 J [0 \xP@dim{\xydashh@}]0 d }%
+}
+% \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}
+% Expected dot distance (see the formula in "\xP@setdottedpat")
+% \begin{macrocode}
+ \@tempdima\dimexpr\@tempdimb/\numexpr\@tempdimb/131072+1\relax\relax
+% \end{macrocode}
+% Make a list of dot positions on the spline segment.
+% \begin{macrocode}
+ \xP@temppar\z@
+ \toks@{}%
+ \loop
+ \xP@append\toks@{\noexpand\xP@paintdot{\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 which is closer to $1$.
+% \begin{macrocode}
+ \xP@lastpar
+ \ifdim\dimexpr\xP@bigdim-\xP@oldpar\relax<\dimexpr\xP@temppar%
+ -\xP@bigdim\relax
+ \xP@oldpar
+ \else
+ \xP@temppar
+ \xP@append\toks@{\noexpand\xP@paintdot{\the\xP@temppar}}%
+ \fi
+% \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}%
+}}
+% \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 (estimation based on the total spline length).
+% \begin{macrocode}
+ \xP@velocity{\xP@temppar*\p@/\xP@bigdim}\xP@tempvel
+ \xP@velocity{(\xP@temppar+\xP@bigdim/\numexpr\@tempdimb%
+ /131072+1\relax)*\p@/\xP@bigdim}\xP@tempvel@
+% \end{macrocode}
+% Use the average velocity to compute the parameter increment. If the parameter increment is too big (i.\,e.\ the velocity was very small), increment the parameter by at most $.1"\xP@bigdim"$, compute the true partial spline length and slide again.
+% \begin{macrocode}
+ \ifdim\dimexpr\@tempdima*1310720/(\xP@tempvel+\xP@tempvel@)\relax>\p@
+ {%
+ \dimen5\xP@temppar
+ \advance\xP@temppar.1\xP@bigdim
+ \dimen7\xP@temppar
+ \xP@shaveprec{\dimen5}{\dimen7}%
+ \xP@bezierlength
+ \advance\@tempdima-\@tempdimb
+ \expandafter}\expandafter\@tempdima\the\@tempdima\relax
+ \advance\xP@temppar.1\xP@bigdim
+ \expandafter\xP@slide@
+ \else
+ \advance\xP@temppar
+ \dimexpr2\xP@bigdim*\@tempdima/(\xP@tempvel+\xP@tempvel@)\relax
+ \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}
+ \xP@temppar\dimexpr#1*\xP@bigdim/\xP@lastpar\relax
+% \end{macrocode}
+% Auxiliary variables
+% \begin{macrocode}
+ \L@p\dimexpr\L@c-\X@p\relax
+ \D@p\dimexpr\U@c-\Y@p\relax
+% \end{macrocode}
+% Velocity vector at parameter value "\xP@temppar"
+% \begin{macrocode}
+ \d@X3\dimexpr((\X@c-\X@p+(\L@c-\R@c)*3)*\xP@temppar/\xP@bigdim
+ +(\R@c-\L@p-\L@c)*2)*\xP@temppar/\xP@bigdim+\L@p\relax
+ \d@Y3\dimexpr((\Y@c-\Y@p+(\U@c-\D@c)*3)*\xP@temppar/\xP@bigdim
+ +(\D@c-\D@p-\U@c)*2)*\xP@temppar/\xP@bigdim+\D@p\relax
+ \xP@veclen
+% \end{macrocode}
+% If the velocity is zero, use its first derivative instead to obtain the direction (up to a factor of $6$).
+% \begin{macrocode}
+ \ifdim\@tempdimb=\z@
+ \d@X3\dimexpr(\X@c-\X@p+(\L@c-\R@c)*3)*\xP@temppar/\xP@bigdim
+ +(\R@c-\L@p-\L@c)\relax
+ \d@Y3\dimexpr(\Y@c-\Y@p+(\U@c-\D@c)*3)*\xP@temppar/\xP@bigdim
+ +(\D@c-\D@p-\U@c)\relax
+ \xP@veclen
+% \end{macrocode}
+% If the first derivative is zero, take the second one (again up to a factor of $6$).
+% \begin{macrocode}
+ \ifdim\@tempdimb=\z@
+ \d@X3\dimexpr\X@c-\X@p+(\L@c-\R@c)*3\relax
+ \d@Y3\dimexpr\Y@c-\Y@p+(\U@c-\D@c)*3\relax
+ \xP@veclen
+ \fi
+ \fi
+% \end{macrocode}
+% Position at parameter value "\xP@temppar"
+% \begin{macrocode}
+ \U@p\dimexpr\R@c-\L@p-\L@c\relax
+ \R@p\dimexpr\X@c-3\R@c+3\L@c-\X@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
+ \xP@posX\dimexpr\X@p+(3\L@p+(3\U@p+\R@p*\xP@temppar/\xP@bigdim)%
+ *\xP@temppar/\xP@bigdim)*\xP@temppar/\xP@bigdim\relax
+ \xP@posY\dimexpr\Y@p+(3\D@p+(3\X@min+\Y@min*\xP@temppar/\xP@bigdim)%
+ *\xP@temppar/\xP@bigdim)*\xP@temppar/\xP@bigdim\relax
+% \end{macrocode}
+% Normal vector to the curve with length "\xydashh@"
+% \begin{macrocode}
+ \L@p\dimexpr\xydashh@*\d@Y/\@tempdimb/2\relax
+ \U@p\dimexpr-\xydashh@*\d@X/\@tempdimb/2\relax
+% \end{macrocode}
+% Append two points on both sides of the curve to the list. (The “zerodot” 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}
+% Expected squiggle length
+% \begin{macrocode}
+ \@tempcnta=\numexpr\@tempdimb/\xybsqll@\relax
+ \ifnum\@tempcnta<\tw@\@tempcnta\tw@\fi
+ \multiply\@tempcnta\tw@
+ \@tempdima\dimexpr\@tempdimb/\@tempcnta\relax
+% \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
+ \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
+ \@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}
+ \xP@temppar\dimexpr#1*\xP@bigdim/\xP@lastpar\relax
+% \end{macrocode}
+% Auxiliary variables
+% \begin{macrocode}
+ \L@p\dimexpr\L@c-\X@p\relax
+ \D@p\dimexpr\U@c-\Y@p\relax
+% \end{macrocode}
+% Velocity vector at parameter value "\xP@temppar"
+% \begin{macrocode}
+ \d@X3\dimexpr((\X@c-\X@p+(\L@c-\R@c)*3)*\xP@temppar/\xP@bigdim
+ +(\R@c-\L@p-\L@c)*2)*\xP@temppar/\xP@bigdim+\L@p\relax
+ \d@Y3\dimexpr((\Y@c-\Y@p+(\U@c-\D@c)*3)*\xP@temppar/\xP@bigdim
+ +(\D@c-\D@p-\U@c)*2)*\xP@temppar/\xP@bigdim+\D@p\relax
+ \xP@veclen
+% \end{macrocode}
+% If the velocity is zero, take its first derivative instead to obtain the direction (up to a factor of $6$).
+% \begin{macrocode}
+ \ifdim\@tempdimb=\z@
+ \d@X3\dimexpr(\X@c-\X@p+(\L@c-\R@c)*3)*\xP@temppar/\xP@bigdim
+ +(\R@c-\L@p-\L@c)\relax
+ \d@Y3\dimexpr(\Y@c-\Y@p+(\U@c-\D@c)*3)*\xP@temppar/\xP@bigdim
+ +(\D@c-\D@p-\U@c)\relax
+ \xP@veclen
+% \end{macrocode}
+% If the first derivative is zero, take the second one (again up to a factor of $6$).
+% \begin{macrocode}
+ \ifdim\@tempdimb=\z@
+ \d@X3\dimexpr\X@c-\X@p+(\L@c-\R@c)*3\relax
+ \d@Y3\dimexpr\Y@c-\Y@p+(\U@c-\D@c)*3\relax
+ \xP@veclen
+ \fi
+ \fi
+% \end{macrocode}
+% Position at parameter value "\xP@temppar"
+% \begin{macrocode}
+ \U@p\dimexpr\R@c-\L@p-\L@c\relax
+ \R@p\dimexpr\X@c-3\R@c+3\L@c-\X@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
+ \xP@posX\dimexpr\X@p+(3\L@p+(3\U@p+\R@p*\xP@temppar/\xP@bigdim)%
+ *\xP@temppar/\xP@bigdim)*\xP@temppar/\xP@bigdim\relax
+ \xP@posY\dimexpr\Y@p+(3\D@p+(3\X@min+\Y@min*\xP@temppar/\xP@bigdim)%
+ *\xP@temppar/\xP@bigdim)*\xP@temppar/\xP@bigdim\relax
+% \end{macrocode}
+% Offset to the current position for multiple curves.
+% \begin{macrocode}
+ \advance\xP@posX\dimexpr-\d@Y*\numexpr\@tempa\relax/\@tempdimb\relax
+ \advance\xP@posY\dimexpr\d@X*\numexpr\@tempa\relax/\@tempdimb\relax
+% \end{macrocode}
+% Tangent vector to the curve with correct length
+% \begin{macrocode}
+ \L@p\dimexpr\d@X*\@tempdima/\@tempdimb\relax
+ \U@p\dimexpr\d@Y*\@tempdima/\@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+\U@p)*173517671/654249180\relax
+ \Y@max\dimexpr(\L@p-\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+\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-\X@max}%
+ \xP@coor\xP@posX\xP@posY
+ \or
+ {\xP@posX-\D@p-\X@min}{\xP@posY+\R@p-\Y@min}%
+ \xP@coor{\xP@posX-\D@p}{\xP@posY+\R@p}%
+ \or
+ {\xP@posX-\X@max}{\xP@posY+\Y@max}%
+ \xP@coor\xP@posX\xP@posY
+ \or
+ {\xP@posX+\D@p-\X@min}{\xP@posY-\R@p-\Y@min}%
+ \xP@coor{\xP@posX+\D@p}{\xP@posY-\R@p}%
+ \fi c }%
+ \edef\next@{\expandafter\xP@coor
+ \ifcase\count@
+ {\xP@posX+\Y@max}{\xP@posY+\X@max}%
+ \or
+ {\xP@posX-\D@p+\X@min}{\xP@posY+\R@p+\Y@min}%
+ \or
+ {\xP@posX+\X@max}{\xP@posY-\Y@max}%
+ \or
+ {\xP@posX+\D@p+\X@min}{\xP@posY-\R@p+\Y@min}%
+ \fi
+ }%
+}
+% \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}
+%
+% \Finale
+\endinput \ No newline at end of file
diff --git a/Master/texmf-dist/source/latex/xypdf/xypdf.ins b/Master/texmf-dist/source/latex/xypdf/xypdf.ins
new file mode 100644
index 00000000000..ac0b9513b79
--- /dev/null
+++ b/Master/texmf-dist/source/latex/xypdf/xypdf.ins
@@ -0,0 +1,117 @@
+%%
+%% 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 - The distribution guide
+%% xypdf.dtx - Documented source code
+%% xypdf.ins - Installation script
+%% xypdf.sty - LaTeX style file
+%% xypdf.pdf - Documentation
+%%
+\input docstrip.tex
+% Change docstrip so that it gobbles spaces at the beginning of lines. Also,
+% lines containing a percent sign are merged with the next line.
+%
+% Caution: this only works if the package does not contain percent signs for
+% any other purpose than indicating comments.
+\CheckCommand*\putline@do[3]{\StreamPut#1{\inLine}}
+\renewcommand*\putline@do[3]{%
+ \expandafter\docgobblespaces\inLine\endLine
+ \docgobblepercent
+ \ifx\@tempa\empty
+ \StreamPut#1{\@stream}%
+ \let\@stream\empty
+ \fi}
+\@ifdefinable\space@\relax
+{\catcode`\ =12\global\let\space@= }
+\newcommand*\docgobblespaces{\futurelet\next\docgobblespaces@}
+\newcommand*\docgobblespaces@{%
+ \ifx\next\space@
+ \def\next@{\afterassignment\docgobblespaces\let\next= }%
+ \else
+ \def\next@{\definLine}%
+ \fi
+ \next@
+}
+\@ifdefinable\definLine\relax
+\def\definLine#1\endLine{\def\inLine{#1}}
+
+\newcommand*\@stream{}
+{\catcode`\%=12
+\@ifdefinable\percentchar\relax
+\gdef\percentchar{%}
+\@ifdefinable\docgobblepercent\relax
+\gdef\docgobblepercent{\expandafter\docgobblepercent@\inLine%\endLine}
+\@ifdefinable\docgobblepercent@\relax
+\gdef\docgobblepercent@#1%#2\endLine{\def\inLine{#1}\def\@tempa{#2}\edef\@stream{\@stream\inLine}}
+}
+
+\keepsilent
+\askforoverwritefalse
+\usedir{tex/latex/xypdf}
+\preamble
+
+Copyright (c) 2010 by Daniel M\string\"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 - The distribution guide
+ xypdf.dtx - Documented source code
+ xypdf.ins - Installation script
+ xypdf.sty - LaTeX style file
+ xypdf.pdf - Documentation
+
+\endpreamble
+\generate{\file{xypdf.sty}{\from{xypdf.dtx}{package}}}
+\obeyspaces
+\Msg{****************************************************}
+\Msg{* *}
+\Msg{* To finish the installation you have to move the *}
+\Msg{* following file into a directory searched by TeX: *}
+\Msg{* *}
+\Msg{* xypdf.sty *}
+\Msg{* *}
+\Msg{* To produce the documentation run the file *}
+\Msg{* xypdf.dtx through LaTeX. *}
+\Msg{* *}
+\Msg{* Happy TeXing! *}
+\Msg{* *}
+\Msg{****************************************************}
+\endbatchfile \ No newline at end of file