summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/source/latex/horoscop/horoscop.dtx
diff options
context:
space:
mode:
authorKarl Berry <karl@freefriends.org>2013-05-17 22:27:40 +0000
committerKarl Berry <karl@freefriends.org>2013-05-17 22:27:40 +0000
commit7b47572c533451aae0bd41e0480845a715bd3bce (patch)
tree18c86598d630a1aed49c150fdf584dff9aca521b /Master/texmf-dist/source/latex/horoscop/horoscop.dtx
parentd5dc9e49d4676082f90ee3e0d3170657f72a5b5f (diff)
horoscop (17may13)
git-svn-id: svn://tug.org/texlive/trunk@30530 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist/source/latex/horoscop/horoscop.dtx')
-rw-r--r--Master/texmf-dist/source/latex/horoscop/horoscop.dtx7413
1 files changed, 7413 insertions, 0 deletions
diff --git a/Master/texmf-dist/source/latex/horoscop/horoscop.dtx b/Master/texmf-dist/source/latex/horoscop/horoscop.dtx
new file mode 100644
index 00000000000..12ea6a98fe5
--- /dev/null
+++ b/Master/texmf-dist/source/latex/horoscop/horoscop.dtx
@@ -0,0 +1,7413 @@
+% \iffalse meta-comment
+%
+% This work is hereby released into the Public Domain. To view a
+% copy of the public domain dedication, visit
+% http://creativecommons.org/licenses/publicdomain/
+% or send a letter to Creative Commons, 171 Second Street, Suite 300,
+% San Francisco, California, 94105, USA.
+%
+% Matthew Skala
+% mskala@ansuz.sooke.bc.ca
+% http://ansuz.sooke.bc.ca/
+% August 30, 2008
+%
+% \fi
+%
+% \iffalse
+%<*driver>
+\ProvidesFile{horoscop.dtx}
+\documentclass{ltxdoc}
+
+\usepackage{color}
+\usepackage{fmtcount}
+\usepackage{graphicx}
+\usepackage[scaled=0.9]{helvet}
+\usepackage[textsym,wasysym,marvosym,starfont]{horoscop}[2013/05/16]
+\usepackage{mathpazo}
+\usepackage{titlesec}
+\usepackage[letterpaper,breaklinks,bookmarks,plainpages=false,
+ colorlinks,pagebackref,citecolor=darkgreen,linkcolor=purplish]{hyperref}
+
+\definecolor{darkgreen}{rgb}{0,0.35,0}
+\definecolor{purplish}{rgb}{0.4,0,0.6}
+
+\def\docornament{\docornA}
+
+\def\docornA{\SunSymbol\gdef\docornament{\docornB}}
+\def\docornB{\MoonSymbol\gdef\docornament{\docornC}}
+\def\docornC{\MercurySymbol\gdef\docornament{\docornD}}
+\def\docornD{\VenusSymbol\gdef\docornament{\docornE}}
+\def\docornE{\MarsSymbol\gdef\docornament{\docornF}}
+\def\docornF{\JupiterSymbol\gdef\docornament{\docornG}}
+\def\docornG{\SaturnSymbol\gdef\docornament{\docornH}}
+\def\docornH{\UranusSymbol\gdef\docornament{\docornI}}
+\def\docornI{\NeptuneSymbol\gdef\docornament{\docornJ}}
+\def\docornJ{\PlutoSymbol\gdef\docornament{\docornK}}
+\def\docornK{\ChironSymbol\gdef\docornament{\docornL}}
+\def\docornL{\LilithSymbol}
+
+\titleformat{\section}[display]%
+ {\normalfont\large\filcenter}%
+ {\itshape Chapter \Numberstring{section}}%
+ {1pc}{\MakeUppercase}[\vspace{0.8pc}\LARGE\docornament]
+\newcommand{\sectionbreak}{\cleardoublepage}
+\titleformat{\subsection}[block]{\normalfont\scshape\filcenter}%
+ {\arabic{subsection}.}{0.5em}{}
+\titleformat{\subsubsection}[runin]{\normalfont\bfseries}%
+ {{\fontseries{b}\selectfont\S}\arabic{subsection}.\arabic{subsubsection}.}{0.5em}{}[.---]
+\titlespacing{\subsubsection}{0pt}{1.5ex plus .1ex minus .2ex}{0pt}
+
+\makeatletter
+\def\mybookmark#1#2{%
+ \edef\Hy@toclevel{\csname toclevel@#1\endcsname}%
+ \Hy@writebookmark{\csname the#1\endcsname}%
+ {#2}%
+ {\@currentHref}%
+ {\Hy@toclevel}%
+ {toc}%
+}
+\makeatother
+
+\EnableCrossrefs
+\CodelineIndex
+\RecordChanges
+\begin{document}
+ \DocInput{horoscop.dtx}
+ \clearpage\phantomsection\mybookmark{section}{Change History}
+ \PrintChanges
+ \clearpage\phantomsection\mybookmark{section}{Index}
+ \PrintIndex
+\end{document}
+%</driver>
+% \fi
+%
+% \CheckSum{4087}
+%
+% \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 \~}
+%
+%
+% \changes{v0.9}{2008/05/03}{Initial (beta) version}
+%
+% \GetFileInfo{horoscop.dtx}
+%
+% \DoNotIndex{\advance,\begingroup,\count,\csname,\def,%
+% \dimen,\dimen@,\divide,\edef,\else,\endcsname,\endgroup,%
+% \expandafter,\fi,\gdef,\if,\ifdim,\let,\multiply,\p@,%
+% \relax,\the,\z@,\newcommand,\newenvironment}
+%
+% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% \title{Typesetting astrology with \textsf{horoscop}}
+% \author{Matthew Skala}
+% \date{May 16, 2013}
+%
+% \begin{titlepage}
+% \phantomsection
+% \mybookmark{section}{Title Page}
+% \centering
+% \vspace{0.75in}
+% {\Huge\scshape Typesetting}
+%
+% \vspace{2pc}
+% {\Huge\scshape Astrology}
+%
+% \vspace{2pc}
+% {\LARGE\itshape with}
+%
+% \vspace{2pc}
+% {\Huge\sffamily horoscop}
+%
+% \vspace{3pc}
+% {\Huge\docornament}
+%
+% \vspace{\fill}
+% {\Large{\scshape Matthew Skala}\\
+% \href{mailto:mskala@ansuz.sooke.bc.ca}%
+% {\nolinkurl{mskala@ansuz.sooke.bc.ca}}}
+%
+% \vspace{0.5in}
+% {\Large\itshape Version 0.92, May 16, 2013}
+% \vspace{2.5pc}
+% \end{titlepage}
+%
+% \clearpage
+% \phantomsection
+% \mybookmark{section}{Contents}
+% \tableofcontents
+%
+% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% \section{Introduction}
+%
+% This document describes the design and use of a \LaTeX\ package named
+% \textsf{horoscop}, which supports typesetting of astrological charts.
+% Features include:
+%
+% \begin{itemize}
+% \item A unified interface for astrological symbols/glyphs, supporting three
+% different astrological fonts as well as text abbreviations.
+% \item Support for invoking Astrolog or Swiss Ephemeris to calculate
+% charts. Positions can also be specified manually.
+% \item Loading and saving object and cusp positions into \TeX\ macros.
+% \item Typesetting of angles and positions as text.
+% \item Ready-made templates for basic wheel charts, dial charts
+% including multi-dials with up to four sets of objects, and decorative
+% wheel charts.
+% \item Optional variations of the standard templates: aspect webs,
+% highlighting for angular cusps, choice of what to include in object
+% labels, house labels inside the houses.
+% \item Low-level graphics functions for plotting in polar coordinates and
+% building new templates.
+% \item Labels move, and where necessary houses expand, to prevent crowding.
+% \end{itemize}
+%
+% This package is primarily typesetting software, not astrological software.
+% It is capable of interfacing to external packages to calculate things like
+% object positions for charts, and it performs astrological computations
+% like detection of aspects where that is directly needed for typesetting,
+% but it does not do more generally astrological tasks like counting the
+% objects in different elements. Things like time zones are not directly
+% relevant to typesetting and left to the user to deal with.
+%
+% Similarly, this documentation is about
+% using \textsf{horoscop} to typeset charts into documents. It is assumed
+% that readers have other sources for the astrological knowledge of what
+% charts to typeset, what they mean, and what to say about them in the
+% documents. Other software is probably more convenient for the earlier
+% stages of exploring a chart and constructing an interpretation. This
+% package becomes relevant after the interpretation is decided, when the time
+% comes to publish a chart in an attractive printed form.
+%
+% Many issues in astrology are subject to opinion, debate, and variations in
+% personal preference. Where possible, \textsf{horoscop} avoids enforcing
+% any specific line on such things. When it is necessary to choose a
+% default (for instance, whether to use \Capricorn\ or \varCapricorn\ for
+% Capricorn) the system generally follows the author's preference with as
+% much support for user customization as possible. The intention is to
+% provide reasonably usable typeset charts---at least as good as the
+% output of high-quality commercial charting software---right out of the
+% box for users with minimal \LaTeX\ skill, and also provide the capability
+% for advanced users to customize the system to meet their own exact needs.
+%
+% Some \LaTeX\ users have philosophical objections to the very idea of
+% astrology. Such issues are not addressed here.
+%
+% Basic correctness is a design priority. Some other software will do
+% things like typeset an object in the wrong house if there are too many
+% objects in the right house for them to fit nicely; \textsf{horoscop}
+% should never do that. The garbage in, garbage out principle applies,
+% however, and \textsf{horoscop} is not responsible for problems occurring
+% in external software; so if you ask for Placidus cusps from a birth in
+% the Arctic Circle, \textsf{horoscop} will make its best effort to typeset
+% whatever comes out of the calculation software but it will be your own
+% fault if that is nonsense.
+%
+% This 0.92 release is the first one to be submitted to CTAN. I still feel
+% like \textsf{horoscop} is beta software, but it has existed since 2004, it
+% has not changed much in years, the recent switch to \textsf{pict2e} makes
+% it a lot more useful with modern \TeX\ installations, and I think the time
+% has come to share it more widely. Next version will probably be 1.0.
+%
+% This package has a GitHub repository at
+% \url{http://github.com/mskala/horoscop}. Bug reports should be filed
+% there using GitHub's issue tracking system.
+%
+% There is an online chart service demonstrating \textsf{horoscop} at
+% \url{http://ansuz.sooke.bc.ca/astrology/makechart.php}. I also maintain a
+% page pointing to recent versions of this, my \textsf{starfont} package,
+% and any other \LaTeX\ astrology resources I can find, at
+% \url{http://ansuz.sooke.bc.ca/entry/107}.
+%
+% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% \section{Prerequisites and Warnings}
+%
+% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% \subsection{Font Support}
+%
+% Typesetting astrological symbols (often called ``glyphs'')
+% requires an appropriate font, packaged for \LaTeX. This package supports
+% three, selectable by package options: \textsf{marvosym},
+% \textsf{starfont}, and \textsf{wasysym}, none of which are included in a
+% typical default \LaTeX\ installation. The \textsf{starfont} package is
+% default and recommended, because the others have many symbols either
+% missing or unsuitable.
+% Instead of using an astrological font
+% at all, the |textsym| option may be used to substitute abbreviations
+% written in \LaTeX's ordinary text font.
+%
+% Sources for astrological font packages:
+% \changes{v0.92}{2013/05/16}{Update links for font packages}
+% \begin{itemize}
+% \item \textsf{marvosym}: \url{http://www.ctan.org/pkg/marvosym}
+% \item \textsf{starfont}: \url{http://www.ctan.org/pkg/starfont}
+% \item \textsf{wasysym}: \url{http://www.ctan.org/pkg/wasysym}
+% \end{itemize}
+%
+% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% \subsection{Chart Graphics}
+%
+% \changes{v0.92}{2013/05/15}{Use \textsf{pict2e} for graphics support}
+% Typesetting astrological charts (which are distinct from symbols---you
+% could use symbols in text without any charts, or conceivably charts
+% without symbols) requires \textsf{pict2e} and
+% \textsf{trig}; these \emph{are} typically included in \LaTeX\
+% installations by default.
+% An earlier version (predating the existence of \textsf{pict2e}) required
+% \textsf{eepic}, and consequently \textsf{latex}/\textsf{dvips}, not
+% \textsf{pdflatex}. But the long-promised \textsf{pict2e} package finally
+% exists, allowing large circles and arbitrary-slope lines in the |picture|
+% environment in many different engines, and that's a nicer solution.
+%
+% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% \subsection{External Programs}
+%
+% Calling an external program to compute chart information requires a
+% suitable external program. At present, \textsf{horoscop} supports
+% Astrolog and Swiss Ephemeris. It is possible to typeset charts without
+% using this feature, by coding all the object locations into the \LaTeX\
+% source file instead of having them calculated on the fly.
+%
+% Sources for external calculation programs:
+% \begin{itemize}
+% \item Astrolog:
+% \url{http://www.astrolog.org/astrolog.htm}
+% \item Swiss Ephemeris:
+% \url{http://www.astro.com/swisseph/}
+% \end{itemize}
+%
+% {\em External calculation programs require |\write18| support in \TeX.}
+% That is disabled by default, and should not be enabled lightly. With
+% |\write18| support, \TeX\ documents can execute arbitrary commands on the
+% host computer system, potentially giving them the ability to cause
+% unlimited damage. No file containing data from an untrusted source should
+% be run on an interpreter with |\write18| enabled. In particular, readers
+% should be especially wary of using \textsf{horoscop} in automated
+% chart-calculation services. If you create a Web form for people to enter
+% birth data and automatically generate a \LaTeX\ source file to typeset a
+% chart, then you must carefully sanitize all the user-entered data on the
+% server side.
+%
+% The procedure for enabling |\write18| will vary depending on your
+% \TeX\ installation; for obvious security reasons, it must be done out of
+% band, and cannot be turned on by any commands given in the document. On a
+% typical installation |\write18| might be enabled by a special command-line
+% option to the \TeX\ interpreter. If you don't know what this stuff means
+% and how to deal with it, then you shouldn't attempt to turn on |\write18|.
+%
+% The external calculation programs' shell commands have only been
+% tested under Linux. They will probably work on any system where the
+% external software can be installed, but no guarantees are offered.
+%
+% Users of \textsf{horoscop} should be aware of some issues related to the
+% external calculation programs, although these issues are not directly
+% issues with \textsf{horoscop}. First, the author of Astrolog \emph{claims}
+% a right under copyright to forbid commercial use not only of Astrolog, but
+% of the factual information contained in Astrolog's output. Noting that in
+% many jurisdictions copyright does not apply to factual information, the
+% author of \textsf{horoscop} does not endorse the validity of any such
+% claims by third parties; and \textsf{horoscop} itself is public domain and
+% may be used without restriction, even commercially. However, commercial
+% users of \textsf{horoscop} may prefer to select the Swiss Ephemeris
+% support, which is default and not subject to such a claim.
+%
+% The authors of Swiss Ephemeris restrict commercial distribution of their
+% package, but do not claim to restrict commercial use of its output. Swiss
+% Ephemeris is not intended by its developers to be an end-user product.
+% They market it to other software developers for use as a module in the
+% other developers' products. To use it with \textsf{horoscop}, you must
+% install the library on your system as if you were preparing to write
+% software using it yourself, and make sure all the paths are right so that
+% \TeX\ can invoke the |swetest| executable and have it really work. This
+% process will normally require at least a minimal level of C programming
+% skill.
+%
+% Users are obviously at their own risk with regard to license conditions
+% set by the copyright holders of any and all third-party products. The
+% \textsf{horoscop} package itself is released to the public domain in an
+% effort to help stop the insanity of escalating license conditions imposed
+% by other authors of astrological software.
+%
+% To use the |egrep| option with the Swiss Ephemeris backend, the standard
+% Unix |egrep| program must be available.
+%
+% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% \section{Package Options}
+%
+% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% \subsection{Astrological Symbol Options}
+%
+% The options |textsym|, |wasysym|, |marvosym|, and |starfont| control the
+% font used for astrological symbols. You may choose more than one of these
+% options, in which case more than one set will be available in your
+% document. The set in force at the start of the document will be the last
+% one on that list, from among the ones chosen; so |starfont| overrides
+% |marvosym| which overrides |wasysym| which overrides |textsym|. If none
+% of these options are specified, then |starfont| will be enabled by
+% default.
+%
+% If you have no astrological font support, or will not be using symbols and
+% want to avoid the resource consumption, choose |textsym| to prevent
+% \textsf{horoscop} from trying to load the missing packages. The
+% abbreviations defined by |textsym| (and the |\horotextsym| macro below)
+% are available regardless of package options; |textsym| is provided as an
+% explicit option so users can override the default loading of |starfont|.
+% The abbreviations are also used to replace missing symbols in the other
+% sets.
+%
+% \DescribeMacro{\horotextsym}
+% \DescribeMacro{\horowasysym}
+% \DescribeMacro{\horomarvosym}
+% \DescribeMacro{\horostarfont}
+% The macros |\horotextsym|, |\horowasysym|, |\horomarvosym|, and
+% |\horostar|-|font| switch to the corresponding set of astrological symbols,
+% so that documents can mix the different sets. Any symbols not defined by
+% the new set remain in the state left by the old set. To use these macros
+% the corresponding symbol sets must have been loaded with the appropriate
+% package options, except |\horotextsym| which is always available.
+%
+% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% \subsection{Calculation Backend Options}
+%
+% The \textsf{horoscop} package can get its chart information from either of
+% two external calculation backends, or just use positions supplied by the
+% user in macro definitions. The options |nocalc|, |astrolog|, and
+% |swetest| choose among no backend (user must supply all positions),
+% Astrolog, and the Swiss Ephemeris test program respectively. If more than
+% one is supplied, |swetest| overrides |astrolog| which overrides |nocalc|.
+% The default if none is specified will be |swetest|. Note that either
+% external calculation program requires that the corresponding software be
+% installed properly on the system and that |\write18| be turned on; see the
+% previous chapter for instructions and warnings regarding external
+% software.
+%
+% \changes{v0.91}{2008/07/07}{\texttt{egrep} filtering option}
+% When using the |swetest| backend, it is possible to request filtering of
+% |swetest|'s output via the |egrep| option. With this option, |swetest|'s
+% output will be filtered through the |egrep| program (which must also be
+% installed) to eliminate error and warning messages. Normally an error or
+% warning from |swetest| will cause typesetting to fail with an
+% uninformative message. This might occur for instance if the chart's date
+% is not covered by the installed high-accuracy ephemeris files and Swiss
+% Ephemeris reverts to its analytic model. Selecting |egrep| makes
+% \textsf{horoscop} try harder to typeset the document, working through the
+% error or warning with whatever numbers come out of |swetest|.
+%
+% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% \subsection{Optional Package Components}
+%
+% If this package will be used in a non-graphical document (for instance, to
+% typeset text-based interpretations), it may be desirable to turn off the
+% graphics support and avoid loading the graphics packages. That can be
+% accomplished with the |nowheels| option. Similarly, the ready-made
+% templates can be disabled with |notemplates|, which might be useful in
+% documents that use user-defined templates exclusively. Selecting
+% |nowheels| automatically causes |notemplates| to take effect also.
+%
+% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% \section{General Concepts}
+%
+% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% \subsection{Objects and Variables}
+%
+% Calculating and typesetting a chart requires keeping track of a number of
+% pieces of information relating to luminaries, planets, asteroids, derived
+% points, hypothetical bodies, and similar things. The pieces of
+% information are referred to as ``variables'' and the things that have
+% associated variables are collectively called ``objects.'' The values for
+% variables are stored in macros named |\horo|\meta{object}\meta{variable};
+% for instance, |\horoSunPos| represents the Sun's longitude. Numerical
+% values should be stored in the macros as plain decimal numbers (with or
+% without a fractional part, possibly negative where appropriate).
+%
+% \subsubsection{Objects}
+% Standard object names include the luminaries and traditional planets Sun,
+% Moon, Mercury, Venus, Mars, Jupiter, Saturn, Uranus, Neptune, and Pluto,
+% and the asteroids Chiron, Ceres, Pallas, Juno, and Vesta. The asteroid
+% Pallas is named that rather than common variations like ``Pallas Athena''
+% because its IAU name is just Pallas. The Lunar North node, as calculated
+% by Astrolog, is called NorthNode; with Swiss Ephemeris the names MeanNode
+% and TrueNode are used instead.\footnote{Calling the osculating node
+% ``true'' is deprecated, but too entrenched to override. The node is
+% undefined except when the Moon is right on top of it, so the question is
+% which of several reasonable assumptions to make when inventing a value in
+% between those times, and there's no reason to privilege one choice over
+% the others.} The Astrolog version will be whichever one Astrolog is
+% configured to compute; on a default installation of Astrolog that is
+% probably the mean version. The name Lilith refers to the Lunar apogee.
+%
+% \DescribeMacro{\horoobjects}
+% Calculation and the chart templates use a macro called |\horoobjects|,
+% which lists the names (comma separated) of all the objects to compute or
+% typeset. The default value is all the object names defined in the
+% previous paragraph except that only one North node will be used: NorthNode
+% for Astrolog and MeanNode for Swiss Ephemeris. To exclude some objects,
+% or choose a different node calculation, the user can redefine
+% |\horoobjects| to the desired list of objects. Note that this macro, like
+% the variable values, is used and parsed internally and so it should not be
+% given a smart value; it should just be a simple list of names separated by
+% commas. No whitespace either, please.
+%
+% It is possible to create additional objects by defining the appropriate
+% macros and adding the new names to the |\horoobjects| macro. An example
+% of this process is given in Section~\ref{sub:adding-objects}. The Swiss
+% Ephemeris backend will also automatically calculate objects called
+% Ascendant, MC, ARMC, and Vertex; these four get calculated every time you
+% calculate a chart whether you request them in |\horoobjects| or not.
+%
+% \subsubsection{Cusps}
+% House\DescribeMacro{\horocusps}
+% \ cusps are treated very much like additional objects with the names
+% CuspI, CuspII, up to CuspXII. Like objects from |\horoobjects|, each cusp
+% has an associated set of variables in macros with names like
+% |\horoCuspIPos|. The macro |\horocusps| lists the cusps, like
+% |\horoobjects|, but in general it should not be modified. Cusps will be
+% calculated and used as appropriate; in general they should not be added to
+% |\horoobjects|. In most present-day house systems, CuspI, CuspIV,
+% CuspVII, and CuspX coincide with the ascendant, nadir, descendant, and
+% zenith respectively. For systems where that is not the case, Swiss
+% Ephemeris users may want to add Ascendant and MC to |\horoobjects| to plot
+% those on the chart as additional objects.
+%
+% \subsubsection{Variables}
+% The variable Pos, associated with every object and cusp, has already been
+% mentioned. It represents the longitude of the object or cusp, measured in
+% decimal degrees starting from 0\horodegrees\AriesSymbol=0.0. On that scale
+% 0\horodegrees\TaurusSymbol=30.0, 0\horodegrees\GeminiSymbol=60.0, and so on.
+%
+% The variable DPos represents ``display Pos''; that is the actual location
+% where the label or line representing an object or cusp will be plotted,
+% which might not be the same as its Pos if it had to be moved to prevent
+% interference with another object or cusp.
+%
+% Vel represents an object's velocity, in longitude. This should be in
+% degrees per day, but the system actually only looks at its sign: positive
+% for direct and negative for retrograde. The calculation backends
+% calculate it along with Pos and the chart templates check for it to
+% determine whether to display a \horoRetrogradeSymbol\ symbol in the label.
+%
+% Variables called MPos, MDPos, and SPos are used internally by
+% \textsf{horoscop} code to represent house midpoints, display positions of
+% internal house labels, and saved position values for checking termination
+% of the adjustment cycle. It should not be necessary for users to touch
+% these. Use of a user-defined variable called XPos is demonstrated in
+% Section~\ref{sub:between-two}.
+%
+% The Symbol macros (described in the next section) are much like variables,
+% although they have slightly different naming and do not take numeric
+% values. The |\horo|\meta{object}|SEOpt| macros used by the Swiss
+% Ephemeris calculation backend are essentially string-valued
+% variables too. Their use is explained in Section~\ref{sub:adding-objects}.
+%
+% \DescribeMacro{\horocopyvar}
+% The |\horocopyvar|\marg{objects}\marg{from}\marg{to} macro copies the
+% \meta{from} variable to the \meta{to} variable on all the objects in the
+% comma-separated list given by \meta{objects}. That operation is often
+% used internally, and exposed to the user because it is occasionally useful
+% to users also. For instance, if you set up the Pos values for your charts
+% manually with |\def|,\footnote{It is traditional to warn readers to use
+% \texttt{\textbackslash newcommand} or \texttt{\textbackslash renewcommand}
+% instead of \texttt{\textbackslash def}.} then you must
+% put the same values into DPos before invoking a chart template that
+% will attempt label adjustment. The command
+% |\horocopyvar{\horoobjects}{Pos}{DPos}| will copy all the Pos variables for
+% objects in |\horoobjects| to the corresponding DPos variables.
+%
+% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% \subsection{Symbols}
+%
+% \subsubsection{Naming scheme}
+%
+% For every object there should be a symbol or glyph in a macro named
+% |\|\meta{object}|Symbol|. Note the absence of |horo| at the start of the
+% macro name; that's to save typing because these macros are probably of
+% interest in general text outside the context of \textsf{horoscop}'s chart
+% features, and to separate the Symbol variable-like thing from real
+% variables that have numeric values.
+%
+% There are four basic sets of symbols, based on three font packages and the
+% |textsym| option of using text abbreviations. See the package options
+% discussion above for a description of how the choice between symbol sets
+% is made. Some of the font packages are incomplete, and \textsf{horoscop}
+% will attempt to make substitutions to fill in the blanks. Users can
+% redefine the macros as needed, to use symbols from other fonts or for
+% instance if it's desired to use \varCapricorn\ instead of \Capricorn\ for
+% Capricorn (\textsf{starfont} provides both).
+%
+% The main use of these is for wheel charts, where you specify a list of
+% objects and they all get typeset into the chart. It's necessary to
+% provide a user-defined |\|\meta{object}|Symbol| for any new objects you
+% add, if those objects will be typeset into wheel charts. The symbols can
+% also be used by themselves in text. Note that \textsf{horoscop} will
+% always invoke these symbols in text mode; if the desired symbol is a
+% math-mode symbol, then the macro has to include the appropriate shift to
+% math mode.
+%
+% \subsubsection{Zodiac signs}
+%
+% \DescribeMacro{\Zodiac}
+% The system provides a |\Zodiac|\marg{sign} macro, whose parameter
+% \meta{sign} should be an integer from 1 to 12 choosing the sign from
+% Aries=1 to Pisces=12; this typesets the symbol for the appropriate sign.
+% It mimics, and replaces, the similar macro provided by \textsf{marvosym}
+% and \textsf{starfont}; instead of going directly to the font characters,
+% \textsf{horoscop}'s |\Zodiac| calls the appropriate macro from
+% |\AriesSymbol|\ldots|\PiscesSymbol|, allowing the user to redefine
+% individual sign symbols without needing to redefine all of |\Zodiac|.
+% Note that all use of sign symbols by \textsf{horoscop} (for instance, in
+% chart wheel labels) goes through |\Zodiac|, so it is possible to redefine
+% the entire zodiac by redefining |\Zodiac| instead of redefining individual
+% symbols.
+%
+% \begin{tabular}{lcccc}
+% macro & |textsym| & |wasysym| & |marvosym| & |starfont| \\
+% |\AriesSymbol| & \horotextsym\AriesSymbol
+% & \horowasysym\AriesSymbol
+% & \horomarvosym\AriesSymbol
+% & \horostarfont\AriesSymbol \\
+% |\TaurusSymbol| & \horotextsym\TaurusSymbol
+% & \horowasysym\TaurusSymbol
+% & \horomarvosym\TaurusSymbol
+% & \horostarfont\TaurusSymbol \\
+% |\GeminiSymbol| & \horotextsym\GeminiSymbol
+% & \horowasysym\GeminiSymbol
+% & \horomarvosym\GeminiSymbol
+% & \horostarfont\GeminiSymbol \\
+% |\CancerSymbol| & \horotextsym\CancerSymbol
+% & \horowasysym\CancerSymbol
+% & \horomarvosym\CancerSymbol
+% & \horostarfont\CancerSymbol \\
+% |\LeoSymbol| & \horotextsym\LeoSymbol
+% & \horowasysym\LeoSymbol
+% & \horomarvosym\LeoSymbol
+% & \horostarfont\LeoSymbol \\
+% |\VirgoSymbol| & \horotextsym\VirgoSymbol
+% & \horowasysym\VirgoSymbol
+% & \horomarvosym\VirgoSymbol
+% & \horostarfont\VirgoSymbol \\
+% |\LibraSymbol| & \horotextsym\LibraSymbol
+% & \horowasysym\LibraSymbol
+% & \horomarvosym\LibraSymbol
+% & \horostarfont\LibraSymbol \\
+% |\ScorpioSymbol| & \horotextsym\ScorpioSymbol
+% & \horowasysym\ScorpioSymbol
+% & \horomarvosym\ScorpioSymbol
+% & \horostarfont\ScorpioSymbol \\
+% |\SagittariusSymbol| & \horotextsym\SagittariusSymbol
+% & \horowasysym\SagittariusSymbol
+% & \horomarvosym\SagittariusSymbol
+% & \horostarfont\SagittariusSymbol \\
+% |\CapricornSymbol| & \horotextsym\CapricornSymbol
+% & \horowasysym\CapricornSymbol
+% & \horomarvosym\CapricornSymbol
+% & \horostarfont\CapricornSymbol \\
+% |\AquariusSymbol| & \horotextsym\AquariusSymbol
+% & \horowasysym\AquariusSymbol
+% & \horomarvosym\AquariusSymbol
+% & \horostarfont\AquariusSymbol \\
+% |\PiscesSymbol| & \horotextsym\PiscesSymbol
+% & \horowasysym\PiscesSymbol
+% & \horomarvosym\PiscesSymbol
+% & \horostarfont\PiscesSymbol
+% \end{tabular}
+%
+% \subsubsection{Luminaries and traditional planets}
+%
+% These are well-supported by the various fonts.
+%
+% \begin{tabular}{lcccc}
+% macro & |textsym| & |wasysym| & |marvosym| & |starfont| \\
+% |\SunSymbol| & \horotextsym\SunSymbol
+% & \horowasysym\SunSymbol
+% & \horomarvosym\SunSymbol
+% & \horostarfont\SunSymbol \\
+% |\MoonSymbol| & \horotextsym\MoonSymbol
+% & \horowasysym\MoonSymbol
+% & \horomarvosym\MoonSymbol
+% & \horostarfont\MoonSymbol \\
+% |\MercurySymbol| & \horotextsym\MercurySymbol
+% & \horowasysym\MercurySymbol
+% & \horomarvosym\MercurySymbol
+% & \horostarfont\MercurySymbol \\
+% |\VenusSymbol| & \horotextsym\VenusSymbol
+% & \horowasysym\VenusSymbol
+% & \horomarvosym\VenusSymbol
+% & \horostarfont\VenusSymbol \\
+% |\MarsSymbol| & \horotextsym\MarsSymbol
+% & \horowasysym\MarsSymbol
+% & \horomarvosym\MarsSymbol
+% & \horostarfont\MarsSymbol \\
+% |\JupiterSymbol| & \horotextsym\JupiterSymbol
+% & \horowasysym\JupiterSymbol
+% & \horomarvosym\JupiterSymbol
+% & \horostarfont\JupiterSymbol \\
+% |\SaturnSymbol| & \horotextsym\SaturnSymbol
+% & \horowasysym\SaturnSymbol
+% & \horomarvosym\SaturnSymbol
+% & \horostarfont\SaturnSymbol \\
+% |\UranusSymbol| & \horotextsym\UranusSymbol
+% & \horowasysym\UranusSymbol
+% & \horomarvosym\UranusSymbol
+% & \horostarfont\UranusSymbol \\
+% |\NeptuneSymbol| & \horotextsym\NeptuneSymbol
+% & \horowasysym\NeptuneSymbol
+% & \horomarvosym\NeptuneSymbol
+% & \horostarfont\NeptuneSymbol \\
+% |\PlutoSymbol| & \horotextsym\PlutoSymbol
+% & \horowasysym\PlutoSymbol
+% & \horomarvosym\PlutoSymbol
+% & \horostarfont\PlutoSymbol
+% \end{tabular}
+%
+% \subsubsection{Other objects, cusps, and angles}
+% The \textsf{starfont} package provides symbols for asteroids, derived
+% points, angles, and so on. Without it, these things default to the
+% |textsym| abbreviations. Cusp symbols are listed here too, although they
+% generally do not appear in the default templates and will seldom be used
+% in actual practice.
+%
+% \begin{tabular}{lcc}
+% macro & |textsym| & |starfont| \\
+% |\ChironSymbol| & \horotextsym\ChironSymbol
+% & \horostarfont\ChironSymbol \\
+% |\CeresSymbol| & \horotextsym\CeresSymbol
+% & \horostarfont\CeresSymbol \\
+% |\PallasSymbol| & \horotextsym\PallasSymbol
+% & \horostarfont\PallasSymbol \\
+% |\JunoSymbol| & \horotextsym\JunoSymbol
+% & \horostarfont\JunoSymbol \\
+% |\VestaSymbol| & \horotextsym\VestaSymbol
+% & \horostarfont\VestaSymbol \\
+% |\NorthNodeSymbol| & \horotextsym\NorthNodeSymbol
+% & \horostarfont\NorthNodeSymbol \\
+% |\SouthNodeSymbol| & \horotextsym\SouthNodeSymbol
+% & \horostarfont\SouthNodeSymbol \\
+% |\LilithSymbol| & \horotextsym\LilithSymbol
+% & \horostarfont\LilithSymbol \\
+% |\CuspISymbol| & \horotextsym\CuspISymbol
+% & \horostarfont\CuspISymbol \\
+% |\CuspIISymbol| & \horotextsym\CuspIISymbol & \\
+% |\CuspIIISymbol| & \horotextsym\CuspIIISymbol & \\
+% |\CuspIVSymbol| & \horotextsym\CuspIVSymbol
+% & \horostarfont\CuspIVSymbol \\
+% |\CuspVSymbol| & \horotextsym\CuspVSymbol & \\
+% |\CuspVISymbol| & \horotextsym\CuspVISymbol & \\
+% |\CuspVIISymbol| & \horotextsym\CuspVIISymbol
+% & \horostarfont\CuspVIISymbol \\
+% |\CuspVIIISymbol| & \horotextsym\CuspVIIISymbol & \\
+% |\CuspIXSymbol| & \horotextsym\CuspIXSymbol & \\
+% |\CuspXSymbol| & \horotextsym\CuspXSymbol
+% & \horostarfont\CuspXSymbol \\
+% |\CuspXISymbol| & \horotextsym\CuspXISymbol & \\
+% |\CuspXIISymbol| & \horotextsym\CuspXIISymbol & \\
+% |\AscendantSymbol| & \horotextsym\AscendantSymbol
+% & \horostarfont\AscendantSymbol \\
+% |\MCSymbol| & \horotextsym\MCSymbol
+% & \horostarfont\MCSymbol \\
+% |\VertexSymbol| & \horotextsym\VertexSymbol
+% & \horostarfont\VertexSymbol \\
+% \end{tabular}
+%
+% Note that \textsf{wasysym} provides a symbol it calls |\ascnode|, but it's
+% actually identical to the symbol it calls |\leo|, and the symbol (\leo)
+% looks more like a Leo symbol; to prevent insanity, \textsf{horoscop} won't
+% use that symbol for the node unless you force the issue by redefining
+% |\NorthNodeSymbol|. The corresponding |\descnode| symbol is just the Leo
+% symbol again, turned upside-down; it is aesthetically offensive enough
+% that it also won't be used for South node by default.
+%
+% \DescribeMacro{\MeanNodeSymbol}\DescribeMacro{\TrueNodeSymbol} There are
+% no well-agreed standard symbols for ``mean'' as opposed to ``true''
+% (osculating) definitions of the Lunar nodes. The macros |\MeanNodeSymbol|
+% and |\TrueNodeSymbol| by default typeset the current value of
+% |\NorthNodeSymbol| with a subscript $M$ or $T$, as \MeanNodeSymbol\ and
+% \TrueNodeSymbol.
+%
+% Note that the default symbols for cusps assume an angular house system
+% like that attributed to Placidus, in which the first house cusp is by
+% definition equal to the ascendant, and so on. If you use a house system
+% where that isn't true, and you will typeset symbols for the house cusps,
+% then you must manually define appropriate symbols for them distinct from
+% whatever symbols you are using for the actual angles. However, it's rare
+% to need symbols for house cusps at all. Most wheel charts don't use them.
+%
+% \subsubsection{Aspects}
+% When typesetting aspect webs, macros having names of the form
+% |\horo|\meta{aspect}|Symbol| will be used to print symbols identifying the
+% aspects at the middle of each aspect line. These have the |\horo| prefix
+% to keep them separated from the object symbols. If you define custom
+% aspects, you should define corresponding symbols in the same pattern. The
+% \textsf{marvosym} package does not define any aspect symbols (defaults to
+% |textsym|), and \textsf{wasysym} only defines a few. The symbols for
+% quintile and biquintile with \textsf{starfont}, and the one for trine with
+% \textsf{wasysym}, are
+% actually made from standard \LaTeX\ symbols rather than using the named
+% fonts. The table
+% below also shows the default angles and orbs for the aspects; see
+% Subsection~\ref{sub:aspect-web}.
+%
+% {\renewcommand{\tabcolsep}{0.2em}
+% \begin{tabular}{lcccc}
+% macro & |textsym| & |wasysym| & |starfont| & angle\\
+% |\horoConjunctionSymbol| & \horotextsym\horoConjunctionSymbol
+% & \horowasysym\horoConjunctionSymbol
+% & \horostarfont\horoConjunctionSymbol & $0\horodegrees\pm6\horodegrees$ \\
+% |\horoOppositionSymbol| & \horotextsym\horoOppositionSymbol
+% & \horowasysym\horoOppositionSymbol
+% & \horostarfont\horoOppositionSymbol & $180\horodegrees\pm6\horodegrees$ \\
+% |\horoTrineSymbol| & \horotextsym\horoTrineSymbol
+% & \horowasysym\horoTrineSymbol
+% & \horostarfont\horoTrineSymbol & $120\horodegrees\pm5\horodegrees$ \\
+% |\horoSquareSymbol| & \horotextsym\horoSquareSymbol
+% & \horowasysym\horoSquareSymbol
+% & \horostarfont\horoSquareSymbol & $90\horodegrees\pm5\horodegrees$ \\
+% |\horoQuintileSymbol| & \horotextsym\horoQuintileSymbol
+% & & \horostarfont\horoQuintileSymbol & $72\horodegrees\pm2\horodegrees$ \\
+% |\horoBiquintileSymbol| & \horotextsym\horoBiquintileSymbol
+% & & \horostarfont\horoBiquintileSymbol & $144\horodegrees\pm2\horodegrees$ \\
+% |\horoSextileSymbol| & \horotextsym\horoSextileSymbol
+% & \horowasysym\horoSextileSymbol
+% & \horostarfont\horoSextileSymbol & $60\horodegrees\pm4\horodegrees$ \\
+% |\horoQuincunxSymbol| & \horotextsym\horoQuincunxSymbol
+% & & \horostarfont\horoQuincunxSymbol & $150\horodegrees\pm3\horodegrees$ \\
+% |\horoSemisextileSymbol| & \horotextsym\horoSemisextileSymbol
+% & & \horostarfont\horoSemisextileSymbol & $30\horodegrees\pm3\horodegrees$ \\
+% |\horoSemisquareSymbol| & \horotextsym\horoSemisquareSymbol
+% & & \horostarfont\horoSemisquareSymbol & $45\horodegrees\pm2\horodegrees$ \\
+% |\horoSesquiquadrateSymbol| & \horotextsym\horoSesquiquadrateSymbol
+% & & \horostarfont\horoSesquiquadrateSymbol & $135\horodegrees\pm2\horodegrees$
+% \end{tabular}}
+%
+% \subsubsection{Text angle and direction symbols}
+% \DescribeMacro{\horodegrees}
+% \DescribeMacro{\horominutes}
+% \DescribeMacro{\horoseconds}
+% Symbols for degrees, minutes, and seconds (|\horodegrees|, |\horominutes|,
+% and |\horoseconds|) are provided for use when an
+% angle will be described numerically, as in 12\horodegrees 34\horominutes
+% 56\horoseconds. As with other symbols, the macros can be redefined to
+% change \textsf{horoscop}'s behaviour. These three use standard \LaTeX\
+% math symbols and do not require any special package support.
+%
+% \DescribeMacro{\horoRetrogradeSymbol}
+% The |\horoRetrogradeSymbol| macro is in a similar category: it will be
+% used to typeset ``retrograde'' for labels that display that information.
+%
+% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% \section{Calculating Horoscopes}
+%
+% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% \subsection{Entering Chart Data}
+%
+% Before erecting a chart we need the astrological locations of all the
+% objects to be included. The \textsf{horoscop} package is not primarily a
+% chart-computing system, but it can interface with other software to do the
+% computation. The external interface takes the time and location data from
+% macros named \DescribeMacro{\horocalcyear}|\horocalcyear|,
+% \DescribeMacro{\horocalcmonth}|\horocalcmonth|,
+% \DescribeMacro{\horocalcday}|\horocalcday|,
+% \DescribeMacro{\horocalctime}|\horocalctime|,
+% \DescribeMacro{\horocalclon}|\horocalclon|,
+% and \DescribeMacro{\horocalclat}|\horo|-|calclat|, which should be
+% defined to contain the year, month, day, time, longitude, and latitude
+% respectively. Each one should be a decimal number, with only whole
+% numbers for year and month; |\horocalctime| is the number of hours from
+% midnight (so that a time like 4:30pm would be 16.5); and longitude and
+% latitude are numbers of degrees. Use positive numbers for North and East
+% and negative for South and West. Times and dates must be UTC. For
+% example, the birth data for Uri Geller could be entered as follows.
+%
+% \begin{verbatim}
+% \renewcommand{\horocalcyear}{1946}
+% \renewcommand{\horocalcmonth}{12}
+% \renewcommand{\horocalcday}{20}
+% \renewcommand{\horocalctime}{0}
+% \renewcommand{\horocalclon}{34.76667}
+% \renewcommand{\horocalclat}{32.06667}
+% \end{verbatim}
+%
+% Setting all those macros one at a time is messy and inconvenient, so a
+% simplified interface is available through the
+% \DescribeMacro{\horocalcparms}|\horocalcparms| macro, which sets them all
+% at once and translates minutes and seconds, both of time and of arc.
+% \begin{verbatim}
+% \horocalcparms{1946}{12}{20}{0:0:0}{E34:46:0}{N32:4:0}
+% \end{verbatim}
+% Although this macro is slightly more forgiving than the lower-level ones,
+% one should nonetheless stick closely to the example format. In
+% particular, do not omit the minutes and seconds even when they are zero.
+%
+% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% \subsection{Calculating Object Positions}
+%
+% Once the chart data is defined, call
+% \DescribeMacro{\horocalculate}|\horocalculate| to invoke the external
+% calculation program and actually compute the object positions. As already
+% mentioned, this requires |\write18| support in your \TeX\ interpreter,
+% which is not the default and should not be turned on without caution.
+%
+% The exact mechanics of chart calculation depend on the backend selected.
+% With Swiss Ephemeris, which is the default, the package runs the ``test''
+% program |swetest| once for each object and once more for all cusps, with
+% the standard-output results directed into a |.hor| file which it will read
+% in to get the data. With Astrolog, the |astrolog| program is run once and
+% told to save its results directly to the |.hor| file as if to be read as
+% options by a later invocation of Astrolog. Then the package reads that
+% and parses the (undocumented) Astrolog command-line format to get the
+% results.
+%
+% Either way, the |\horoobjects| macro already described determines the list
+% of objects whose positions will be calculated, and the positions go into
+% the variables Pos (longitude), DPos (initially equal to longitude, but
+% subject to later adjustment), and Vel (velocity). Pos and DPos are
+% measured from 0\horodegrees\AriesSymbol. Vel is degrees per day, positive
+% for direct and negative for retrograde. Similar Pos and DPos
+% values are calculated for the cusp pseudo-objects CuspI, CuspII, and so on
+% (listed in |\horocusps|). In the case of Swiss Ephemeris, some extra
+% pseudo-objects (Ascendant, MC, ARMC, and Vertex) are always calculated
+% too.
+%
+% The house system used in the calculation can be set by invoking a macro
+% named like |\horo|\meta{system}|Houses| before calling |\horocalculate|.
+% The default for both backends is |\horoPlacidusHouses|. Astrolog supports
+% systems called Alcabitus, Campanus, Equal, EqualMC, Koch, Meridian,
+% Morinus, NeoPorphyry, Placidus, PolichPage, Porphyry, Regiomontanus,
+% Vedic, and Whole. Swiss Ephemeris supports systems called Alcabitus,
+% Axial, Azimuthal, Campanus, Equal, Koch, Krusinski, Morinus, Placidus,
+% PolichPage, Porphyry, Regiomontanus, and Vehlow. Consult the external
+% software's documentation for details of these systems.
+%
+% \changes{v0.91}{2008/08/30}{Documentation on equal-house systems}
+% Please note that despite the inclusion of non-angular house systems like
+% Equal among the choices for the Astrolog backend, their actual utility is
+% severely limited because Astrolog overloads two objects it calls ``Asc''
+% and ``Mid'' to serve as both angles and house cusps; Asc can be the first
+% house cusp, but then Astrolog will not write out the Ascendant, or it can
+% be the Ascendant, but then Astrolog will not write out the first house
+% cusp. A future version of this package will probably solve this issue by
+% running Astrolog twice to get out both pieces of information. Another
+% possibility would be to tell Astrolog to write out the angles, and then
+% derive the first and tenth house cusps by calculating points opposite the
+% seventh and fourth house cusps (which always seem to be house cusps rather
+% than angles). Such a change might also be an opportunity to fix the
+% annoying differences between the Astrolog and Swiss Ephemeris backends, as
+% far as possible. In the mean time, the recommendation for Astrolog users who
+% want equal houses is to select Porphyry (as a system that uses the
+% Ascendant and Midheaven and does not break down near the poles) and then
+% compute house cusps internally to \textsf{horoscop} as described below,
+% rather than attempting to use Astrolog's calculation. Note that the
+% object names for the Ascendant and Midheaven will be CuspI and CuspX, not
+% the Swiss Ephemeris names used in the examples.
+%
+% It is possible for \textsf{horoscop} to calculate its own house cusps
+% internally, to provide equal-sized houses starting from any position. Use
+% \DescribeMacro{\horomakeequalcusps}|\horomakeequalcusps| to make twelve
+% cusps spaced equally (30\horodegrees\ apart) with CuspI set to the single
+% argument. For instance, if using |swetest|, which calculates an object
+% called Ascendant automatically, you can use
+% |\horomakeequalcusps{\horoAscendantPos}| to make equal houses starting
+% from the Ascendant, simulating the ``Equal'' house system that actually is
+% already provided anyway. That particular application may seem pointless;
+% but the feature can also be used with any other object to create house
+% systems unavailable from the backend. Someone who wanted to drop the
+% concept of houses entirely, as for an unknown birth time, but still use a
+% chart template that shows houses, might use |\horomakecusps{0}| to make
+% houses equivalent to signs (Aries=first, Taurus=second, and so on).
+%
+% The |\horomakeequalcusps| macro should be called after |\horocalculate| if
+% it is to take effect, because they overwrite each others' house cusp
+% results. Any house system may be used for the original |\horocalculate|
+% call because the results will be discarded anyway, except for the concern
+% that a broken house calcuation in |\horocalculate| (for instance, using
+% polar latitudes with Placidus and without the |egrep| option) may cause
+% typesetting of the whole document to fail.
+%
+% A similar macro, \DescribeMacro{\horomakesigncusps}|\horomakesigncusps|,
+% makes equally-spaced cusps just like |\horomakeequalcusps| (in fact, using
+% a call to it) but starting from the start of the sign that contains the
+% argument value instead of starting at the argument value itself. This is
+% useful for creating historical whole-sign systems. See also the use of
+% |\horoshiftcusps| described in section~\ref{sub:manipulation} for ways to
+% expand this feature to (for instance) simulate the Vehlow equal-house
+% system, or base the system on the location of a cusp other than the first.
+%
+% Note that in all cases \textsf{horoscop} follows the common astrological
+% practice of computing house cusps based on the intersections of the house
+% boundaries with the ecliptic and then placing objects into houses based
+% solely on their longitude. In effect, the assumption is that all objects
+% are located exactly on the ecliptic. For some house systems (with
+% boundaries that do not follow lines of longitude) it can be argued that it
+% would be better to assign house positions in a way that takes latitude
+% into account. See the article ``The Problems of House Division'' by
+% Deborah Houlding, available online at
+% \url{http://www.skyscript.co.uk/houprob_print.html}, for more discussion
+% of this issue. In some future version \textsf{horoscop} may be extended
+% to provide more options for handling of this kind of thing.
+%
+% Note also that in some house systems, the angles (\CuspISymbol,
+% \CuspVIISymbol, \CuspXSymbol, and \CuspIVSymbol) do not coincide with
+% house cusps, and in such cases you may wish to compute and chart them as
+% extra objects.
+%
+% \DescribeMacro{\horoastrologopt}
+% \DescribeMacro{\horosweopt}
+% The macros |\horoastrologopt| and |\horosweopt| define extra command-line
+% options for the external calculation programs (Astrolog and |swetest|
+% respectively). These default to empty, but may be redefined to pass
+% global configuration settings to these programs.
+%
+% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% \subsection{Entering Positions Manually}
+%
+% If it is not desired to compute the positions with \textsf{horoscop}'s
+% external program interface, they can be entered manually instead. This
+% approach might be useful if you use other software to do your
+% calculations, or if you need to create \TeX\ source that will run on a
+% system without the external calculation software installed. The macros
+% that would be created by |\horocalculate| simply need to be created
+% directly, as in the example below.
+%
+% \begin{verbatim}
+% \def\horoSunPos{267.5002492}\def\horoSunVel{1.0185515}
+% \def\horoMoonPos{229.2067659}\def\horoMoonVel{11.9237313}
+% \def\horoMercuryPos{249.2355412}\def\horoMercuryVel{1.4004420}
+% \def\horoVenusPos{229.6610785}\def\horoVenusVel{0.4165367}
+% \def\horoMarsPos{271.9242409}\def\horoMarsVel{0.7571908}
+% \def\horoJupiterPos{228.1368358}\def\horoJupiterVel{0.1927896}
+% \def\horoSaturnPos{128.1056809}\def\horoSaturnVel{-0.0516070}
+% \def\horoUranusPos{79.4428694}\def\horoUranusVel{-0.0421386}
+% \def\horoNeptunePos{190.6482218}\def\horoNeptuneVel{0.0133648}
+% \def\horoPlutoPos{133.0955746}\def\horoPlutoVel{-0.0150157}
+% \def\horoNorthNodePos{70.7814892}\def\horoNorthNodeVel{-0.0529425}
+% \def\horoLilithPos{265.3475147}\def\horoLilithVel{0.1108368}
+% \def\horoCuspI{207.9120843}
+% \def\horoCuspII{236.5553269}
+% \def\horoCuspIII{267.6976404}
+% \def\horoCuspIV{300.5365877}
+% \def\horoCuspV{332.9973490}
+% \def\horoCuspVI{2.5292853}
+% \def\horoCuspVII{27.9120843}
+% \def\horoCuspVIII{56.5553269}
+% \def\horoCuspIX{87.6976404}
+% \def\horoCuspX{120.5365877}
+% \def\horoCuspXI{152.9973490}
+% \def\horoCuspXII{182.5292853}
+% \end{verbatim}
+%
+% A few less obvious macros also need to be set for manually-entered
+% positions to work correctly. Load |\horoobjects| with a list of the
+% objects with manual positions, and set the DPos values to match the Pos
+% values. The |\horocopyvar| macro can help with setting DPos. Finally, set
+% the \DescribeMacro{\horocalculatedtrue}|\horocalculatedtrue| flag so that
+% other parts of the system will know there is valid data in the variables.
+% That flag is normally set by the calculation interface when it has read
+% usable data from the backend.
+%
+% \begin{verbatim}
+% \def\horoobjects{Sun,Moon,Mercury,Venus,Mars,Jupiter,Saturn,%
+% Uranus,Neptune,Pluto,NorthNode,Lilith}
+% \horocopyvar{\horoobjects}{Pos}{DPos}
+% \horocopyvar{\horocusps}{Pos}{DPos}
+% \horocalculatedtrue
+% \end{verbatim}
+%
+% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% \subsection{Saving and Manipulating Positions}
+% \label{sub:manipulation}
+%
+% In documents that contain multiple charts it may be useful to save the
+% results of one calculation for use later. Something similar is also
+% required for single charts that contain more than one person's objects, or
+% for mixing the results of one calculation with another as when making
+% synastry charts. The package provides macros for storing results in
+% macros to handle these situations.
+%
+% The \DescribeMacro{\horosaveobjects}|\horosaveobjects| macro takes one
+% argument which is the name of a new macro to create (or to redefine,
+% without warning, if it already exists). All the Pos and Vel values for
+% objects in |\horoobjects|, and the current value of |\horoobjects| itself,
+% are stored in the newly defined macro. When that macro is run later, it
+% will restore all those values, and set DPos values to the restored Pos
+% values. The effect is that |\horosaveobjects| creates a macro
+% representing the object-related results of the last |\horocalculate|, so
+% we can return to the current state later.
+%
+% The \DescribeMacro{\horosavecusps}|\horosavecusps| macro does something
+% similar, but instead of saving the objects it saves the current values of
+% |\hororightcoord|, |\horocusps|, and the Pos of all cusps. This function
+% is split into a separate macro to make it easy to create synastry charts:
+% calculate one chart, save the objects, calculate the other chart, and
+% restore the first chart's objects, to get one chart's objects in the
+% other's houses.
+%
+% Some manipulations can be applied to calculated positions to alter the
+% appearance of the resulting chart. First, the
+% \DescribeMacro{\hororotatechart}|\hororotatechart|\marg{object}\marg{angle}
+% macro will rotate a chart to
+% place a specified object at a specified place. The default is for CuspVII
+% (the descendant) to be at the right. The angle must be specified
+% in degrees according to the mathematical convention: 0 is to the right and
+% it increases counterclockwise, so 90 is up, 180 is to the left, and
+% 270 is down. For instance, |\hororotatechart{Sun}{90}| would place the
+% Sun at the top. This macro works by manipulating an internal macro called
+% |\hororightcoord|, mentioned above as one of the things saved by
+% |\horosavecusps|. This rotation does not change the actual stored
+% positions of the objects and cusps, only the way in which they will be
+% plotted on the page.
+%
+% The \DescribeMacro{\horocalcharmonic}|\horocalcharmonic|\marg{harmonic}
+% macro multiplies all the Pos values of objects in |\horoobjects| by its
+% argument and sets the Pos and DPos values to the result. The harmonic
+% should be an integer, and no more than 45 (because of \TeX's limits on
+% number magnitude). Higher harmonics, if they are not prime numbers, can
+% be achieved by calling it twice; for instance, with 20 and 10 to get 200.
+% The internal representation of Zodiac positions is only good to
+% approximately $1/18$ of a second of arc in the original position; that
+% will be multiplied by the harmonic, limiting the precision of the result
+% for high harmonics. Your original input data is probably even less good
+% than that. The precision of positions in high-harmonic charts is
+% inherently limited by the nature of high-harmonic charts, and users must
+% understand that. Note also that this macro does not change the house cusp
+% positions. The most popular current practices seem to be to leave cusps
+% unchanged, or not to use them at all, in harmonic charts; and multiplying
+% them like object positions could lead to problematic situations such as
+% cusps ending up out of order, especially in higher harmonics.
+%
+% \changes{v0.91}{2008/08/30}{Documentation on new shift macros}
+% The macros \DescribeMacro{\horoshiftobjects}|\horoshiftobjects| and
+% \DescribeMacro{\horoshiftcusps}|\horoshiftcusps| apply an additive shift,
+% specified in decimal degrees as the single argument, to all the object or
+% cusp Pos values respectively, and sets the Pos and DPos values to the
+% results. These macros, unlike |\horochartrotate| above, do change the
+% stored values of the variables; they can be seen as moving the planets
+% instead of moving the chart. This kind of shift can be applied to object
+% positions to create solar arc charts. With cusp positions, it can be used
+% to create a variety of equal-house systems that may or may not also be
+% available directly from the calculation backends. For instance, assuming
+% the |swetest| backend, this code will calculate whole-sign houses such
+% that the midheaven is contained in the tenth house:
+% \begin{verbatim}
+% \horocalculate
+% \horomakesigncusps{\horoMCPos}
+% \horoshiftcusps{90}
+% \end{verbatim}
+%
+% That says: calculate the chart, including the implicit pseudo-object
+% ``MC''; create whole-sign houses with CuspI set to the start of
+% the sign containing the MC pseudo-object and CuspX three signs
+% (90\horodegrees) earlier than that; and then shift the cusps forwards
+% 90\horodegrees, so that we end up with CuspX set to the start of the sign
+% containing the MC object. A similar chart but with the midheaven actually
+% on the tenth house cusp (instead of using whole signs), duplicating
+% Astrolog's EqualMC system, could be obtained by substituting
+% |\horomakeequalcusps| for |\horomakesigncusps|.
+%
+% In charts like these where the cusps do not necessarily coincide with the
+% angles, one would probably also want to include MC and Ascendant in
+% |\horoobjects| so that they will be plotted like objects on the chart.
+% The angle-highlighting features of the standard templates remain
+% associated with the angular cusps (CuspI, CuspIV, CuspVII, and CuspX)
+% rather than the angle pseudo-objects like Ascendant and MC. It may be
+% appropriate to turn off the highlighting features for charts in which the
+% angular cusps are not actually the angles, but that is left to the user's
+% discretion.
+%
+% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% \subsection{Printing the Results as Text}
+%
+% Instead of or in addition to printing a wheel chart, one may want to print
+% the numerical values of object positions as text with astrological
+% symbols. The \DescribeMacro{\horodsmstext}|\horodsmstext| macro prints
+% its argument as an astrological longitude with degree, (Zodiac) sign,
+% minutes, and seconds. The argument can be a macro set by |\horocalculate|
+% or a raw number in decimal degrees. For instance,
+% |\horodsmstext{\horoVenusPos}| might print \horodsmstext{229.6610785}.
+%
+% The \DescribeMacro{\horotimetext}|\horotimetext| has a similar function
+% for times. Its argument should be hours after midnight, and it prints the
+% value as hours, minutes, and seconds separated by colons. For instance,
+% |\horotimetext{12.58222}| prints \horotimetext{12.58222}. This might
+% typically be used with |\horocalctime|.
+%
+% For latitudes and longitudes,
+% \DescribeMacro{\horolatlontext}|\horolatlontext| takes three arguments.
+% The first is the number of degrees, which may be positive or negative, and
+% it prints the number of degrees, minutes, and seconds followed by either
+% the second or third argument depending on whether the angle was positive
+% or negative. For instance, |\horolatlontext{50}{N}{S}|
+% and |\horolatlontext{-40}{E}{W}| print \horolatlontext{50}{N}{S}
+% and \horolatlontext{-40}{E}{W}.
+%
+% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% \section{Ready-Made Chart Templates}
+%
+% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% \subsection{Basic Wheel Charts}
+%
+% \DescribeEnv{horoscope}
+% \DescribeMacro{\horowheelVancouver}
+% The package provides several ready-made chart templates for different
+% purposes. The basic wheel chart, similar to the best ones produced by
+% other software, is called Vancouver. It's easy to use in the simplest
+% case: just open a |horoscope| environment and invoke
+% |\horowheelVancouver|, as in the birth chart for John Lennon shown in
+% Figure~\ref{fig:basic-wheel}.
+%
+% \begin{figure}
+% \horocalcparms{1940}{10}{9}{17:30:0}{W2:55:0}{N53:25:0}
+% \horocalculate
+% \begin{horoscope}
+% \horowheelVancouver
+% \end{horoscope}
+%
+% \begin{verbatim}
+% \horocalcparms{1940}{10}{9}{17:30:0}{W2:55:0}{N53:25:0}
+% \horocalculate
+% \begin{horoscope}
+% \horowheelVancouver
+% \end{horoscope}
+% \end{verbatim}
+% \caption{Basic wheel chart (John Lennon).}
+% \label{fig:basic-wheel}
+% \end{figure}
+%
+% The |horoscope| environment is a |picture| environment, 100
+% unit-lengths square with the origin in the centre, so that coordinates
+% range from $-50\ldots 50$ on both axes. The unit length is set to
+% \DescribeMacro{\horounitlength}|\horounitlength|, which defaults to
+% 0.00952 times |\textwidth|, so that a |horoscope| environment will be
+% just slightly less than the full text width of the page. Change it to
+% change the size of horoscope wheels, though if it is changed much the text
+% size will need to be adjusted also.
+%
+% \subsubsection{Notes}
+% \DescribeMacro{\horoULnote}
+% \DescribeMacro{\horoURnote}
+% \DescribeMacro{\horoLLnote}
+% \DescribeMacro{\horoLRnote}
+% \DescribeMacro{\horoCnote}
+% Five macros are provided for typesetting notes in the corners or centre of
+% a wheel chart. They are called |\horoULnote|, |\horoURnote|, |\horoLLnote|,
+% |\horoLRnote|, and |\horoCnote|, for upper left, upper right, lower left,
+% lower right, and centre respectively; each takes a single argument
+% specifying the text to put there, which may include |\\| commands for line
+% breaks. Typesetting is flushed into the corners for corner notes and
+% centred for the centre note. If you're using a chart style that
+% puts things of its own in the space where you want to put a note,
+% then the note will collide with the chart, so depending on configuration
+% it may not always make sense to use all five of these.
+% Figure~\ref{fig:notes} demonstrates the use of these macros.
+%
+% \begin{figure}
+% \horocalcparms{1875}{10}{12}{23:30:0}{W1:31:0}{N52:18:0}
+% \horocalculate
+% \begin{horoscope}
+% \horowheelVancouver
+% \horoULnote{Aleister Crowley\\Natal chart}
+% \horoURnote{Leamington Spa\\1\horodegrees31\horominutes W 52\horodegrees18\horominutes N}
+% \horoLLnote{The Master Therion\\$\tau o\ \mu\eta\gamma\alpha\ \theta\eta\rho\iota o\nu$}
+% \horoLRnote{$7=4$, $666$,\\and other nonsense}
+% \end{horoscope}
+%
+% \begin{verbatim}
+% \horocalcparms{1875}{10}{12}{23:30:0}{W1:31:0}{N52:18:0}
+% \horocalculate
+% \begin{horoscope}
+% \horowheelVancouver
+% \horoULnote{Aleister Crowley\\Natal chart}
+% \horoURnote{Leamington Spa\\
+% 1\horodegrees31\horominutes W 52\horodegrees18\horominutes N}
+% \horoLLnote{The Master Therion\\
+% $\tau o\ \mu\eta\gamma\alpha\ \theta\eta\rho\iota o\nu$}
+% \horoLRnote{$7=4$; 666;\\and other nonsense}
+% \end{horoscope}
+% \end{verbatim}
+% \caption{Corner notes.}
+% \label{fig:notes}
+% \end{figure}
+%
+% \subsubsection{Aspect webs}\label{sub:aspect-web}
+% \DescribeMacro{\horoaspectwebtrue}
+% \DescribeMacro{\horoaspectwebfalse}
+% The pattern in the centre of the Vancouver wheel, showing which objects
+% are or are not in aspect to each other, is called the
+% \emph{aspect web}. It can be turned on and off with |\horoaspectwebtrue|
+% and |\horoaspectwebfalse|.
+%
+% \DescribeMacro{\horoaspectobjectsa}
+% \DescribeMacro{\horoaspectobjectsb}
+% By default, the aspect web will show aspects between any two objects from
+% |\horoobjects|. That may not be desirable in charts with many minor
+% objects; an aspect between two small asteroids may not be important enough
+% to be worth displaying in the web. You can override the default to show
+% only selected aspects by defining new values for |\horoaspectobjectsa| and
+% |\horoaspectobjectsb|. Each should be a comma-separated list of object
+% names; an aspect will be displayed if it goes between one object from one
+% list and one from the other. Thus, if you set one to a list of objects to
+% consider ``major'' while leaving the other set to all objects, you will
+% get an aspect web showing only aspects that involve at least one major
+% object, as in Figure~\ref{fig:selected-aspects}.
+%
+% \begin{figure}
+% \horocalcparms{1949}{9}{24}{2:50:0}{W74:17:0}{N40:16:0}
+% \horocalculate
+% \begin{horoscope}
+% \renewcommand{\horoaspectobjectsa}%
+% {Sun,Moon,Mercury,Venus,Mars,Jupiter,Saturn}
+% \horowheelVancouver
+% \horoULnote{Bruce Springsteen}
+% \end{horoscope}
+%
+% \begin{verbatim}
+% \horocalcparms{1949}{9}{24}{2:50:0}{W74:17:0}{N40:16:0}
+% \horocalculate
+% \begin{horoscope}
+% \renewcommand{\horoaspectobjectsa}%
+% {Sun,Moon,Mercury,Venus,Mars,Jupiter,Saturn}
+% \horowheelVancouver
+% \horoULnote{Bruce Springsteen}
+% \end{horoscope}
+% \end{verbatim}
+% \caption{Limiting the objects for the aspect web.}
+% \label{fig:selected-aspects}
+% \end{figure}
+%
+% \DescribeMacro{\horoaspects}
+% The |\horoaspects| macro stores a list of aspects to include in aspect webs,
+% much in the manner that |\horoobjects| lists objects to include in charts.
+% The default is to include Opposition, Trine, Square, and Sextile. The other
+% predefined aspects users can add to the list are all those for which
+% Symbol macros were defined earlier: Conjunction, Quintile, Biquintile,
+% Quincunx, Semisextile, Semisquare, and Sesquiquadrate. Other
+% (user-defined) aspects may be added by defining
+% |\horo|\meta{aspect}|Symbol|, |\horo|\meta{aspect}|Angle|, and
+% |\horo|\meta{aspect}|Orb| macros, with the angle and orb given in decimal
+% degrees.
+%
+% \subsubsection{House and angle markings}
+% The ready-made wheel templates also support several options for marking
+% the houses and the angles. Exactly which options are supported depends
+% on the template; the Vancouver template supports them all.
+%
+% \DescribeMacro{\horointhouselabelstrue}
+% \DescribeMacro{\horointhouselabelsfalse}
+% \DescribeMacro{\horohouselabel}
+% Internal house labels are numbers that appear inside the houses among the
+% object labels, selected
+% with the |\horointhouselabelstrue| and |\horointhouse|-|labelsfalse| macros.
+% The default
+% is false, because they take up a fair bit of space and can lead to
+% crowding. By default they are uppercase Roman numerals; you can make them
+% be something else by redefining the |\horohouselabel| command to print the
+% |horohouse| \LaTeX\ counter in the desired style.
+%
+% \DescribeMacro{\horoboldanglestrue}
+% \DescribeMacro{\horoboldanglesfalse}
+% \DescribeMacro{\horoanglecuspwidth}
+% With |\horoboldanglestrue| and |\horoboldanglesfalse| the user can select
+% whether to display angular house cusps as extra-bold lines. The default
+% is true. The actual width to use is set by the \LaTeX\ length
+% |\horoanglecuspwidth|, which defaults to 1.44pt.
+%
+% \DescribeMacro{\horoanglearrowstrue}
+% \DescribeMacro{\horoanglearrowsfalse}
+% Angular cusps can also be highlighted by giving them arrowheads; this is
+% selected with |\horoanglearrowstrue| and |\horoanglearrowsfalse|, default
+% true. The size of the arrowheads is fixed as part of the template.
+%
+% Figure~\ref{fig:angle-highlight} shows all the cusp-highlighting features
+% set to the opposite from their defaults.
+%
+% \begin{figure}
+% \horocalcparms{1920}{10}{22}{14:45:0}{W72:35:0}{N42:06:0}
+% \horocalculate
+% \begin{horoscope}
+% \horointhouselabelstrue
+% \horoboldanglesfalse
+% \horoanglearrowsfalse
+% \horowheelVancouver
+% \horoULnote{Timothy Leary}
+% \end{horoscope}
+%
+% \begin{verbatim}
+% \horocalcparms{1920}{10}{22}{14:45:0}{W72:35:0}{N42:06:0}
+% \horocalculate
+% \begin{horoscope}
+% \horointhouselabelstrue
+% \horoboldanglesfalse
+% \horoanglearrowsfalse
+% \horowheelVancouver
+% \horoULnote{Timothy Leary}
+% \end{horoscope}
+% \end{verbatim}
+% \caption{Cusp-highlighting features}
+% \label{fig:angle-highlight}
+% \end{figure}
+%
+% \subsubsection{Smart labels}
+% By default, the Vancouver chart template will display a label for each
+% object containing its symbol, longitude down to the minute of arc, and
+% the retrograde symbol if the object is retrograde. It will automatically
+% adjust the sequence of the different parts of the label so that the
+% longitude part will read in degree-sign-minute order in as close as
+% possible to left-to-right, top-to-bottom order, with the object's symbol
+% at the outside near the rim of the wheel and the retrograde symbol on the
+% inside near the hub. However, this labelling scheme can be customized in
+% several ways.
+%
+% First, the |\horowheelVancouver| command can take an optional argument
+% which is a format string specifying what ``chunks'' should be typeset in
+% each object label. The format string should be some sequence of the
+% letters |d|, |m|, |s|, |z|, |y|, and |r|, which refer respectively to
+% Degrees, Minutes, and Seconds of longitude, Zodiac sign symbol, object
+% sYmbol, and possible Retrograde. If a label string like |ydzmsr| is
+% specified it will be read in an inward direction; that example would
+% typeset object symbols at the outside, then degrees, sign, minutes,
+% seconds, and retrograde at successively smaller radii.
+%
+% If two label strings are specified separated by a slash, then the first
+% one will be used for all labels typeset above an imaginary line drawn at a
+% 45\horodegrees\ angle from lower left to upper right, and the second
+% string will be used for labels below that line. The idea is that for the
+% first class of labels, the preferred reading direction will be inward, and
+% for the second class it will be outward, so by reversing the appropriate
+% letters between the two strings one can keep sections of the label reading
+% in the correct direction. The default format string is |ydzmr/ymzdr|,
+% which implements the default behaviour described above.
+%
+% \DescribeMacro{\horotextsize}
+% The Vancouver chart template automatically adjusts the size of text in its
+% labels according to how much detail was selected in the labels. Formally,
+% it counts the number of letters in the format string (the first one if two
+% were specified) and uses that to index into the sequence of \LaTeX\ type
+% size commands |\Large|, |\large|, |\normalsize|, |\small|, |\scriptsize|,
+% |\scriptsize| (twice---by trial and error, that seems to work best),
+% |\tiny|. That results in larger text for shorter labels. Similar
+% trickery changes the radii on which the different chunks are shown, to
+% keep the labels reasonable-looking even when different levels of detail
+% are chosen. However, this process is by no means foolproof and the result
+% may not be the desired size. If necessary, the |\horotextsize| macro can
+% be changed with |\renewcommand| to a positive or negative size adjustment.
+% For instance, if it is set to |2|, the labels will use text two sizes
+% larger than the default.
+%
+% \changes{v0.91}{2008/08/30}{Label example to use rounding}
+% Figure~\ref{fig:degrees-only} is an example with lower-detail labels
+% than default (showing longitude only down to the degree) and larger text.
+% Rounding options described in section~\ref{sub:rounding} are used because
+% the default rounding assumes the labels will show minutes.
+%
+% \begin{figure}
+% \horocalcparms{1950}{8}{11}{16:45:0}{W121:53:0}{N37:20:0}
+% \horocalculate
+% \begin{horoscope}
+% \renewcommand{\horotextsize}{2}%
+% \hororoundautofalse
+% \hororoundtodegkeepsign
+% \horowheelVancouver[ydzr/yzdr]
+% \horoULnote{Steve Wozniak}
+% \end{horoscope}
+%
+% \begin{verbatim}
+% \horocalcparms{1950}{8}{11}{16:45:0}{W121:53:0}{N37:20:0}
+% \horocalculate
+% \begin{horoscope}
+% \renewcommand{\horotextsize}{2}
+% \hororoundautofalse
+% \hororoundtodegkeepsign
+% \horowheelVancouver[ydzr/yzdr]
+% \horoULnote{Steve Wozniak}
+% \end{horoscope}
+% \end{verbatim}
+% \caption{Custom label string and text size adjustment.}
+% \label{fig:degrees-only}
+% \end{figure}
+%
+% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% \subsection{Dial Charts}
+%
+% The Vancouver chart template is designed for a traditional style of wheel
+% chart with house cusps featuring prominently. For some kinds of
+% interpretation, you may want to focus more on the angles between objects
+% without much reference to house cusps. The dial chart templates are
+% designed to support that kind of view; they emphasize angles and do not
+% include cusps. They are loosely based on the style of charts popular in
+% Cosmobiology; they might also be worthwhile for charts where the birth
+% time or location are unknown, so that house cusps cannot be meaningfully
+% calculated. Templates are offered for comparing up to four sets of
+% objects.
+%
+% All dial charts are printed with the 0\horodegrees\AriesSymbol\ mark at the
+% top. In the case of harmonic charts, that may coincide with other
+% longitudes as well---for instance, 0\horodegrees\CancerSymbol,
+% 0\horodegrees\LibraSymbol, and 0\horodegrees\CapricornSymbol\ on a
+% 90\horodegrees\ dial.
+%
+% \DescribeMacro{\horowheelIqaluit}
+% Figure~\ref{fig:iqaluit} shows the basic single 360\horodegrees\ dial chart
+% style, available through the |\horowheelIqaluit| macro. This macro, like
+% all the dial chart macros, has an optional first argument for a harmonic
+% number. The popular 90\horodegrees\ dial is available with
+% |\horowheelIqaluit[4]|, as shown in Figure~\ref{fig:iqaluit-ninety}.
+% Other harmonics may be chosen to give dials with other numbers of degrees.
+%
+% \begin{figure}
+% \horocalcparms{1942}{11}{2}{2:10:0}{W83:04:0}{N37:45:0}
+% \horocalculate
+% \begin{horoscope}
+% \horoaspectwebfalse
+% \horowheelIqaluit
+% \horoULnote{Larry Flynt}
+% \end{horoscope}
+%
+% \begin{verbatim}
+% \horocalcparms{1942}{11}{2}{2:10:0}{W83:04:0}{N37:45:0}
+% \horocalculate
+% \begin{horoscope}
+% \horoaspectwebfalse
+% \horowheelIqaluit
+% \horoULnote{Larry Flynt}
+% \end{horoscope}
+% \end{verbatim}
+% \caption{Single 360\horodegrees\ dial (Iqaluit).}
+% \label{fig:iqaluit}
+% \end{figure}
+%
+% \begin{figure}
+% \horocalcparms{1926}{4}{9}{22:20:0}{W87:39:0}{N41:52:0}
+% \horocalculate
+% \begin{horoscope}
+% \horowheelIqaluit[4]
+% \horoULnote{Hugh Hefner}
+% \end{horoscope}
+%
+% \begin{verbatim}
+% \horocalcparms{1926}{4}{9}{22:20:0}{W87:39:0}{N41:52:0}
+% \horocalculate
+% \begin{horoscope}
+% \horowheelIqaluit[4]
+% \horoULnote{Hugh Hefner}
+% \end{horoscope}
+% \end{verbatim}
+% \caption{Single 90\horodegrees\ dial (Iqaluit).}
+% \label{fig:iqaluit-ninety}
+% \end{figure}
+%
+% All the dial templates support an aspect web, turned on by default. The
+% aspect web will be based on whatever values are currently in the Pos
+% variables when the chart is drawn, which will normally be the last ones
+% calculated. Most users will probably prefer that those be the positions
+% for the innermost dial in the case of a multi-dial chart, but by careful
+% sequencing or use of |\horosaveobjects|, other selections are possible.
+%
+% As seen in Figure~\ref{fig:iqaluit-ninety}, the aspects refer to the object
+% longitudes {\em after} any harmonic transformation. For instance,
+% Hefner's Moon and Chiron are shown as in opposition in the aspect web
+% because they are close to 180\horodegrees\ apart on the chart. It is a
+% fourth-harmonic chart, the objects are actually about 45\horodegrees\ apart
+% in the sky, and so the aspect is really a semisquare. His Jupiter and
+% Saturn, on the other hand, really are square to each other in the sky, but
+% appear as conjunct on the dial. Users who choose to use an aspect web
+% with harmonic charts are assumed to understand these issues. If desired,
+% the aspect symbols may be redefined to correspond to aspects in the sky
+% (before harmonics) rather than on the chart (after harmonics).
+%
+% If the aspect web is turned off, the dial chart will include a small cross
+% at the centre of the dials, for centering the moveable pointer that some
+% interpreters like to use. Note that that style of interpretation is not
+% part of the author's background; people who do want to do it are
+% encouraged to comment on how the package's features could be better tuned
+% to their purposes.
+%
+% \DescribeMacro{\horowheelIgloolik}
+% The |\horowheelIgloolik| command creates a double dial, as shown in
+% Figure~\ref{fig:igloolik}. It has two required arguments which should be
+% saved object position macros created by the |\horosaveobjects| command, as
+% illustrated by the example code. The first will be used for the inner
+% dial and the second for the outer dial. An optional argument in square
+% brackets may be added before the required ones (in the standard
+% \LaTeX\ usage) for a dial of less than 360\horodegrees.
+%
+% \begin{figure}
+% \horocalcparms{1955}{2}{24}{15:0:0}{W122:25:0}{N37:46:0}
+% \horocalculate\horosaveobjects{\SteveJobs}
+% \horocalcparms{1955}{10}{29}{6:0:0}{W122:20:0}{N47:36:0}
+% \horocalculate\horosaveobjects{\BillGates}
+% \begin{horoscope}
+% \horowheelIgloolik{\BillGates}{\SteveJobs}
+% \horoULnote{Inner: Bill Gates}
+% \horoURnote{Outer: Steve Jobs}
+% \end{horoscope}
+%
+% \begin{verbatim}
+% \horocalcparms{1955}{2}{24}{15:0:0}{W122:25:0}{N37:46:0}
+% \horocalculate\horosaveobjects{\SteveJobs}
+% \horocalcparms{1955}{10}{29}{6:0:0}{W122:20:0}{N47:36:0}
+% \horocalculate\horosaveobjects{\BillGates}
+% \begin{horoscope}
+% \horowheelIgloolik{\BillGates}{\SteveJobs}
+% \horoULnote{Inner: Bill Gates}
+% \horoURnote{Outer: Steve Jobs}
+% \end{horoscope}
+% \end{verbatim}
+% \caption{Double 360\horodegrees\ dial (Igloolik).}
+% \label{fig:igloolik}
+% \end{figure}
+%
+% \DescribeMacro{\horowheelRankin}
+% \DescribeMacro{\horowheelResolute}
+% Triple and quadruple dials are also available, through |\horowheelRankin|
+% and |\horowheelResolute| respectively. These are illustrated in
+% Figures~\ref{fig:resolute} and~\ref{fig:rankin}. Their operation is
+% fundamentally the same as |\horowheelIgloolik|, just extended to three or
+% four sets of objects.
+%
+% \begin{figure}
+% \horocalcparms{1961}{1}{26}{12:45:0}{W80:16:0}{N43:08:0}
+% \horocalculate\horosaveobjects{\WayneGretzky}
+% \horocalcparms{1939}{3}{20}{12:47:0}{W68:30:0}{N49:13:0}
+% \horocalculate\horosaveobjects{\BrianMulroney}
+% \horocalcparms{1938}{11}{17}{12:0:0}{W79:25:0}{N44:37:0}
+% \horocalculate\horosaveobjects{\GordonLightfoot}
+% \begin{horoscope}
+% \horowheelResolute{\GordonLightfoot}{\BrianMulroney}{\WayneGretzky}
+% \horoULnote{Inner: Gordon Lightfoot}
+% \horoURnote{Middle: Brian Mulroney}
+% \horoLLnote{Outer: Wayne Gretzky}
+% \end{horoscope}
+%
+% \begin{verbatim}
+% \horocalcparms{1961}{1}{26}{12:45:0}{W80:16:0}{N43:08:0}
+% \horocalculate\horosaveobjects{\WayneGretzky}
+% \horocalcparms{1939}{3}{20}{12:47:0}{W68:30:0}{N49:13:0}
+% \horocalculate\horosaveobjects{\BrianMulroney}
+% \horocalcparms{1938}{11}{17}{12:0:0}{W79:25:0}{N44:37:0}
+% \horocalculate\horosaveobjects{\GordonLightfoot}
+% \begin{horoscope}
+% \horowheelResolute{\GordonLightfoot}{\BrianMulroney}{\WayneGretzky}
+% \horoULnote{Inner: Gordon Lightfoot}
+% \horoURnote{Middle: Brian Mulroney}
+% \horoLLnote{Outer: Wayne Gretzky}
+% \end{horoscope}
+% \end{verbatim}
+% \caption{Triple 360\horodegrees\ dial (Resolute).}
+% \label{fig:resolute}
+% \end{figure}
+%
+% \begin{figure}
+% \horocalcparms{1934}{2}{6}{2:25:0}{W88:03:0}{N30:41:0}
+% \horocalculate\horosaveobjects{\HankAaron}
+% \horocalcparms{1931}{5}{7}{4:30:0}{W86:55:0}{N33:28:0}
+% \horocalculate\horosaveobjects{\WillieMays}
+% \horocalcparms{1925}{5}{12}{8:0:0}{W90:12:0}{N38:37:0}
+% \horocalculate\horosaveobjects{\YogiBerra}
+% \horocalcparms{1919}{1}{31}{24:30:0}{W84:13:0}{N30:52:0}
+% \horocalculate\horosaveobjects{\JackieRobinson}
+% \begin{horoscope}
+% \horoaspectwebfalse
+% \horowheelRankin{\JackieRobinson}{\YogiBerra}%
+% {\WillieMays}{\HankAaron}
+% \horoCnote{Inner to outer:\\ Jackie Robinson\\
+% Yogi Berra\\ Willie Mays\\ Hank Aaron}
+% \end{horoscope}
+%
+% \begin{verbatim}
+% \horocalcparms{1934}{2}{6}{2:25:0}{W88:03:0}{N30:41:0}
+% \horocalculate\horosaveobjects{\HankAaron}
+% \horocalcparms{1931}{5}{7}{4:30:0}{W86:55:0}{N33:28:0}
+% \horocalculate\horosaveobjects{\WillieMays}
+% \horocalcparms{1925}{5}{12}{8:0:0}{W90:12:0}{N38:37:0}
+% \horocalculate\horosaveobjects{\YogiBerra}
+% \horocalcparms{1919}{1}{31}{24:30:0}{W84:13:0}{N30:52:0}
+% \horocalculate\horosaveobjects{\JackieRobinson}
+% \begin{horoscope}
+% \horoaspectwebfalse
+% \horowheelRankin{\JackieRobinson}{\YogiBerra}%
+% {\WillieMays}{\HankAaron}
+% \horoCnote{Inner to outer:\\ Jackie Robinson\\
+% Yogi Berra\\ Willie Mays\\ Hank Aaron}
+% \end{horoscope}
+% \end{verbatim}
+% \caption{Quadruple 360\horodegrees\ dial (Rankin).}
+% \label{fig:rankin}
+% \end{figure}
+%
+% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% \subsection{Decorative Wheel Charts}
+%
+% The standard wheel chart emphasizes house cusps, and the dial
+% charts concentrate on longitudes without showing the houses. For other
+% styles of interpretation it may be desirable to put more emphasis on the
+% houses containing objects and less on the geometry of objects' physical
+% locations in the sky. The decorative wheel chart templates are designed
+% to support that kind of emphasis, provide visually appealing designs
+% similar to some historical chart styles, and demonstrate the possibilities
+% for customized templates.
+%
+% \DescribeMacro{\horowheelMontreal}
+% The |\horowheelMontreal| macro generates a chart like that shown in
+% Figure~\ref{fig:montreal}. It shows labels for the angular cusps down to
+% the minute of arc and for objects showing object symbol, degree and sign,
+% and possible retrograde. Most of the house cusps are drawn as curves,
+% creating a floral effect. This template does not support an automatic
+% aspect web (it wouldn't make sense because there are no object-location
+% ticks) nor modification of the label content.
+%
+% \begin{figure}
+% \horocalcparms{1942}{11}{27}{17:15:0}{W122:20:0}{N47:36:0}
+% \horocalculate
+% \begin{horoscope}
+% \horowheelMontreal
+% \horoULnote{Jimi Hendrix}
+% \end{horoscope}
+%
+% \begin{verbatim}
+% \horocalcparms{1942}{11}{27}{17:15:0}{W122:20:0}{N47:36:0}
+% \horocalculate
+% \begin{horoscope}
+% \horowheelMontreal
+% \horoULnote{Jimi Hendrix}
+% \end{horoscope}
+% \end{verbatim}
+% \caption{Decorative chart template (Montreal).}
+% \label{fig:montreal}
+% \end{figure}
+%
+% \DescribeMacro{\horowheelQuebecCity}
+% The |\horowheelQuebecCity| macro is another take on the decorative wheel
+% chart concept: here eight houses are on the outside and four on the
+% inside, in contrast to the eight on the inside and four around the outside
+% of the Montreal template. As a result of the different layout it becomes
+% possible to draw the cusps as straight lines rather than curves. The
+% result is shown in Figure~\ref{fig:quebec-city}. This template style
+% shows degree-sign-minute labels for all twelve cusps, and
+% degree-sign-retrograde labels for objects. As with Montreal, the label
+% detail is fixed and there is no provision for an aspect web (which would
+% need to be stretched to fit the roughly square shape of the wheel's hub).
+%
+% \begin{figure}
+% \horocalcparms{1958}{8}{16}{12:05:0}{W83:54:0}{N43:36:0}
+% \horocalculate
+% \begin{horoscope}
+% \horowheelQuebecCity
+% \horoULnote{Madonna Ciccone}
+% \end{horoscope}
+%
+% \begin{verbatim}
+% \horocalcparms{1958}{8}{16}{12:05:0}{W83:54:0}{N43:36:0}
+% \horocalculate
+% \begin{horoscope}
+% \horowheelQuebecCity
+% \horoULnote{Madonna Ciccone}
+% \end{horoscope}
+% \end{verbatim}
+% \caption{Decorative chart template (QuebecCity).}
+% \label{fig:quebec-city}
+% \end{figure}
+%
+% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% \section{Advanced Topics}
+%
+% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% \subsection{Rounding and Mixed-Base Conversion}
+% \label{sub:rounding}
+% \changes{v0.91}{2008/07/04}{Added smart rounding features}
+%
+% \subsubsection{The rounding problem}
+% Astrologers traditionally describe Zodiac positions with a mixed-base
+% number system in which a position might be written like
+% 2\horodegrees\AriesSymbol34\horominutes56\horoseconds. This format
+% descends from Babylonian sexagesimal arithmetic, representing fractions in
+% terms of multiples of powers of $1/60$. It is convenient for hand
+% calculation and human analysis because it makes it easy for humans to
+% recognize important boundaries (like sign cusps) and relationships
+% (like aspects). Humans are generally good at doing arithmetic on small
+% integers, which is the necessary skill for using this representation.
+%
+% The mixed-base system is less convenient for computer arithmetic, however.
+% Computers generally record positions in other formats, such as floating-
+% or fixed-point degrees, radians, or ``centiseconds'' past
+% the Pisces-Aries cusp; \textsf{horoscop} in particular uses degrees
+% stored in \TeX\ length variables with a scaling of 1\horodegrees=1pt. At
+% that scale the inherent precision of a \TeX\ length means that the angles
+% can be reproduced to an accuracy of $1\horodegrees/65536$, which is
+% just under $1/18$ of a second of arc.
+%
+% When an internal-format Zodiac position has to be displayed in
+% human-readable form, some kind of rounding must necessarily occur. Each
+% position needs a name. A name like
+% 2\horodegrees\AriesSymbol34\horominutes56\horoseconds\ strictly speaking
+% represents just one point on the Zodiac. There are an infinite number of
+% points and only a finite number of possible names (about 1.3~million if we
+% use whole seconds of arc as the precision level); so for any given point
+% on the Zodiac, in general there will be no name exactly describing its
+% location. How shall we assign names to points? Most astrological
+% software has built-in arbitrary and undocumented assumptions on how to
+% round positions for display; in \textsf{horoscop}, we attempt to do it
+% in a more principled way, and expose the decisions to interested users.
+%
+% Rounding is already a serious issue in general numerical computation, and
+% people have developed a variety of solutions to serve varying purposes.
+% Some of them are non-obvious---for instance, the ``banker's rounding''
+% rule designed to reduce overall rounding error when taking the sum of a
+% set of rounded numbers. Rounding for astrological purposes presents
+% unique challenges because of the way humans will use the rounded results.
+% In particular, sign and degree boundaries are important in astrology and
+% otherwise-good rounding schemes may cause problems if they do not respect
+% those boundaries.
+%
+% For example, suppose some object in a horoscope has a Zodiac position
+% 29.9999\horodegrees\ past the Pisces-Aries cusp. It is before the
+% Aries-Taurus cusp, but by less than half a second of arc. If we round it
+% to the nearest second, we get
+% 0\horodegrees\TaurusSymbol0\horominutes0\horoseconds. That misrepresents
+% the position in an important way: the object has not yet entered Taurus,
+% but the rounded position says it has. A similar issue shows up around the
+% 10\horodegrees\ and 20\horodegrees\ boundaries if we are interested in
+% decans; or around \emph{all} the degree boundaries if we are interested in
+% Sabian symbols.
+%
+% This kind of issue also becomes worse when positions are rounded to larger
+% units (minutes or degrees). With rounding to the nearest degree, a
+% position can be represented as being in the next sign while actually being
+% up to half a degree before the cusp. In the case of the Sun in
+% particular, this kind of issue can only exacerbate existing public
+% misunderstandings of what Sun-sign cusps actually mean. See
+% Figure~\ref{fig:pure-round-deg}: the range of positions that will be
+% labelled as a particular sign in a pure round-to-nearest-degree scheme
+% actually starts half a degree before the start of the sign and ends half a
+% degree before the end of the sign. Pure rounding seems to be a problem if
+% we care about which signs things are really in.
+%
+% \begin{figure}
+% \begin{center}
+% \setlength{\unitlength}{1.2pt}
+% \begin{picture}(260,50)(-130,-20)
+% \put(-125,0){\line(1,0){250}}
+% \multiput(-120,-2)(10,0){25}{\line(0,1){4}}
+% \put(-120,-5){\line(0,1){10}}
+% \put(-60,-5){\line(0,1){10}}
+% \put(0,-5){\line(0,1){10}}
+% \put(60,-5){\line(0,1){10}}
+% \put(120,-5){\line(0,1){10}}
+% \put(-120,-10){\makebox(0,0){28\horodegrees\AriesSymbol}}
+% \put(-60,-10){\makebox(0,0){29\horodegrees\AriesSymbol}}
+% \put(0,-10){\makebox(0,0){0\horodegrees\TaurusSymbol}}
+% \put(60,-10){\makebox(0,0){1\horodegrees\TaurusSymbol}}
+% \put(120,-10){\makebox(0,0){2\horodegrees\TaurusSymbol}}
+% \put(-120,20){\makebox(0,0){28\horodegrees\AriesSymbol}}
+% \put(-109,20){\line(1,0){19}}
+% \put(-90,20){\makebox(0,0){)}}
+% \put(-90,10){\makebox(0,0){[}}
+% \put(-90,10){\line(1,0){19}}
+% \put(-60,10){\makebox(0,0){29\horodegrees\AriesSymbol}}
+% \put(-49,10){\line(1,0){19}}
+% \put(-30,10){\makebox(0,0){)}}
+% \put(-30,20){\makebox(0,0){[}}
+% \put(-30,20){\line(1,0){22}}
+% \put(0,20){\makebox(0,0){0\horodegrees\TaurusSymbol}}
+% \put(8,20){\line(1,0){22}}
+% \put(30,20){\makebox(0,0){)}}
+% \put(30,10){\makebox(0,0){[}}
+% \put(30,10){\line(1,0){22}}
+% \put(60,10){\makebox(0,0){1\horodegrees\TaurusSymbol}}
+% \put(68,10){\line(1,0){22}}
+% \put(90,10){\makebox(0,0){)}}
+% \put(90,20){\makebox(0,0){[}}
+% \put(90,20){\line(1,0){22}}
+% \put(120,20){\makebox(0,0){2\horodegrees\TaurusSymbol}}
+% \end{picture}
+% \end{center}
+% \caption{Pure rounding to nearest degree.}
+% \label{fig:pure-round-deg}
+% \end{figure}
+%
+% One possible solution is to use pure truncation, as shown in
+% Figure~\ref{fig:truncate-deg}. This approach has the advantage of being
+% very simple. Each name corresponds to an interval stretching from the
+% named point to the next named point. All the intervals are the same size.
+% It respects sign and degree boundaries, and smaller-unit boundaries when
+% generalized to higher precision. The lower-precision truncated version of
+% any position is always identical to the most significant few digits of the
+% higher-precision truncated version. However, because the labels refer to
+% the lower extremes of the rounding intervals, this approach maximizes the
+% rounding error. A position truncated to the next lower degree may be as
+% much as one degree away from its named position; and it may be much closer
+% to the next degree than to its named position. Because this scheme is
+% asymmetrical, truncating a batch of randomly chosen points to the degree
+% level will tend to shift them backwards by an average of half a degree.
+%
+% \begin{figure}
+% \begin{center}
+% \setlength{\unitlength}{1.2pt}
+% \begin{picture}(260,50)(-130,-20)
+% \put(-125,0){\line(1,0){250}}
+% \multiput(-120,-2)(10,0){25}{\line(0,1){4}}
+% \put(-120,-5){\line(0,1){10}}
+% \put(-60,-5){\line(0,1){10}}
+% \put(0,-5){\line(0,1){10}}
+% \put(60,-5){\line(0,1){10}}
+% \put(120,-5){\line(0,1){10}}
+% \put(-120,-10){\makebox(0,0){28\horodegrees\AriesSymbol}}
+% \put(-60,-10){\makebox(0,0){29\horodegrees\AriesSymbol}}
+% \put(0,-10){\makebox(0,0){0\horodegrees\TaurusSymbol}}
+% \put(60,-10){\makebox(0,0){1\horodegrees\TaurusSymbol}}
+% \put(120,-10){\makebox(0,0){2\horodegrees\TaurusSymbol}}
+% \put(-120,10){\makebox(0,0){)}}
+% \put(-120,20){\makebox(0,0){[}}
+% \put(-120,20){\line(1,0){19}}
+% \put(-90,20){\makebox(0,0){28\horodegrees\AriesSymbol}}
+% \put(-79,20){\line(1,0){19}}
+% \put(-60,20){\makebox(0,0){)}}
+% \put(-60,10){\makebox(0,0){[}}
+% \put(-60,10){\line(1,0){19}}
+% \put(-30,10){\makebox(0,0){29\horodegrees\AriesSymbol}}
+% \put(-19,10){\line(1,0){19}}
+% \put(0,10){\makebox(0,0){)}}
+% \put(0,20){\makebox(0,0){[}}
+% \put(0,20){\line(1,0){22}}
+% \put(30,20){\makebox(0,0){0\horodegrees\TaurusSymbol}}
+% \put(38,20){\line(1,0){22}}
+% \put(60,20){\makebox(0,0){)}}
+% \put(60,10){\makebox(0,0){[}}
+% \put(60,10){\line(1,0){22}}
+% \put(90,10){\makebox(0,0){1\horodegrees\TaurusSymbol}}
+% \put(98,10){\line(1,0){22}}
+% \put(120,10){\makebox(0,0){)}}
+% \put(120,20){\makebox(0,0){[}}
+% \end{picture}
+% \end{center}
+% \caption{Truncation to degree.}
+% \label{fig:truncate-deg}
+% \end{figure}
+%
+% Another option might be to do rounding to nearest at the lowest level, but
+% add extra rounding boundaries, and extra names, to solve the ``signs start
+% too early'' problem. There are many equivalent ways of stating this
+% scheme; one way to describe it is that we use truncation for all
+% mixed-base digits except the least significant and then round the least
+% significant digit to nearest without allowing it to carry into higher
+% digits. The result is shown schematically in
+% Figure~\ref{fig:nocarry-round-deg}.
+%
+% In the rounding without carry scheme, a position very near the end of
+% Aries might be named 30\horodegrees\AriesSymbol. Such a name may be
+% upsetting to readers who expect every sign to contain 30 degrees named
+% 0\horodegrees\ldots29\horodegrees. It also creates strange exceptional
+% degrees at either end of every sign: 0\horodegrees\ and 30\horodegrees\
+% are each 30\horominutes\ long, while 1\horodegrees\ldots29\horodegrees\
+% are 60\horominutes\ each. However, it has significant advantages. It
+% makes the sign boundaries clear; it makes positions near sign boundaries
+% stand out in an obvious way to informed readers; it keeps the maximum
+% rounding error to half a degree, improving on truncation's maximum error
+% of one degree; and because of its symmetry, randomly chosen points do not
+% tend to shift in a particular direction under this scheme. This scheme is
+% used by some printed ephemerides, and is preferred by the author of
+% \textsf{horoscop}.
+%
+% \begin{figure}
+% \begin{center}
+% \setlength{\unitlength}{1.2pt}
+% \begin{picture}(260,50)(-130,-20)
+% \put(-125,0){\line(1,0){250}}
+% \multiput(-120,-2)(10,0){25}{\line(0,1){4}}
+% \put(-120,-5){\line(0,1){10}}
+% \put(-60,-5){\line(0,1){10}}
+% \put(0,-5){\line(0,1){10}}
+% \put(60,-5){\line(0,1){10}}
+% \put(120,-5){\line(0,1){10}}
+% \put(-120,-10){\makebox(0,0){28\horodegrees\AriesSymbol}}
+% \put(-60,-10){\makebox(0,0){29\horodegrees\AriesSymbol}}
+% \put(0,-10){\makebox(0,0){0\horodegrees\TaurusSymbol}}
+% \put(60,-10){\makebox(0,0){1\horodegrees\TaurusSymbol}}
+% \put(120,-10){\makebox(0,0){2\horodegrees\TaurusSymbol}}
+% \put(-120,20){\makebox(0,0){28\horodegrees\AriesSymbol}}
+% \put(-109,20){\line(1,0){19}}
+% \put(-90,20){\makebox(0,0){)}}
+% \put(-90,10){\makebox(0,0){[}}
+% \put(-90,10){\line(1,0){19}}
+% \put(-60,10){\makebox(0,0){29\horodegrees\AriesSymbol}}
+% \put(-49,10){\line(1,0){19}}
+% \put(-30,10){\makebox(0,0){)}}
+% \put(-30,20){\makebox(0,0){[}}
+% \put(-30,20){\line(1,0){4}}
+% \put(-15,20){\makebox(0,0){30\horodegrees\AriesSymbol}}
+% \put(-4,20){\line(1,0){4}}
+% \put(0,20){\makebox(0,0){)}}
+% \put(0,10){\makebox(0,0){[}}
+% \put(0,10){\line(1,0){7}}
+% \put(15,10){\makebox(0,0){0\horodegrees\TaurusSymbol}}
+% \put(22,10){\line(1,0){8}}
+% \put(30,10){\makebox(0,0){)}}
+% \put(30,20){\makebox(0,0){[}}
+% \put(30,20){\line(1,0){22}}
+% \put(60,20){\makebox(0,0){1\horodegrees\TaurusSymbol}}
+% \put(68,20){\line(1,0){22}}
+% \put(90,20){\makebox(0,0){)}}
+% \put(90,10){\makebox(0,0){[}}
+% \put(90,10){\line(1,0){22}}
+% \put(120,10){\makebox(0,0){2\horodegrees\TaurusSymbol}}
+% \end{picture}
+% \end{center}
+% \caption{Rounding without carry.}
+% \label{fig:nocarry-round-deg}
+% \end{figure}
+%
+% Some astrological software uses another scheme, illustrated in
+% Figure~\ref{fig:clamped-round-deg}, where positions are in general rounded
+% to nearest but the rule changes to truncation at the end of each sign.
+% This is essentially the same as the previous rounding mode with the added
+% rule that any digit given an out of range value (such as 30\horodegrees)
+% is changed to the next lower value. Swiss Ephemeris offers this as one of
+% several options in the |swe_split_deg| library function, along with a
+% similar mode that introduces truncation at the end of every degree. These
+% rounding schemes obey sign (or degree) boundaries, and preserve the
+% advantages of rounding to nearest elsewhere. However, this technique is
+% asymmetrical, and it creates two different kinds of exceptional degrees
+% around sign boundaries: 0\horodegrees\ is 30\horominutes\ long,
+% 1\horodegrees\ldots28\horodegrees\ are 60\horominutes\ each, and then
+% 29\horodegrees\ is 90\horominutes. This technique is mentioned for
+% completeness and because some users may want it; it is not particularly
+% recommended. Its advantage over rounding without carry is that it will
+% never produce confusing labels like 30\horodegrees.
+%
+% \begin{figure}
+% \begin{center}
+% \setlength{\unitlength}{1.2pt}
+% \begin{picture}(260,50)(-130,-20)
+% \put(-125,0){\line(1,0){250}}
+% \multiput(-120,-2)(10,0){25}{\line(0,1){4}}
+% \put(-120,-5){\line(0,1){10}}
+% \put(-60,-5){\line(0,1){10}}
+% \put(0,-5){\line(0,1){10}}
+% \put(60,-5){\line(0,1){10}}
+% \put(120,-5){\line(0,1){10}}
+% \put(-120,-10){\makebox(0,0){28\horodegrees\AriesSymbol}}
+% \put(-60,-10){\makebox(0,0){29\horodegrees\AriesSymbol}}
+% \put(0,-10){\makebox(0,0){0\horodegrees\TaurusSymbol}}
+% \put(60,-10){\makebox(0,0){1\horodegrees\TaurusSymbol}}
+% \put(120,-10){\makebox(0,0){2\horodegrees\TaurusSymbol}}
+% \put(-120,20){\makebox(0,0){28\horodegrees\AriesSymbol}}
+% \put(-109,20){\line(1,0){19}}
+% \put(-90,20){\makebox(0,0){)}}
+% \put(-90,10){\makebox(0,0){[}}
+% \put(-90,10){\line(1,0){34}}
+% \put(-45,10){\makebox(0,0){29\horodegrees\AriesSymbol}}
+% \put(-34,10){\line(1,0){34}}
+% \put(0,10){\makebox(0,0){)}}
+% \put(0,20){\makebox(0,0){[}}
+% \put(0,20){\line(1,0){7}}
+% \put(15,20){\makebox(0,0){0\horodegrees\TaurusSymbol}}
+% \put(22,20){\line(1,0){8}}
+% \put(30,20){\makebox(0,0){)}}
+% \put(30,10){\makebox(0,0){[}}
+% \put(30,10){\line(1,0){22}}
+% \put(60,10){\makebox(0,0){1\horodegrees\TaurusSymbol}}
+% \put(68,10){\line(1,0){22}}
+% \put(90,10){\makebox(0,0){)}}
+% \put(90,20){\makebox(0,0){[}}
+% \put(90,20){\line(1,0){22}}
+% \put(120,20){\makebox(0,0){2\horodegrees\TaurusSymbol}}
+% \end{picture}
+% \end{center}
+% \caption{Rounding with truncation at end of sign.}
+% \label{fig:clamped-round-deg}
+% \end{figure}
+%
+% A philosophical issue exists regarding treatment of points that may happen
+% to be exactly on sign boundaries. Is the exact equinoctial point, for
+% instance, properly described as part of Aries, part of Pisces, neither, or
+% both? This is essentially the same question as whether the exact moment
+% of noon (in civil time) should be called ``12:00~AM,'' ``12:00~PM,'' or
+% something special of its own. In mathematical terms, the question is
+% whether signs are open or closed at their ends. As implied by the use of
+% ``['' and ``)'' in the figures in this section, \textsf{horoscop} assumes
+% that signs are half-open intervals closed at the beginning and open at the
+% end, so that the equinoctial point is part of Aries and not part of
+% Pisces. This approach is consistent with the convention that noon is
+% 12:00~PM and midnight is 12:00~AM.
+%
+% It is possible to argue using antiscion relationships that the Zodiac
+% ought to be symmetric under a flip between retrograde and direct. The
+% half-open interval scheme breaks that symmetry. Preserving it would
+% require that cusps must be in both signs, or in neither---like saying that
+% noon and midnight must always be called noon and midnight instead of AM or
+% PM, or that ``12:00~AM'' and ``12:00~PM'' each refer to both moments.
+% Such an approach has obvious problems for computer systems that try to
+% assign one of twelve sign symbols to every position. Because of the
+% limited precision both of computer arithmetic and the observations on
+% which astrological calculations ultimately rest, it is not clear that we
+% can ever really say a calculated position is \emph{exactly} on a cusp
+% anyway; there is always some amount of fuzz;\footnote{The eminent
+% Professor Doron Zeilberger has suggested an ``ultrafinitist''
+% intepretation under which the real number line itself has limited
+% precision, so that points exactly on certain boundaries do not necessarily
+% exist \emph{even in theory}. He was probably joking, but so might I be.
+% See \emph{``Real'' Analysis is a Degenerate Case of Discrete Analysis},
+% D.~Zeilberger,
+% \url{http://www.math.rutgers.edu/~zeilberg/mamarim/mamarimhtml/real.html}.}
+% so the decision on how to represent truly exact cusps seems not to be of
+% much practical consequence anyway.
+%
+% \subsubsection{Automatic rounding}
+% The default configuration of \textsf{horoscop} is to automatically choose
+% a sensible rounding mode in each situation. As long as you stick to the
+% ready-made wheel templates, don't change the smart label strings, and
+% don't care about the arcane details described in the previous subsection,
+% you don't need to do anything about rounding and it will just work.
+%
+% \DescribeMacro{\hororoundautofalse}
+% \DescribeMacro{\hororoundautotrue}
+% In more detail: automatic rounding mode selection is on by default. It
+% can be turned off and on with |\hororoundautofalse| and
+% |\hororoundautotrue| respectively. When this mode is active, the package
+% will switch to |\hororoundtoseckeepmin| for text-mode typeset positions from
+% |\horodsmstext|, |\hororoundtruncate| for times and latitude-longitude
+% coordinates, |\hororoundtominkeepdeg| for labels typeset in the Vancouver
+% wheel template, and |\hororoundtodegkeepsign| for labels in the Montreal
+% and Quebec City templates. These modes are described in more detail
+% below. The rationale for their choice is that time and geographic
+% coordinates would have been entered by the user to precision of
+% seconds, and should always match what the user entered. For Zodiac
+% positions as such, the automated choice is rounding without carry, as
+% shown in Figure~\ref{fig:nocarry-round-deg}, generalized to the level of
+% precision in the particular label.
+%
+% If you design a template of your own, it would be a nice added feature to
+% make it automatically choose an appropriate rounding mode when automatic
+% rounding mode selection is in force. \DescribeMacro{\ifhororoundauto} Test
+% it with |\ifhororoundauto|; see the source code of the existing templates
+% for examples of how this test can be used.
+%
+% \subsubsection{Manual rounding modes}
+% When |\hororoundautofalse| is active, the user must choose rounding modes
+% manually. There are 11 basic modes, and six of them can be modified
+% by turning on clamping, for a total of 17 manually-selected rounding
+% modes.
+%
+% \DescribeMacro{\hororoundtruncate}
+% Truncation, as in Figure~\ref{fig:truncate-deg}, is selected by
+% |\hororoundtruncate|. This rounding mode is actually not pure truncation;
+% it adds an offset of $1\horodegrees/65536$ before doing the truncation in
+% order to compensate for precision lost in the internal representation of
+% angles. Without the offset, values entered in degrees or hours, minutes,
+% and integer seconds, converted to internal form, and then converted back,
+% would usually end up one second less than the input value. The offset
+% makes sure that exact whole-second values will survive a round trip
+% conversion. However, if for some reason a really strict truncation with
+% no offset is desired, that can be selected with
+% \DescribeMacro{\hororoundstricttruncate}|\hororoundstricttruncate|. It is
+% not necessary to specify what boundaries to truncate to, because the digit
+% values are the same; if you want less precision, just write out fewer of
+% the mixed-base digits.
+%
+% True rounding to the nearest unit, as shown for degrees in
+% Figure~\ref{fig:pure-round-deg}, is not recommended for the reasons
+% described in the previous subsection. However, it is available if
+% desired, via the macros
+% \DescribeMacro{\hororoundtosec}
+% \DescribeMacro{\hororoundtomin}
+% \DescribeMacro{\hororoundtodeg}
+% |\hororoundtosec|, |\hororoundtomin|, and |\hororoundtodeg|. Note that if
+% you select rounding to a unit larger than seconds, then rounding will put
+% nonsense values in the smaller-unit digits; so, for instance, if using the
+% Vancouver template (which displays degrees and minutes by default) with
+% rounding to the nearest degree, it is important to change the label string
+% to only display degrees.
+%
+% The remaining manual modes specify rounding to the nearest of one unit
+% while keeping the boundaries of a larger unit intact, in a generalization of
+% the scheme shown in Figure~\ref{fig:nocarry-round-deg}. The choices are
+% \DescribeMacro{\hororoundtoseckeepsign}
+% \DescribeMacro{\hororoundtoseckeepdeg}
+% \DescribeMacro{\hororoundtoseckeepmin}
+% \DescribeMacro{\hororoundtominkeepsign}
+% \DescribeMacro{\hororoundtominkeepdeg}
+% \DescribeMacro{\hororoundtodegkeepsign}
+% |\hororoundtoseckeepsign|,
+% |\hororoundtoseckeepdeg|,
+% |\hororoundtoseckeepmin|,
+% |\hororoundtominkeepsign|,
+% |\hororoundtominkeepdeg|, and
+% |\hororoundtodegkeepsign|. In general it is probably most useful to round
+% to the smallest unit you will be displaying and keep the boundaries of the
+% next larger unit (i.e.\ -|seckeepmin|, -|minkeepdeg|, or -|degkeepsign|),
+% but the others are provided to cover some possibilities offered by other
+% software. As with the pure rounding modes, these modes leave garbage in
+% any digits smaller than the rounding unit and you should not display any
+% digits less significant than the one you rounded to.
+%
+% By default the ``keep boundaries'' modes can generate out-of-range digits
+% like 30\horodegrees. If you want to prevent that by switching to
+% truncation (clamping the values) at the ends of higher-level units, as in
+% \DescribeMacro{\hororoundclamptrue}
+% Figure~\ref{fig:clamped-round-deg}, turn on |\hororoundclamptrue|. This
+% modification of the rounding algorithm is deprecated, but provided for
+% compatibility. It can also be used to modify the automatic mode selection
+% of |\hororoundautotrue|. Turn it off with
+% \DescribeMacro{\hororoundclampfalse}
+% |\hororoundclampfalse|.
+%
+% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% \subsection{Adding Custom Objects}
+% \label{sub:adding-objects}
+%
+% The Swiss Ephemeris calculation backend can potentially compute
+% positions for a great many objects beyond the ones enabled by default.
+% This section describes how to add support for a customized object, with
+% the example of adding the dwarf planet 136199~Eris (formerly
+% 2003~UB$_{313}$, once tentatively named Xena) to the birth chart of Lucy
+% Lawless.
+%
+% First, define a |\horo|\meta{object}|SEOpt| macro specifying the
+% |swetest| command-line option(s)
+% for calculating the object's position. For Eris, those are |-ps| (planet
+% to calculate is one of the ``small'' ones to be designated by number) and
+% \changes{v0.92}{2013/05/15}{Use official MPC number for Eris}
+% |-xs136199| (planet number 136199\footnote{For current versions of
+% Swiss Ephemeris. Some versions published between the discovery of the
+% planet and the assignment of its official number referred to it as object
+% number 999001.}). Other asteroid-like objects would be designated
+% similarly; see the |swetest| documentation for how to select other kinds
+% of objects.
+%
+% \begin{verbatim}
+% \newcommand{\horoErisSEOpt}{-ps -xs136199}
+% \end{verbatim}
+%
+% The chart plotting system also needs a |\|\meta{object}|Symbol| macro.
+% The symbol macro can be as complicated as necessary; for the example we
+% just use a letter X.
+%
+% \begin{verbatim}
+% \newcommand{\ErisSymbol}{X}
+% \end{verbatim}
+%
+% Having defined those macros it only remains to add the new object to the
+% |\horoobjects| list and proceed as with any other chart. The result is
+% shown in Figure~\ref{fig:custom-object}.
+%
+% \begin{figure}
+% \horocalcparms{1968}{3}{28}{18:25:0}{E174:46:0}{S36:52:0}
+% \newcommand{\horoErisSEOpt}{-ps -xs136199}
+% \newcommand{\ErisSymbol}{X}
+% \renewcommand{\horoobjects}{Sun,Moon,Mercury,Venus,Mars,Jupiter,Saturn,Uranus,Neptune,Pluto,Eris}
+% \horocalculate
+% \begin{horoscope}
+% \renewcommand{\horotextsize}{1}
+% \horowheelVancouver
+% \horoULnote{Lucy Lawless}
+% \end{horoscope}
+%
+% \begin{verbatim}
+% \horocalcparms{1968}{3}{28}{18:25:0}{E174:46:0}{S36:52:0}
+% \newcommand{\horoErisSEOpt}{-ps -xs136199}
+% \newcommand{\ErisSymbol}{X}
+% \renewcommand{\horoobjects}{Sun,Moon,Mercury,Venus,%
+% Mars,Jupiter,Saturn,Uranus,Neptune,Pluto,Eris}
+% \horocalculate
+% \begin{horoscope}
+% \renewcommand{\horotextsize}{1}
+% \horowheelVancouver
+% \horoULnote{Lucy Lawless}
+% \end{horoscope}
+% \end{verbatim}
+% \caption{Adding a custom object.}
+% \label{fig:custom-object}
+% \end{figure}
+%
+% Adding customized objects for use with the Astrolog calculation backend
+% may be possible, but less easy. Macros would have to be defined for
+% two-way translation between the names used in \textsf{horoscop} and the
+% abbreviations used in the Astrolog command line and output file. That is
+% unsupported and so the macros involved have been given @ names to mark
+% them as private. It is less useful in the case of Astrolog anyway
+% because, unlike Swiss Ephemeris, current Astrolog does not support an
+% arbitrarily growing set of calculable objects.
+%
+% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% \subsection{Special Charts}
+%
+% People sometimes want to compute and display special kinds of charts,
+% other than the basic one representing the time and place of a native's
+% birth. Here are some notes on those.
+%
+% Relocation:
+% A relocation chart is just the chart for a different geographic
+% location at the native's moment of birth, so you can substitute the
+% appropriate coordinates into the |\horocalcparms| command and proceed as
+% with any other chart.
+%
+% Transits, Solar returns, horary, etc.:
+% These charts are also just ordinary charts for special times and
+% locations, so they can be calculated normally given the right data.
+% There is currently no
+% special support for automatically calculating the data to use, for
+% instance to get the exact time of a Solar return.
+%
+% Secondary progressions:
+% A progressed chart is basically a standard birth chart with the birth time
+% advanced (or retarded, in the case of converse progression) by a number of
+% days equal to the number of years since the birth.
+% The package can calculate these with no problem if you enter an
+% appropriately modified birth date and time. However, there is no special
+% support for computing the right data to enter. Some astrologers
+% also use computation methods that are not equivalent to computing a
+% standard chart for any real time and place---for instance, moving house
+% cusps by a fixed angle while moving planets according to their actual
+% motion in the sky. Some of these can be accomplished by computing a
+% standard chart and then using |\horoshiftobjects| or |\horoshiftcusps| to
+% move the objects or cusps by the appropriate angle, but the user must
+% calculate for themselves the angles they wish to use.
+%
+% Solar arc progression:
+% This consists of computing an angle based on the Sun's progression and
+% then adding it uniformly to all the object locations. The result does not
+% represent the sky at any real time and place. This kind of chart can be
+% calculated by computing the original natal chart and then using
+% |\horoshiftobjects| to move the objects through the appropriate angle.
+% There is no built-in support for computing the appropriate angle; the user
+% must provide that,
+%
+% Synastry:
+% A synastry chart normally shows one person's objects in another person's
+% houses. These can be typeset using the |\horosavecusps| command: compute
+% one chart, use |\horosavecusps| to save the cusps to a macro, then compute
+% the other chart and restore the cusps from the first one by calling the
+% created macro before typesetting the synastry chart. See the next section
+% for information on creating an aspect web between the objects of two
+% different charts; though at present, there is no template for showing two
+% sets of objects on a Vancouver-like traditional wheel chart.
+%
+% Midpoint composite:
+% No current support. Many things can go wrong with these charts in the
+% worst case (for instance, house cusps can end up out of sequence if the
+% two ascendants are near opposition), and they do not represent the actual
+% sky at any real time and place. If necessary, they can be typeset by
+% manually setting the Pos variables for the objects, then copying Pos to
+% DPos, before calling the template macros.
+%
+% Time-space midpoint (Davison):
+% This type of midpoint chart does represent the actual sky at a real time
+% and place (the midpoint of the birth times and locations of two people) so
+% it can be obtained by entering the appropriate midpoint with
+% |\horocalcparms| and proceeding normally. There is no built-in support
+% provided for calculating that midpoint, and supporting it would require a
+% clearer definition of geographic ``midpoint.'' Most people\footnote{For
+% instance, based on an inspection of the source code this seems to be what
+% Astrolog does.} seem to do it by
+% computing the numerical midpoint of the latitude and longitude, as angles,
+% but that is not necessarily the same as the midpoint of the great-circle
+% line between the two points, which might have more symbolic
+% validity. This kind of issue seems to be beyond the intended scope of the
+% current version of \textsf{horoscop}.
+%
+% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% \subsection{Aspects Between Two Charts}
+% \label{sub:between-two}
+%
+% The aspect web in the standard chart templates normally shows aspects
+% among the objects within a single chart. By clever hacking of the
+% |\horoaspectobjectsa| and |\horoaspectobjectsb| macros, however, it is
+% possible to make it display aspects between two different sets of objects,
+% for instance between natal and transiting objects. See
+% Figure~\ref{fig:marilyn-transit} for an example.\footnote{The figure shows
+% the death of Marilyn Monroe, an event which happened at an uncertain time;
+% 3:00~AM, when her housekeeper phoned the psychiatrist after discovering
+% the body, was used for the calculation.}
+%
+% \begin{figure}
+% \horocalcparms{1962}{8}{5}{10:0:0}{W118:19:0}{N34:08:0}
+% \horocalculate\horosaveobjects{\MarilynDeath}
+% \horocopyvar{\horoobjects}{Pos}{XPos}
+% \horocalcparms{1926}{6}{1}{17:30:0}{W118:15:0}{N34:04:0}
+% \horocalculate\horosaveobjects{\MarilynBirth}
+% \horocalculate
+% \begin{horoscope}
+% \renewcommand\horoaspectobjectsa{SunX,MoonX,MercuryX,VenusX,MarsX,JupiterX,SaturnX,UranusX,NeptuneX,PlutoX,MeanNodeX,LilithX,ChironX,CeresX,PallasX,JunoX,VestaX}
+% \horowheelIgloolik{\MarilynBirth}{\MarilynDeath}
+% \horoULnote{Inner: Marilyn Monroe (birth)}
+% \horoURnote{Outer: Marilyn Monroe (death)}
+% \horoLLnote{Birth to death aspects}
+% \end{horoscope}
+%
+% \begin{verbatim}
+% \horocalcparms{1962}{8}{5}{10:0:0}{W118:19:0}{N34:08:0}
+% \horocalculate\horosaveobjects{\MarilynDeath}
+% \horocopyvar{\horoobjects}{Pos}{XPos}
+% \horocalcparms{1926}{6}{1}{17:30:0}{W118:15:0}{N34:04:0}
+% \horocalculate\horosaveobjects{\MarilynBirth}
+% \horocalculate
+% \begin{horoscope}
+% \renewcommand\horoaspectobjectsa%
+% {SunX,MoonX,MercuryX,VenusX,MarsX,JupiterX,SaturnX,%
+% UranusX,NeptuneX,PlutoX,%
+% NorthNodeX,LilithX,ChironX,CeresX,PallasX,JunoX,VestaX}
+% \horowheelIgloolik{\MarilynBirth}{\MarilynDeath}
+% \horoULnote{Inner: Marilyn Monroe (birth)}
+% \horoURnote{Outer: Marilyn Monroe (death)}
+% \horoLLnote{Birth to death aspects}
+% \end{horoscope}
+% \end{verbatim}
+% \caption{Aspects between two charts.}
+% \label{fig:marilyn-transit}
+% \end{figure}
+%
+% We start by calculating both sets of objects and saving them to macros
+% named |\MarilynBirth| and |\MarilynDeath|. After calculating the first
+% set we use the |\horocopyvar| macro to copy what is currently in the Pos
+% variable for each object (the positions at death) into a new variable
+% called XPos. Since this is not a standard variable used by the rest of
+% the system, other macros will not touch it by default.
+%
+% Then we redefine |\horoaspectobjectsa| to be the list of default objects
+% with X appended to each of their names. That's the clever bit. When the
+% aspect web attempts to look up the Pos of an object like the Sun, it will
+% look in a macro called |\horoSunXPos|, which is the copied value of Pos
+% from the Sun at the time we did the copying. That is the death
+% location; meanwhile the Pos values will be for the inner chart, using the
+% default value of |\horoaspectobjectsb|. The inner chart is the birth
+% chart, so the aspect web shows aspects between birth objects and death
+% objects.
+%
+% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% \subsection{Label Adjustments}
+%
+% In general, it is desirable to put object labels on the chart in
+% angular positions that correspond to their actual longitudes. However,
+% when objects are close together in longitude, that can result in labels
+% being printed on top of each other. The problem gets worse when other
+% things are added to the chart, such as house cusps and internal house
+% labels. One of the steps in typesetting a wheel chart involves an
+% adjustment process that moves the labels around to keep them from
+% interfering with each other and with house cusps. This process has a
+% number of adjustable parameters, set by redefining internal macros. In
+% general it should not be necessary to change these parameters while using
+% the ready-made templates, but designers of new templates may need to set
+% them, and some changes may also be needed if you modify the sizes of labels.
+%
+% See Figures~\ref{fig:lee-interfering}--\ref{fig:lee-strange} for some
+% examples of the effects of these options. In
+% Figure~\ref{fig:lee-interfering} the adjustment process has been disabled
+% by setting the minimum distances to zero, so labels are free to interfere.
+% Internal house labels are turned on to exacerbate the crowding.
+% In Figure~\ref{fig:lee-default}, the distances have been increased to show
+% how cusps will be modified to expand houses where necessary. Note the
+% crowded eleventh house, which the system has expanded to make room for
+% all the labels that must fit there. In Figure~\ref{fig:lee-strange},
+% the options have been set to prevent cusps from being modified, even at
+% the cost of crowding a house. Note the difference between this situation
+% and Figure~\ref{fig:lee-interfering}, visible for instance in the eighth
+% and ninth houses: labels can still move, but cusps cannot.
+%
+% \begin{figure}
+% \horocalcparms{1940}{11}{27}{15:12:0}{W122:25:0}{N37:47:0}
+% \horocalculate
+% \begin{horoscope}
+% \horointhouselabelstrue
+% \renewcommand{\horotextsize}{2}
+% \renewcommand{\horooomindist}{0}
+% \renewcommand{\horoocmindist}{0}
+% \horowheelVancouver
+% \horoULnote{Bruce Lee}
+% \end{horoscope}
+%
+% \begin{verbatim}
+% \horocalcparms{1940}{11}{27}{15:12:0}{W122:25:0}{N37:47:0}
+% \horocalculate
+% \begin{horoscope}
+% \horointhouselabelstrue
+% \renewcommand{\horotextsize}{2}
+% \renewcommand{\horooomindist}{0}
+% \renewcommand{\horoocmindist}{0}
+% \horowheelVancouver
+% \horoULnote{Bruce Lee}
+% \end{horoscope}
+% \end{verbatim}
+% \caption{Labels printed at their longitudes without adjustment.}
+% \label{fig:lee-interfering}
+% \end{figure}
+%
+% \begin{figure}
+% \horocalcparms{1940}{11}{27}{15:12:0}{W122:25:0}{N37:47:0}
+% \horocalculate
+% \begin{horoscope}
+% \horointhouselabelstrue
+% \renewcommand{\horotextsize}{2}
+% \renewcommand{\horooomindist}{15.0}
+% \renewcommand{\horoocmindist}{10.0}
+% \renewcommand{\horomaxrepulsion}{15.0}
+% \horowheelVancouver
+% \horoULnote{Bruce Lee}
+% \end{horoscope}
+%
+% \begin{verbatim}
+% \horocalcparms{1940}{11}{27}{15:12:0}{W122:25:0}{N37:47:0}
+% \horocalculate
+% \begin{horoscope}
+% \horointhouselabelstrue
+% \renewcommand{\horotextsize}{2}
+% \renewcommand{\horooomindist}{15.0}
+% \renewcommand{\horoocmindist}{10.0}
+% \renewcommand{\horomaxrepulsion}{15.0}
+% \horowheelVancouver
+% \horoULnote{Bruce Lee}
+% \end{horoscope}
+% \end{verbatim}
+% \caption{Extra space between labels.}
+% \label{fig:lee-default}
+% \end{figure}
+%
+% \begin{figure}
+% \horocalcparms{1940}{11}{27}{15:12:0}{W122:25:0}{N37:47:0}
+% \horocalculate
+% \begin{horoscope}
+% \horointhouselabelstrue
+% \renewcommand{\horotextsize}{2}
+% \renewcommand{\horocuspadjusttrigger}{1}
+% \horowheelVancouver
+% \horoULnote{Bruce Lee}
+% \end{horoscope}
+%
+% \begin{verbatim}
+% \horocalcparms{1940}{11}{27}{15:12:0}{W122:25:0}{N37:47:0}
+% \horocalculate
+% \begin{horoscope}
+% \horointhouselabelstrue
+% \renewcommand{\horotextsize}{2}
+% \renewcommand{\horocuspadjusttrigger}{1}
+% \horowheelVancouver
+% \horoULnote{Bruce Lee}
+% \end{horoscope}
+% \end{verbatim}
+% \caption{Crowded houses permitted.}
+% \label{fig:lee-strange}
+% \end{figure}
+%
+% \DescribeMacro{\horooomindist}
+% \DescribeMacro{\horoocmindist}
+% The minimum distance targets in degrees are set by |\horooomindist| (note
+% triple |o| in name) and |\horocmindist|, for ``|\horo| object-object
+% minimum distance'' and ``|\horo| object-cusp minimum distance''
+% respectively. The defaults are 6\horodegrees\ object to object and
+% 4\horodegrees\ object to cusp. Any labels that are separated by less than
+% this will be subject to movement.
+%
+% \DescribeMacro{\horoposattobj}
+% \DescribeMacro{\horoposattcusp}
+% \DescribeMacro{\hororepulsion}
+% The sizes of the adjustments (or strengths of the springs) are determined
+% by three divisors applied to the distances between things and where they
+% should be. Note that these must be integers, and they are {\em divisors},
+% so larger values mean weaker attraction or repulsion. The
+% |\horoposattobj| macro sets the attraction between objects and their
+% longitudes; the |\horoposattcusp| macro is, similarly, the attraction
+% between cusps and their longitudes; and the |\hororepulsion| macro sets
+% the repulsion between things (both cusps and objects) that are closer than
+% their target distances. The defaults are |20|, |7|, and |3| respectively,
+% so cusps spring toward their longitudes about three times as strongly as
+% objects do (if cusps are allowed to move at all), and things that are
+% crowded together spring apart a little more than twice as strongly as
+% that.
+%
+% Note that the spring strength settings are for adjusting
+% the {\em relative} strengths of the different kind of adjustments. It
+% will not work to increase or decrese all three uniformly to make
+% the overall layout looser or tighter, because the system will simply make
+% more or fewer iterations and end up with substantially the same solution.
+% Overall looser-tighter control should instead be exercised by changing
+% the minimum distances.
+%
+% \DescribeMacro{\horosignificantadj}
+% Label adjustment is done by an iterative processes that approximately
+% simulates a system of springs. Each label is subject to tension when it
+% is too close to its neighbours or too far from its longitude, and the
+% system makes small adjustments to the label locations to reduce the
+% tension. The usual way for the process to terminate is if the adjustments
+% become so small as to make no visible difference. The
+% |\horosignificantadjust| macro sets the threshold in degrees for
+% terminating the loop; it defaults to |0.1|.
+%
+% \DescribeMacro{\horoadjcycles}
+% There is also a hard limit on how many cycles of adjustment the system
+% will do, set by |\horoadjcycles|. The default is |30|, which is almost
+% never reached in practice because the |\horosignificantadj| terminating
+% condition will normally trigger before that. However, the
+% |\horoadjcycles| is for each overall attempt at convergence; if cusp
+% adjustment, described next, happens to be triggered, then it will start
+% over with a fresh set of |30| (or however many) iterations.
+%
+% \DescribeMacro{\horocuspadjusttrigger}
+% Adjustment will first try to find a converged solution without moving any
+% house cusps. Once it does, it will compare the worst separation among
+% objects and cusps actually achieved, against the configured target
+% separation. If the result is less than |\horocuspadjusttrigger| as a
+% percentage of the target, then adjustment without moving house cusps is
+% considered to have failed, and the system will try again with house cusps
+% permitted to move. The default is |65|.
+%
+% \DescribeMacro{\horoadjust}
+% The ready-made templates will invoke |\horoadjust| automatically at the
+% right time to adjust the locations of objects, but it can also be invoked
+% manually in the context of user-created templates. Since most of the
+% chart-drawing macros use the current DPos values, it is important to
+% invoke |\horoadjust| at the right time: after all things that should be
+% drawn at the ``true'' Pos locations and before all things that should have
+% their locations adjusted. Consult the source code, and the next section,
+% for examples and information useful in deciding exactly when to run the
+% adjustment.
+%
+% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% \subsection{Designing New Templates}
+%
+% Many users will be content to simply use the provided horoscope wheel
+% templates, but \textsf{horoscop} also provides a set of tools intended for
+% more advanced users to design their own wheels. Interested users are
+% encouraged to read the relevant parts of the source code and its
+% comments for details on how the existing templates work, and imitate their
+% approach. This section provides a brief summary of the user-visible
+% macros provided.
+%
+% \subsubsection{Ticks and keys}
+% Generally, a wheel template starts by drawing the basic furniture that
+% will be shared by all wheels of that type---typically one or more circles,
+% a key showing the twelve sign symbols, and perhaps some radial ticks that
+% provide an angle scale. Circles can be drawn with the ordinary |\circle|
+% command, bearing in mind that the |horoscope| environment is just a
+% |picture| of fixed dimensions. Template authors are urged to design for a
+% basic radius of 50 to match the existing templates.
+%
+% \DescribeMacro{\horoputticks}
+% The |\horoputticks|\marg{r}\marg{length}\marg{interval} macro creates a
+% set of ticks going around the circle starting at
+% 0\horodegrees\AriesSymbol\ and every \meta{interval}\horodegrees\
+% thereafter, with inner radius \meta{r} and length \meta{length}, so that
+% the outer radius is \meta{r}+\meta{length}. All radii are in
+% |\horounitlength| units.
+%
+% \DescribeMacro{\horoputsignkey}
+% The |\horoputsignkey|\marg{r} macro creates a sign key, which consists of
+% all twelve Zodiac sign symbols, each placed with its centre at radius
+% \meta{r} and longitude 15\horodegrees\ into its own sign. One would
+% typically use this along with a set of ticks at 30\horodegrees\ intervals
+% and spanning the radius of the sign key, to mark the boundaries between
+% signs.
+%
+% \subsubsection{Conditionals for use in templates}
+% \DescribeMacro{\ifhorocalculated}
+% Macros that operate on the locations of things---especially
+% |\horoadjust|---will generally take a long time to run or produce ugly
+% results if they happen to run when there are no valid locations in the
+% variables. To avoid that scenario, the ready-made templates wrap all such
+% macros inside an |\ifhorocalculated|\ldots|\fi| conditional; if the
+% template is invoked without valid data, then the relevant parts of the
+% chart will simply be blank in the typeset document. Similar measures are
+% recommended for any newly-defined templates, because it is inevitable that
+% users will eventually attempt to run the template without valid object
+% positions.
+%
+% \DescribeMacro{\ifhorodrawcusps}
+% \DescribeMacro{\ifhoroboldangles}
+% \DescribeMacro{\ifhoroanglearrows}
+% \DescribeMacro{\ifhorointhouselabels}
+% \DescribeMacro{\ifhoroaspectweb}
+% Some user-settable configuration flags are available through the conditional
+% macros named
+% |\ifhorodrawcusps|, |\ifhoroboldangles|, |\ifhoroanglearrows|,
+% |\ifhorointhouselabels|, and |\ifhoroaspectweb|, and template authors
+% may wish to use these to turn on or off special features in the template.
+%
+% \subsubsection{Drawing sets of graphical elements}
+% Most chart designs include sets of lines drawn at angles determined by the
+% positions of objects or cusps. The following macros draw things at the
+% DPos values of sets of items. A template will typically invoke some of
+% these to draw things like the true-location ticks corresponding to
+% objects, then call |\horoadjust| to set the DPos values to keep labels
+% from interfering, then draw the labels and call these macro again to draw
+% things like the possibly-shifted house cusps that are subject to
+% adjustment.
+%
+% \DescribeMacro{\horoputradials}
+% Most templates draw radial lines at angles corresponding to object or cusp
+% longitudes, using |\horoputradials|\marg{objects}\marg{r}\marg{length}.
+% The \meta{objects} argument should be a comma-separated list of things
+% that will describe the longitudes for the radials. It might typically be
+% |\horoobjects|, |\horocusps|, or
+% \DescribeMacro{\horoangularcusps}|\horoangularcusps|. The inner radius is
+% equal to \meta{r}, and the length of each line is \meta{length}. Radials
+% will be drawn at the DPos values for all the listed objects.
+%
+% \DescribeMacro{\horoputarrows}
+% The |\horoputarrows| macro has the same syntax as
+% |\horoputradials|. It places arrowheads (not actually complete arrows)
+% pointing outward with their tips on the circle of radius \meta{r}. The
+% \meta{length} value sets the size of the arrowheads: they will be sized to
+% fit inside boxes of $3\times 2$ this length. To draw complete arrows,
+% draw a matching set of radial lines to connect with the arrowheads.
+%
+% \DescribeMacro{\horoputinthouselabels}
+% Use |\horoputinthouselabels|\marg{radius} to draw a set of internal house
+% labels. For
+% this to work, |\ifhorointhouselabels| must be true and |\horoadjust| must
+% have been called; otherwise, the locations for the labels will not have
+% been calculated. Each house label results in a call to |\horohouselabel|,
+% which by default typesets the |horohouse| \LaTeX\ counter in uppercase Roman
+% numerals. It can be redefined to get some other style. The centres of
+% the labels are set at radius \meta{radius}; they are attracted to the
+% longitudes of the midpoints of the houses, but may be shifted somewhat by
+% the adjustment process to avoid interfering with other labels.
+%
+% \subsubsection{Single linework objects}
+% For finer control, template authors can also invoke macros to draw
+% things on the chart one at a time at specified coordinates, instead of in
+% sets. Object positions are available to use as coordinates, by invoking
+% the relevant variable macros such as |\horoSunDPos|. It is generally
+% preferable to use DPos rather than Pos so as to pick up the results of any
+% adjustment.
+%
+% \DescribeMacro{\horoputradial}
+% Note this is distinct from the similarly-named |\horoputradials|. The
+% |\horo|-|putradial|\marg{radius}\marg{length}\marg{theta} macro draws a
+% radial line out from the point at radius \meta{radius} and
+% longitude \meta{theta} for a length of \meta{length}.
+%
+% \DescribeMacro{\horoputline}
+% The more general line-drawing macro,
+% |\horoputline|\marg{r1}\marg{theta1}\marg{r2}-\marg{theta2}, draws a line
+% between any two points given in polar coordinates.
+%
+% \DescribeMacro{\horoputarrowhead}
+% The |\horoputarrowhead|\marg{r}\marg{theta}\marg{size} macro creates an
+% arrowhead just like the ones made by |\horoputarrows|, at the specified
+% polar coordinates and with the size determined by \meta{size}; the
+% arrowhead fits into a box of $3\times 2$ the value of \meta{size}. It
+% always points outward from the origin.
+%
+% \DescribeMacro{\horoputcurve}
+% The |\horoputcurve|\marg{r1}\marg{theta1}\marg{r2}\marg{theta2} draws a
+% smooth curve connecting two points designated by their polar coordinates.
+% If the points happen to be at the same radius and not too far apart, the
+% curve will approximate a circular arc centred on the origin. If they
+% happen to be at the same longitude (theta coordinate) then the curve will
+% be a straight line. In other cases it will be somewhere in between these.
+% The main intended use is for the jogs drawn when a house cusp is displaced
+% by adjustment in charts like Vancouver, although it was later applied to
+% the floral shapes in Montreal as well. To draw a complete circle instead
+% of an arc, use the existing \LaTeX\ |\circle| macro.
+%
+% \subsubsection{For-each and things to put in it}
+%
+% \DescribeMacro{\horoforeach}
+% To run a macro on every object in a comma-separated list, call
+% |\horoforeach|\marg{list}\marg{macro}. The contents of \meta{macro} will
+% be invoked once for each comma-separated item in \meta{list}, with the
+% item (in curly braces) added to the end. For instance,
+% an invocation of |\horoforeach{x,y,z}{\foo{a}}| would call |\foo{a}{x}|,
+% |\foo{a}{y}|, and
+% |\foo{a}{z}|. The single-item commands below are all designed to take an
+% object or cusp name as their last argument, to make them easy to use with
+% |\horoforeach|.
+%
+% \DescribeMacro{\horoconncurve}
+% The |\horoconncurve|\marg{r1}\marg{r2}\marg{object} macro draws a
+% connecting curve showing the relationship between the Pos and DPos of
+% an object. This would typically be used after |\horoadjust| to connect the
+% label of an object, which might have been moved by adjustment, with the
+% radial tick showing its true longitude. The curve goes from radius
+% \meta{r1} and the object's Pos, to radius \meta{r2} and its DPos.
+%
+% \DescribeMacro{\horoputcusplabel}
+% The |\horoputcusplabel|\marg{radius}\marg{spacing}\marg{object} macro draws a
+% style of label designed to show the longitude of an angle or cusp. This
+% kind of label appears in the Montreal and QuebecCity chart templates. It
+% consists of the degrees, Zodiac sign, and minutes of arc of the object's Pos,
+% placed on the circle at radius \meta{r} with the sign symbol at the
+% object's DPos and the other two things arranged \meta{spacing} degrees
+% away from it on either side, ordered so that they will read
+% degrees-sign-minutes as nearly as possible to left-to-right top-to-bottom.
+%
+% \DescribeMacro{\horoputobjsymbol}
+% The |\horoputobjsymbol|\marg{radius}\marg{object} places an object's symbol
+% at its DPos and the specified radius
+%
+% There are three macros called
+% \DescribeMacro{\horoputobjdeglabel}|\horoputobjdeglabel|,
+% \DescribeMacro{\horoputobjminlabel}|\horoputobjminlabel|, and
+% \DescribeMacro{\horoputobjseclabel}|\horoputobjseclabel| for typesetting a
+% label showing an object's longitude down to the degree, minute, or second of
+% arc. The labels consist of two to four chunks showing the
+% the object's Pos in degrees, sign, and possibly minutes and seconds,
+% arranged radially on concentric circles and ordered to read in
+% degree-sign-minute-second order as nearly as possible to left-to-right
+% top-to-bottom. The macros each take three arguments
+% \marg{radius}\marg{spacing}\marg{object}, where \meta{radius} is the
+% radius on which to place the centre of the innermost label chunk and
+% \meta{spacing} is the spacing between successive chunks outward from
+% there.
+%
+% The
+% \DescribeMacro{\horoputrxlabel}|\horoputrxlabel|\marg{radius}\marg{object}
+% macro typesets an optional retrograde label for the object at the object's
+% DPos and radius \meta{radius}: if the object's Vel is negative then the
+% label will appear as the value of
+% |\horoRetrogradeSymbol| and otherwise it will be blank. A similar
+% function for use in text (possibly in tables showing numeric data) is
+% provided by \DescribeMacro{\hororxtext}|\hororxtext|\marg{object}.
+%
+% The \DescribeMacro{\horoputsmartlabel}|\horoputsmartlabel|\marg{object}
+% macro provides elaborately-configurable labels as seen in the Vancouver
+% template. The macro itself simply plots the label for an object; it must
+% be configured in advance using other macros. First,
+% \DescribeMacro{\horoscanlabels}|\horoscanlabels|\marg{string} takes
+% one or two label format specifiers (separated by a slash if there are two)
+% just as documented for the Vancouver template. After calling that to set
+% the format strings, use
+% \DescribeMacro{\horosetsmartradii}|\horosetsmartradii|%
+% \marg{outer}\marg{stepbase}\marg{stepadj} to set the radii for the chunks of
+% the label. The outermost chunk will be set with its centre at radius
+% \meta{outer}. Successive chunks will be set inside that at a spacing of
+% \meta{stepbase}$-n\times$\meta{stepadj}, where $n$ is the number of
+% chunks. For instance, with |\horosetsmartradii{30}{7}{1}| and four
+% chunks, the radii will be 30, 27, 24, and 21. The reason for this
+% apparently unusual design is that a simple even division of a fixed amount
+% of space tends to produce excessively wide spacing when there are few
+% chunks; with carefully chosen coefficients, this formula seems to produce
+% more visually appealing results across the range of typical label lengths.
+%
+% Label commands set things in the current text size. With smart labels it
+% may be desirable to change the text size depending on how many chunks are
+% in the label; \DescribeMacro{\horochoosetextsize}|\horochoosetextsize| does
+% that, according to the scheme documented for the Vancouver template.
+%
+% \subsubsection{Drawing the aspect web}
+% Low-level macros used in drawing the aspect web are exposed primarily to
+% make it easier to do more sophisticated aspect handling than the default,
+% such as varying the orb based on the objects involved or more carefully
+% selecting which individual aspects to show at all.
+%
+% The macro
+% \DescribeMacro{\horoputaspect}|\horoputaspect|%
+% \marg{radius}\marg{theta1}\marg{theta2}\marg{symbol} draws a single
+% aspect consisting of a line connecting the points at radius \meta{radius}
+% and longitudes \meta{theta1} and \meta{theta2}. The contents of
+% \meta{symbol} will be typeset on the midpoint of the line.
+%
+% To automatically find and draw aspects of a given type, use
+% \DescribeMacro{\horoautoaspect}|\horoautoaspect|-%
+% \marg{list1}\marg{list2}\marg{angle}\marg{orb}\marg{radius}\marg{symbol}.
+% This searches for all
+% pairs of one object from \meta{list1} with one object from \meta{list2}
+% whose Pos values are \meta{angle}\horodegrees\ apart (in either direction)
+% to within \meta{orb}\horodegrees. For each one it invokes |\horoputaspect|
+% with the specified \meta{radius} and \meta{symbol}.
+%
+% Finally, \DescribeMacro{\horoautoaspects}|\horoautoaspects|\marg{radius}
+% (note plural) draws a complete aspect web of the kind demonstrated by the
+% default templates. It loops through the aspects listed in |\horoaspects|
+% running |\horoautoaspect| on each one and using the angle and orb
+% information from the corresponding |\horo|\meta{aspect}|Angle| and
+% |\horo|\meta{aspect}|Orb| macros.
+%
+% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% \StopEventually{}
+%
+% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% \section{Implementation}
+%
+% We start by declaring that this is the start of a \LaTeX$2\varepsilon$
+% package and giving it a name.
+%
+% \begin{macrocode}
+\NeedsTeXFormat{LaTeX2e}[1999/12/01]
+\ProvidesPackage{horoscop}%
+ [2013/05/16 v0.92 Astrological chart macros by Matthew Skala]
+% \end{macrocode}
+%
+% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% \subsection{Initial Option Handling}
+%
+% All the options correspond to Boolean flags created by |\newif|, which
+% then get set appropriately by |\ProcessOptions|. The actual consequences
+% of the options are implemented later.
+%
+% \subsubsection{Symbol choices}
+%
+% These can all be turned on and off independently.
+%
+% \begin{macrocode}
+\newif\ifhoro@textsym\horo@textsymfalse
+\newif\ifhoro@wasysym\horo@wasysymfalse
+\newif\ifhoro@marvosym\horo@marvosymfalse
+\newif\ifhoro@starfont\horo@starfontfalse
+\DeclareOption{textsym}{\horo@textsymtrue}
+\DeclareOption{wasysym}{\horo@wasysymtrue}
+\DeclareOption{marvosym}{\horo@marvosymtrue}
+\DeclareOption{starfont}{\horo@starfonttrue}
+% \end{macrocode}
+%
+% \subsubsection{Calculation backends}
+%
+% At most one of these may be selected, so choosing
+% either also turns off the other one's flag, and the
+% |nocalc| option turns both flags off.
+%
+% \begin{macrocode}
+\newif\ifhoro@strolog\horo@strologfalse
+\newif\ifhoro@swetest\horo@swetesttrue
+\DeclareOption{nocalc}{\horo@strologfalse\horo@swetestfalse}
+\DeclareOption{astrolog}{\horo@strologtrue\horo@swetestfalse}
+\DeclareOption{swetest}{\horo@strologfalse\horo@swetesttrue}
+% \end{macrocode}
+%
+% Declare an |\if| and associated option for |egrep| filtering.
+% \begin{macrocode}
+\newif\ifhoro@egrep\horo@egrepfalse
+\DeclareOption{egrep}{\horo@egreptrue}
+% \end{macrocode}
+%
+% \subsubsection{Higher-level features}
+%
+% Wheels (the general support for drawing wheels) and
+% templates (the specific ready-made wheel designs) can each be turned off.
+% Templates require wheels, so turning off wheels also turns off templates.
+%
+% \begin{macrocode}
+\newif\ifhoro@wheels\horo@wheelstrue
+\newif\ifhoro@templates\horo@templatestrue
+\DeclareOption{nowheels}{\horo@wheelsfalse\horo@templatesfalse}
+\DeclareOption{notemplates}{\horo@templatesfalse}
+% \end{macrocode}
+%
+% \subsubsection{Processing the options}
+%
+% Let \LaTeX\ interpret the option settings.
+%
+% \begin{macrocode}
+\ProcessOptions\relax
+% \end{macrocode}
+%
+% If none of the symbol options were set, then pretend |starfont| was set.
+% This is actually expected to be the most common case in actual use.
+%
+% \begin{macrocode}
+\ifhoro@textsym\else
+ \ifhoro@wasysym\else
+ \ifhoro@marvosym\else
+ \horo@starfonttrue
+ \fi
+ \fi
+\fi
+% \end{macrocode}
+%
+% Load other packages as needed by the selected options. Since
+% there are some name conflicts between macros defined by in different
+% packages and we want to retain access to both versions, we save each
+% package's versions immediately after loading the packages.
+%
+% \begin{macrocode}
+\ifhoro@wasysym
+ \RequirePackage{wasysym}%
+ \let\horow@sySquare\Square
+\fi
+\ifhoro@marvosym
+ \RequirePackage{marvosym}%
+ \let\horom@rvAries\Aries
+ \let\horom@rvTaurus\Taurus
+ \let\horom@rvGemini\Gemini
+ \let\horom@rvCancer\Cancer
+ \let\horom@rvLeo\Leo
+ \let\horom@rvVirgo\Virgo
+ \let\horom@rvLibra\Libra
+ \let\horom@rvScorpio\Scorpio
+ \let\horom@rvSagittarius\Sagittarius
+ \let\horom@rvCapricorn\Capricorn
+ \let\horom@rvAquarius\Aquarius
+ \let\horom@rvPisces\Pisces
+ \let\horom@rvSun\Sun
+ \let\horom@rvMoon\Moon
+ \let\horom@rvMercury\Mercury
+ \let\horom@rvVenus\Venus
+ \let\horom@rvMars\Mars
+ \let\horom@rvJupiter\Jupiter
+ \let\horom@rvSaturn\Saturn
+ \let\horom@rvUranus\Uranus
+ \let\horom@rvNeptune\Neptune
+ \let\horom@rvPluto\Pluto
+\fi
+\ifhoro@starfont\RequirePackage{starfont}%
+ \let\horost@rAries\Aries
+ \let\horost@rTaurus\Taurus
+ \let\horost@rGemini\Gemini
+ \let\horost@rCancer\Cancer
+ \let\horost@rLeo\Leo
+ \let\horost@rVirgo\Virgo
+ \let\horost@rLibra\Libra
+ \let\horost@rScorpio\Scorpio
+ \let\horost@rSagittarius\Sagittarius
+ \let\horost@rCapricorn\Capricorn
+ \let\horost@rAquarius\Aquarius
+ \let\horost@rPisces\Pisces
+ \let\horost@rSun\Sun
+ \let\horost@rMoon\Moon
+ \let\horost@rMercury\Mercury
+ \let\horost@rVenus\Venus
+ \let\horost@rMars\Mars
+ \let\horost@rJupiter\Jupiter
+ \let\horost@rSaturn\Saturn
+ \let\horost@rUranus\Uranus
+ \let\horost@rNeptune\Neptune
+ \let\horost@rPluto\Pluto
+ \let\horost@rSquare\Square
+\fi
+\ifhoro@wheels
+ \RequirePackage{pict2e}
+ \RequirePackage{trig}
+\fi
+% \end{macrocode}
+%
+% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% \subsection{Symbols}
+%
+% \subsubsection{General symbols}
+%
+% No special packages needed for these angle symbols; they're all based
+% on standard \LaTeX\ symbols.
+% \begin{macrocode}
+\def\horodegrees{\ensuremath{^\circ}}
+\def\horominutes{\ensuremath{'}}
+\def\horoseconds{\ensuremath{''}}
+% \end{macrocode}
+%
+%\begin{macro}{\Zodiac}
+% Although \textsf{marvosym} and \textsf{starfont} both provide their own
+% versions of this, we redefine it to use \textsf{horoscop}'s own abstraction
+% layer so it can be applied to all the symbol sets.
+% \begin{macrocode}
+\def\Zodiac#1{\ifcase#1
+ \or\AriesSymbol\or\TaurusSymbol\or\GeminiSymbol
+ \or\CancerSymbol\or\LeoSymbol\or\VirgoSymbol
+ \or\LibraSymbol\or\ScorpioSymbol\or\SagittariusSymbol
+ \or\CapricornSymbol\or\AquariusSymbol\or\PiscesSymbol\fi}
+% \end{macrocode}
+% \end{macro}
+%
+% None of the packages define symbols specifically for mean versus true
+% nodes, so this gets abstracted out and will use whatever the current
+% setting for |\NorthNodeSymbol| might be.
+% \begin{macrocode}
+\def\MeanNodeSymbol{\NorthNodeSymbol$_M$}%
+\def\TrueNodeSymbol{\NorthNodeSymbol$_T$}%
+% \end{macrocode}
+%
+% \subsubsection{Text abbreviations}
+% These are used as defaults and to replace any symbols not provided by
+% other packages. They're all built into the |\horotextsym| command so that
+% users who mix symbol sets will be able to switch \emph{back} to this set
+% after having defined other symbols.
+% \begin{macro}{\horotextsym}
+% \begin{macrocode}
+\newcommand{\horotextsym}{%
+% \end{macrocode}
+%
+% Signs of the Zodiac:
+% \begin{macrocode}
+\gdef\AriesSymbol{Ar}%
+\gdef\TaurusSymbol{Ta}%
+\gdef\GeminiSymbol{Ge}%
+\gdef\CancerSymbol{Cn}%
+\gdef\LeoSymbol{Le}%
+\gdef\VirgoSymbol{Vi}%
+\gdef\LibraSymbol{Li}%
+\gdef\ScorpioSymbol{Sc}%
+\gdef\SagittariusSymbol{Sg}%
+\gdef\CapricornSymbol{Cp}%
+\gdef\AquariusSymbol{Aq}%
+\gdef\PiscesSymbol{Pi}%
+% \end{macrocode}
+%
+% Traditional planets and luminaries:
+% \begin{macrocode}
+\gdef\SunSymbol{Su}%
+\gdef\MoonSymbol{Mo}%
+\gdef\MercurySymbol{Me}%
+\gdef\VenusSymbol{Ve}%
+\gdef\MarsSymbol{Ma}%
+\gdef\JupiterSymbol{Ju}%
+\gdef\SaturnSymbol{Sa}%
+\gdef\UranusSymbol{Ur}%
+\gdef\NeptuneSymbol{Ne}%
+\gdef\PlutoSymbol{Pl}%
+% \end{macrocode}
+%
+% Minor planets:
+% \begin{macrocode}
+\gdef\ChironSymbol{Chi}%
+\gdef\CeresSymbol{Cer}%
+\gdef\PallasSymbol{Pal}%
+\gdef\JunoSymbol{Jun}%
+\gdef\VestaSymbol{Ves}%
+% \end{macrocode}
+%
+% Derived points:
+% \begin{macrocode}
+\gdef\NorthNodeSymbol{No}%
+\gdef\SouthNodeSymbol{SNo}%
+\gdef\LilithSymbol{Lil}%
+% \end{macrocode}
+%
+% House cusps:
+% \begin{macrocode}
+\gdef\CuspISymbol{ASC}%
+\gdef\CuspIISymbol{$2^{nd}$}%
+\gdef\CuspIIISymbol{$3^{rd}$}%
+\gdef\CuspIVSymbol{IC}%
+\gdef\CuspVSymbol{$5^{th}$}%
+\gdef\CuspVISymbol{$6^{th}$}%
+\gdef\CuspVIISymbol{DSC}%
+\gdef\CuspVIIISymbol{$8^{th}$}%
+\gdef\CuspIXSymbol{$9^{th}$}%
+\gdef\CuspXSymbol{MC}%
+\gdef\CuspXISymbol{$11^{th}$}%
+\gdef\CuspXIISymbol{$12^{th}$}%
+% \end{macrocode}
+%
+% Angles (in case these are distinct from house cusps):
+% \begin{macrocode}
+\gdef\AscendantSymbol{ASC}%
+\gdef\MCSymbol{MC}%
+\gdef\VertexSymbol{Vtx}%
+% \end{macrocode}
+%
+% Direction:
+% \begin{macrocode}
+\gdef\horoRetrogradeSymbol{Rx}%
+% \end{macrocode}
+%
+% Aspects:
+% \begin{macrocode}
+\gdef\horoConjunctionSymbol{Con}%
+\gdef\horoOppositionSymbol{Opp}%
+\gdef\horoTrineSymbol{Tri}%
+\gdef\horoSquareSymbol{Sqr}%
+\gdef\horoQuintileSymbol{Qnt}%
+\gdef\horoBiquintileSymbol{Bqi}%
+\gdef\horoSextileSymbol{Sex}%
+\gdef\horoQuincunxSymbol{Qcx}%
+\gdef\horoSemisextileSymbol{Ssx}%
+\gdef\horoSemisquareSymbol{Ssq}%
+\gdef\horoSesquiquadrateSymbol{Sqq}%
+}
+% \end{macrocode}
+% \end{macro}
+%
+% Now invoke |\horotextsym| unconditionally to provide initial defaults.
+% \begin{macrocode}
+\horotextsym
+% \end{macrocode}
+%
+% \subsubsection{Symbols from \textsf{wasysym}}
+%
+% \begin{macro}{\horowasysym}
+% As with |textsym|, the actual setting of the symbol macros is all inside a
+% \textsf{wasysym}-specific macro so that we can switch back to it easily
+% after using other symbol sets.
+% \begin{macrocode}
+\ifhoro@wasysym\newcommand{\horowasysym}{%
+% \end{macrocode}
+%
+% Signs of the Zodiac:
+% \begin{macrocode}
+\gdef\AriesSymbol{\aries}%
+\gdef\TaurusSymbol{\taurus}%
+\gdef\GeminiSymbol{\gemini}%
+\gdef\CancerSymbol{\cancer}%
+\gdef\LeoSymbol{\leo}%
+\gdef\VirgoSymbol{\virgo}%
+\gdef\LibraSymbol{\libra}%
+\gdef\ScorpioSymbol{\scorpio}%
+\gdef\SagittariusSymbol{\sagittarius}%
+\gdef\CapricornSymbol{\capricornus}%
+\gdef\AquariusSymbol{\aquarius}%
+\gdef\PiscesSymbol{\pisces}%
+% \end{macrocode}
+%
+% Traditional planets and luminaries:
+% \begin{macrocode}
+\gdef\SunSymbol{\astrosun}%
+\gdef\MoonSymbol{\rightmoon}%
+\gdef\MercurySymbol{\mercury}%
+\gdef\VenusSymbol{\venus}%
+\gdef\MarsSymbol{\mars}%
+\gdef\JupiterSymbol{\jupiter}%
+\gdef\SaturnSymbol{\saturn}%
+\gdef\UranusSymbol{\uranus}%
+\gdef\NeptuneSymbol{\neptune}%
+\gdef\PlutoSymbol{\pluto}%
+% \end{macrocode}
+%
+% Aspects:
+% \begin{macrocode}
+\gdef\horoConjunctionSymbol{\conjunction}%
+\gdef\horoOppositionSymbol{\opposition}%
+\gdef\horoTrineSymbol{\ensuremath{\bigtriangleup}}%
+\gdef\horoSquareSymbol{\horow@sySquare}%
+\gdef\horoSextileSymbol{\hexstar}%
+}
+% \end{macrocode}
+%
+% Invoke |\horowasysym| to set it as default:
+% \begin{macrocode}
+\horowasysym
+\fi
+% \end{macrocode}
+% \end{macro}
+%
+% \subsubsection{Symbols from \textsf{marvosym}}
+%
+% \begin{macro}{\horomarvosym}
+% As above. Note that because of the macro name conflict between
+% \textsf{marvosym} and \textsf{starfont}, we use the saved copies of
+% \textsf{marvosym}'s symbols instead of the contested names.
+% \begin{macrocode}
+\ifhoro@marvosym\newcommand{\horomarvosym}{%
+% \end{macrocode}
+%
+% Signs of the Zodiac:
+% \begin{macrocode}
+\gdef\AriesSymbol{\horom@rvAries}%
+\gdef\TaurusSymbol{\horom@rvTaurus}%
+\gdef\GeminiSymbol{\horom@rvGemini}%
+\gdef\CancerSymbol{\horom@rvCancer}%
+\gdef\LeoSymbol{\horom@rvLeo}%
+\gdef\VirgoSymbol{\horom@rvVirgo}%
+\gdef\LibraSymbol{\horom@rvLibra}%
+\gdef\ScorpioSymbol{\horom@rvScorpio}%
+\gdef\SagittariusSymbol{\horom@rvSagittarius}%
+\gdef\CapricornSymbol{\horom@rvCapricorn}%
+\gdef\AquariusSymbol{\horom@rvAquarius}%
+\gdef\PiscesSymbol{\horom@rvPisces}%
+% \end{macrocode}
+%
+% Traditional planets and luminaries:
+% \begin{macrocode}
+\gdef\SunSymbol{\horom@rvSun}%
+\gdef\MoonSymbol{\horom@rvMoon}%
+\gdef\MercurySymbol{\horom@rvMercury}%
+\gdef\VenusSymbol{\horom@rvVenus}%
+\gdef\MarsSymbol{\horom@rvMars}%
+\gdef\JupiterSymbol{\horom@rvJupiter}%
+\gdef\SaturnSymbol{\horom@rvSaturn}%
+\gdef\UranusSymbol{\horom@rvUranus}%
+\gdef\NeptuneSymbol{\horom@rvNeptune}%
+\gdef\PlutoSymbol{\horom@rvPluto}%
+}
+% \end{macrocode}
+%
+% Invoke |\horomarvosym| to set it as default:
+% \begin{macrocode}
+\horomarvosym
+\fi
+% \end{macrocode}
+% \end{macro}
+%
+% \subsubsection{Symbols from \textsf{starfont}}
+%
+% \begin{macro}{\horostarfont}
+% This is the preferred set of astrological symbols. Like the others, all the
+% definitions are inside a symbol set selection macro; like
+% \textsf{marvosym}, we use previously saved copies of the package macros
+% instead of invoking the conflicting names directly.
+% \begin{macrocode}
+\ifhoro@starfont\newcommand{\horostarfont}{%
+% \end{macrocode}
+%
+% Signs of the Zodiac:
+% \begin{macrocode}
+\gdef\AriesSymbol{\horost@rAries}%
+\gdef\TaurusSymbol{\horost@rTaurus}%
+\gdef\GeminiSymbol{\horost@rGemini}%
+\gdef\CancerSymbol{\horost@rCancer}%
+\gdef\LeoSymbol{\horost@rLeo}%
+\gdef\VirgoSymbol{\horost@rVirgo}%
+\gdef\LibraSymbol{\horost@rLibra}%
+\gdef\ScorpioSymbol{\horost@rScorpio}%
+\gdef\SagittariusSymbol{\horost@rSagittarius}%
+\gdef\CapricornSymbol{\horost@rCapricorn}%
+\gdef\AquariusSymbol{\horost@rAquarius}%
+\gdef\PiscesSymbol{\horost@rPisces}%
+% \end{macrocode}
+%
+% Traditional planets and luminaries:
+% \begin{macrocode}
+\gdef\SunSymbol{\horost@rSun}%
+\gdef\MoonSymbol{\horost@rMoon}%
+\gdef\MercurySymbol{\horost@rMercury}%
+\gdef\VenusSymbol{\horost@rVenus}%
+\gdef\MarsSymbol{\horost@rMars}%
+\gdef\JupiterSymbol{\horost@rJupiter}%
+\gdef\SaturnSymbol{\horost@rSaturn}%
+\gdef\UranusSymbol{\horost@rUranus}%
+\gdef\NeptuneSymbol{\horost@rNeptune}%
+\gdef\PlutoSymbol{\horost@rPluto}%
+% \end{macrocode}
+%
+% Asteroids:
+% \begin{macrocode}
+\gdef\ChironSymbol{\Chiron}%
+\gdef\CeresSymbol{\Ceres}%
+\gdef\PallasSymbol{\Pallas}%
+\gdef\JunoSymbol{\Juno}%
+\gdef\VestaSymbol{\Vesta}%
+% \end{macrocode}
+%
+% Derived points:
+% \begin{macrocode}
+\gdef\NorthNodeSymbol{\NorthNode}%
+\gdef\SouthNodeSymbol{\SouthNode}%
+\gdef\MeanNodeSymbol{\NorthNode$_M$}%
+\gdef\TrueNodeSymbol{\NorthNode$_T$}%
+\gdef\LilithSymbol{\Lilith}%
+% \end{macrocode}
+%
+% Cusps and angles:
+% \begin{macrocode}
+\gdef\CuspISymbol{\ASC}%
+\gdef\CuspIVSymbol{\IC}%
+\gdef\CuspVIISymbol{\DSC}%
+\gdef\CuspXSymbol{\MC}%
+\gdef\AscendantSymbol{\ASC}%
+\gdef\MCSymbol{\MC}%
+\gdef\VertexSymbol{\Vertex}%
+% \end{macrocode}
+%
+% Direction:
+% \begin{macrocode}
+\gdef\horoRetrogradeSymbol{\Retrograde}%
+% \end{macrocode}
+%
+% Aspects:
+% \begin{macrocode}
+\gdef\horoConjunctionSymbol{\Conjunction}%
+\gdef\horoOppositionSymbol{\Opposition}%
+\gdef\horoTrineSymbol{\Trine}%
+\gdef\horoSquareSymbol{\horost@rSquare}%
+\gdef\horoQuintileSymbol{$\mathsf{Q}$}%
+\gdef\horoBiquintileSymbol{$\mathsf{Q}^2$}%
+\gdef\horoSextileSymbol{\Sextile}%
+\gdef\horoQuincunxSymbol{\Quincunx}%
+\gdef\horoSemisextileSymbol{\Semisextile}%
+\gdef\horoSemisquareSymbol{\Semisquare}%
+\gdef\horoSesquiquadrateSymbol{\Sesquiquadrate}%
+}
+% \end{macrocode}
+%
+% Invoke |\horostarfont| to set it as default:
+% \begin{macrocode}
+\horostarfont
+\fi
+% \end{macrocode}
+% \end{macro}
+%
+% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% \subsection{Utilities}
+%
+% \subsubsection{Trimming spaces}
+% This code is from Michael Downes's series of mailing list postings
+% available at
+% \href{http://ctan.math.utah.edu/ctan/tex-archive/info/aro-bend/answer.015}{\nolinkurl{http://ctan.math.utah.edu/ctan/tex-archive/}}
+% \href{http://ctan.math.utah.edu/ctan/tex-archive/info/aro-bend/answer.015}{\nolinkurl{info/aro-bend/answer.015}}.
+% The trick of changing the letter Q's catcode to make an exotic
+% $\mathcal{Q}$ that can't occur in ordinary token lists, is used elsewhere
+% in the \textsf{horoscop} code so we leave it in force after defining
+% |\trimspaces|.
+% \begin{macrocode}
+%% WATCH OUT! MAKING Q EXOTIC HERE!
+\catcode`\Q=3
+\def\horo@cue{Q}
+% \end{macrocode}
+%
+% \begin{macro}{\trimspaces}
+% \begin{macrocode}
+\def\trimspaces#1{%
+ \begingroup
+ \aftergroup\toks\aftergroup0\aftergroup{%
+ \expandafter\@trimb\expandafter\noexpand#1Q Q}%
+ \edef#1{\the\toks0}%
+}
+\long\def\@trimb#1 Q{\@trimc#1Q}
+\long\def\@trimc#1Q#2{\afterassignment\endgroup \vfuzz\the\vfuzz#1}
+% \end{macrocode}
+% \end{macro}
+%
+% \subsubsection{Redefine after current group}
+%
+% Sometimes we want to pass data currently in a |\def|ined macro to the world
+% outside the current group, but we don't want to pollute the global namespace
+% with a |\gdef|. This code provides a way to do that. It's a bit nasty and
+% should only be used with macros whose contents translate to nice
+% well-behaved strings. In practice, we use it for macros whose contents are
+% decimal numbers.
+%
+% \begin{macro}{\horo@fterdef}
+% First, |\horo@fterdef| puts three tokens into the |\aftergroup| queue to be
+% evaluated outside the current group. They are: |\horo@ft@a|, the name of
+% the macro being passed out, and a newly-constructed token whose name is
+% |\horo@@| followed by the \emph{contents} of the macro being passed out.
+% \begin{macrocode}
+\def\horo@fterdef#1{%
+ \aftergroup\horo@ft@a
+ \aftergroup#1\expandafter\aftergroup\csname horo@@#1\endcsname
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\horo@eathead}
+% This will be used in a moment; it simply drops the next seven characters.
+% \begin{macrocode}
+\def\horo@eathead#1#2#3#4#5#6#7{}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\horo@ft@a}
+% Now, watch carefully. When we left |\horo@fterdef|, there were three
+% tokens queued to run after the group. Now the group has ended and
+% it's time to look at those tokens. The first one is |\horo@ft@a|, so this
+% macro runs and the next two become its arguments. The first of those is
+% the name of the macro we will redefine, and the second is macro whose name
+% consists of |\horo@@| and then the contents of the original macro.
+%
+% So the |\edef| expands its argument, which starts by deferring expansion
+% of |\horo@eathead|, and then finding the string value of the
+% |\horo@@|\ldots\ token. That string value consists of seven characters
+% spelling out ``|\|-|h|-|o|-|r|-|o|-|@|-|@|'' followed by the data to pass.
+% When the deferred |\horo@eathead| runs it eats those seven characters.
+% What's left in the |\edef| body is just the data, which gets assigned to
+% the macro.
+% \begin{macrocode}
+\def\horo@ft@a#1#2{%
+ \edef#1{\expandafter\horo@eathead\string#2}%
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \subsubsection{Polar to Cartesian}
+%
+% \begin{macro}{\horo@polarconvert}
+% Positioning the items on a wheel chart generally makes more sense in polar
+% than Cartesian coordinates, so this computes the Cartesian coordinates for
+% given polar coordinates. Takes four arguments; \#1 and \#2 are numbers
+% containing the polar coordinates $r$ and $\theta$ (in degrees), and \#3
+% and \#4 are dimension registers that will contain the result encoded into
+% points. The coordinate $\theta$ is zero on the $+X$ axis and increases
+% counterclockwise under the standard mathematical convention.
+%
+% This macro calls |\TG@@sin| from the \textsf{trig} package, which may be
+% a slightly dangerous thing to do. It trashes |\dimen@|.
+% \begin{macrocode}
+\def\horo@polarconvert#1#2#3#4{%
+ \dimen@=\nin@ty\p@\advance\dimen@-#2\p@\TG@@sin
+ #3=#1\dimen@
+ \dimen@=#2\p@\TG@@sin
+ #4=#1\dimen@
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \subsubsection{For-each}
+% These macros allow applying another macro on each item in a
+% comma-separated list. They use exotic $\mathcal{Q}$ for parsing the list
+% because it's convenient, but that's probably not necessary.
+%
+% \begin{macro}{\horo@fe}
+% Internal for |\horoforeach|. It checks whether the next comma-separated
+% item is $\mathcal{Q}$, and if not, it calls |\horo@fe@b| on it and then
+% invokes itself tail-recursively to do the next one.
+% \begin{macrocode}
+\def\horo@fe#1,{%
+ \def\horo@fe@c{#1}%
+ \ifx\horo@fe@c\horo@cue\relax
+ \else
+ \horo@fe@b{#1}%
+ \expandafter\horo@fe
+ \fi
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\horoforeach}
+% No @ in the name because a user could possibly want to use it and it's
+% reasonably safe. First argument is the list of items, comma-separated.
+% Second is the action to perform on them, which will be invoked with each
+% successive items from the list as its first and only argument. The list
+% of items gets expanded. The logic is simple: it just saves the arguments
+% and calls |\horo@fe| with a list containing an extra $\mathcal{Q}$ item at
+% the end to terminate the recursion.
+% \begin{macrocode}
+\def\horoforeach#1#2{%
+ \edef\horo@fe@a{#1}%
+ \def\horo@fe@b{#2}%
+ \expandafter\horo@fe\horo@fe@a,Q,%
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \subsubsection{Double for-each}
+% This is two nested for-eaches in one; that's a common enough operation
+% that it seems useful to have a special feature for it instead of trying to
+% nest regular for-eaches. We think of the outer index as $x$ and the inner
+% index as $y$, so the list of items for the outer loop is the $x$-list and
+% the list of items for the inner loop is the $y$-list.
+%
+% \begin{macro}{\horo@dfe@b}
+% Inner loop. Logic is very similar to |\horo@fe|: it gets a new item from
+% the $y$-list, checks whether it is the $\mathcal{Q}$ terminator, and if
+% not, applies |\horo@dfe@action| to the pair of |\horo@dfe@x| and
+% |\horo@dfe@y| before tail-recursing.
+% \begin{macrocode}
+\def\horo@dfe@b#1,{%
+ \def\horo@dfe@y{#1}%
+ \ifx\horo@dfe@y\horo@cue\relax
+ \else
+ \horo@dfe@ction{\horo@dfe@x}{\horo@dfe@y}%
+ \expandafter\horo@dfe@b
+ \fi
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\horo@dfe@a}
+% Outer loop. The same kind of tail-recursive iteration through the
+% $x$-list, applying |\horo@dfe@b| to each item.
+% \begin{macrocode}
+\def\horo@dfe@a#1,{%
+ \def\horo@dfe@x{#1}%
+ \ifx\horo@dfe@x\horo@cue\relax
+ \else
+ \expandafter\horo@dfe@b\horo@dfe@ylist,Q,\relax
+ \expandafter\horo@dfe@a
+ \fi
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\horo@dblforeach}
+% Master entry point for double for-each. This does get an @ because it's
+% sufficiently dangerous. Arguments are the $x$-list, the $y$-list, and the
+% action. The code just saves those and invokes |\horo@dfe@a| with the
+% appropriate terminating $\mathcal{Q}$.
+% \begin{macrocode}
+\def\horo@dblforeach#1#2#3{%
+ \edef\horo@dfe@xlist{#1}\edef\horo@dfe@ylist{#2}\def\horo@dfe@ction{#3}%
+ \expandafter\horo@dfe@a\horo@dfe@xlist,Q,\relax
+}
+% \end{macrocode}
+% \end{macro}
+%
+% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% \subsection{Basic Astrological Calculation Routines}
+%
+% These handle stuff like angle arithmetic. They're included even in the
+% |nocalc| state because some of them are needed by the chart graphics
+% routines, or are things you might still want to do even with
+% manually-entered coordinates.
+%
+% The |\ifhorocalculated| flag keeps track of whether we expect there to be
+% valid data in the object-position variables; that's useful to prevent
+% wasted calculation when we're using the emphemeris interface but it isn't
+% working (for instance, because of |\write18| being turned off), because in
+% such a case the positions are unknown.
+%
+% \begin{macrocode}
+\newif\ifhorocalculated\horocalculatedfalse
+% \end{macrocode}
+%
+% \subsubsection{Cusp information}
+% These theoretically might be user-settable, but would seldom be changed in
+% practice.
+%
+% \begin{macro}{\hororightcoord}
+% The object, or more correctly, the astrological longitude, to put at the
+% right of the chart corresponding to polar coodinate $\theta=0$. This
+% normally would be the Descendant, which in turn would normally be the
+% seventh house cusp.
+% \begin{macrocode}
+\def\hororightcoord{\ifhorocalculated\horoCuspVIIPos\else180\fi}%
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\horocusps}
+% A list of all the house cusps.
+% \begin{macrocode}
+\def\horocusps{CuspI,CuspII,CuspIII,CuspIV,CuspV,CuspVI,%
+ CuspVII,CuspVIII,CuspIX,CuspX,CuspXI,CuspXII}%
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\horoangularcusps}
+% A list of which cusps correspond to angles, used for showing the
+% angles more prominently in some ready-made wheels.
+% \begin{macrocode}
+\def\horoangularcusps{CuspI,CuspIV,CuspVII,CuspX}
+% \end{macrocode}
+% \end{macro}
+%
+% \subsubsection{Calculating harmonics}
+% \begin{macro}{\horocalcharmonic}
+% Multiplies all the object positions from |\horoobjects| by its parameter.
+% Straightforward implementation: it just calls |\horo@calch| on each object.
+% House cusps and objects not mentioned in |\horoobjects| will be unchanged.
+% Pos is the variable that gets multiplied; DPos gets set to the new value
+% of Pos.
+% \begin{macrocode}
+\def\horocalcharmonic#1{%
+ \horoforeach{\horoobjects}{\horo@calch{#1}}%
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\horo@calch}
+% Internal for |\horocalcharmonic|. Gets the object's Pos into |\dimen@|,
+% multiplies it by the harmonic number, takes it modulo 360 degrees, and
+% saves it back to Pos and DPos.
+% \begin{macrocode}
+\def\horo@calch#1#2{%
+ \dimen@=\csname horo#2Pos\endcsname\p@\relax
+ \multiply\dimen@ by #1\relax
+ \horo@fixdimen@
+ \expandafter\edef\csname horo#2Pos\endcsname{\TG@rem@pt\dimen@}%
+ \expandafter\edef\csname horo#2DPos\endcsname{\TG@rem@pt\dimen@}%
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \subsubsection{Shifting positions}
+% \begin{macro}{\horoshiftobjects}
+% \changes{v0.91}{2008/07/15}{New macro}
+% Adds an offset to all the object positions in |\horoobjects|, much like
+% |\horocalcharmonic| above.
+% \begin{macrocode}
+\def\horoshiftobjects#1{%
+ \horoforeach{\horoobjects}{\horo@shift{#1}}%
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\horoshiftcusps}
+% \changes{v0.91}{2008/07/15}{New macro}
+% Adds an offset to all the object positions in |\horocusps|, much like
+% |\horocalcharmonic| above.
+% \begin{macrocode}
+\def\horoshiftcusps#1{%
+ \horoforeach{\horocusps}{\horo@shift{#1}}%
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\horo@shift}
+% Internal for |\horoshiftobjects| and -|cusps|. Much like |\horo@calch|
+% except it adds instead of multiplying.
+% \begin{macrocode}
+\def\horo@shift#1#2{%
+ \dimen@=\csname horo#2Pos\endcsname\p@\relax
+ \advance\dimen@ by #1\p@\relax
+ \horo@fixdimen@
+ \expandafter\edef\csname horo#2Pos\endcsname{\TG@rem@pt\dimen@}%
+ \expandafter\edef\csname horo#2DPos\endcsname{\TG@rem@pt\dimen@}%
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \subsubsection{Calculating equal cusps}
+%
+% \begin{macro}{\horomakeequalcusps}
+% \changes{v0.91}{2008/07/15}{New macro}
+% Creates a set of equal-house cusps starting from CuspI set to the
+% argument. Implementation simply sets them to hardcoded values and then
+% shifts.
+% \begin{macrocode}
+\def\horomakeequalcusps#1{
+ \def\horoCuspIPos{0}%
+ \def\horoCuspIIPos{30}%
+ \def\horoCuspIIIPos{60}%
+ \def\horoCuspIVPos{90}%
+ \def\horoCuspVPos{120}%
+ \def\horoCuspVIPos{150}%
+ \def\horoCuspVIIPos{180}%
+ \def\horoCuspVIIIPos{210}%
+ \def\horoCuspIXPos{240}%
+ \def\horoCuspXPos{270}%
+ \def\horoCuspXIPos{300}%
+ \def\horoCuspXIIPos{330}%
+ \horoshiftcusps{#1}%
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\horomakesigncusps}
+% \changes{v0.91}{2008/07/15}{New macro}
+% Truncates the argument to the sign boundary and then uses it for
+% |\horomakeequalcusps|. The magic number 1966080 is 30\horodegrees\
+% measured in units of $1\horodegrees/65536$.
+% \begin{macrocode}
+\def\horomakesigncusps#1{
+ \dimen@=#1\p@\relax
+ \edef\horo@savecount@{\the\count0}%
+ \count0=\dimen@\relax
+ \divide\count0 by 1966080\relax
+ \multiply\count0 by 30\relax
+ \expandafter\horomakeequalcusps{\the\count0}%
+ \count0=\horo@savecount@\relax
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \subsubsection{Calculating midpoints}
+% At present this only includes a private macro used to compute the midpoint
+% of two raw angles. A future feature might actually compute midpoint
+% charts by the time-space and/or object-position methods.
+%
+% \begin{macro}{\horo@midpoint}
+% Find the midpoint between two angles, going around the circle in the
+% shorter direction. Input angles are the two arguments, output goes into
+% |\dimen@|.
+% \begin{macrocode}
+\def\horo@midpoint#1#2{%
+ \dimen@#1\p@\relax
+ \advance\dimen@ by-#2\p@\relax
+ \horo@fixdimen@diff
+ \divide\dimen@ by2\relax
+ \advance\dimen@ by#2\p@\relax
+ \horo@fixdimen@
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \subsubsection{Angle adjustments}
+% These all have to do with fixing the angle currently in |\dimen@|, which
+% is assumed to be encoded at one point per degree, one way
+% or another to make it well-behaved.
+%
+% \begin{macro}{\horo@chartrotate}
+% Subtract |\hororightcoord| to account for rotation of the entire chart.
+% \begin{macrocode}
+\def\horo@chartrotate{%
+ \advance\dimen@-\hororightcoord\p@
+ \horo@fixdimen@
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\horo@fixdimen@}
+% Takes |\dimen@| modulo 360\horodegrees\ so it ends up in the range
+% 0\ldots360\horodegrees. The magic number 23592960 is 65536 times 360.
+% \begin{macrocode}
+\def\horo@fixdimen@{%
+ \edef\horo@savecount@{\the\count0}%
+ \count0=\dimen@\relax
+ \ifnum\count0<0\relax
+ \divide\count0 by 23592960\relax
+ \advance\count0 by -1\relax
+ \else
+ \divide\count0 by 23592960\relax
+ \fi
+ \multiply\count0 by -360\relax
+ \advance\dimen@ by\count0\p@\relax
+ \count0=\horo@savecount@\relax
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\horo@fixdimen@diff}
+% Very similar to |\horo@fixdimen@| except that the output range is
+% $-180\ldots180\horodegrees$, which is useful when we want to find the
+% difference between two locations (tells us whether they are clockwise or
+% counterclockwise from each other).
+% \begin{macrocode}
+\def\horo@fixdimen@diff{%
+ \horo@fixdimen@
+ \ifdim\dimen@>180\p@\advance\dimen@ by -360\p@\fi
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \subsubsection{Chart rotation}
+% Rotates the chart so that object \#1 appears at angle \#2, which is
+% expressed as a $\theta$ coordinate so that 0 is to the right, 90 is up,
+% and so on. This works by changing the value of |\hororightcoord|,
+% which is checked during the actual plotting. Note it doesn't happen
+% globally, and you probably don't want it to; the global definition of
+% |\hororightcoord| is a smart one that picks up the Descendant's value.
+% \begin{macro}{\hororotatechart}
+% \begin{macrocode}
+\def\hororotatechart#1#2{%
+ \begingroup
+ \dimen@=#2\p@\relax
+ \advance\dimen@ by-\csname horo#1DPos\endcsname\p@\relax
+ \multiply\dimen@ by -1\relax
+ \edef\hororightcoord{\TG@rem@pt\dimen@}%
+ \horo@fterdef\hororightcoord
+ \endgroup
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \subsubsection{Variable copying and saving}
+% \begin{macro}{\horocopyvar}
+% Copies one variable to another on some objects, such as setting all DPos to
+% the value of the corresponding Pos. Arguments are the list of objects,
+% the from variable, and the to variable.
+% \begin{macrocode}
+\def\horocopyvar#1#2#3{%
+ \horoforeach{#1}{\horo@cv@{#2}{#3}}%
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\horo@cv}
+% Internal for |\horocopyvar|. Does the actual copying on one object.
+% \begin{macrocode}
+\def\horo@cv@#1#2#3{%
+ \expandafter\edef\csname horo#3#2\endcsname{\csname horo#3#1\endcsname}%
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\horosaveobjects}
+% Save all the object positions (Pos) and velocities (Vel)
+% to a macro. When the macro is called it
+% will set all the Pos and Vel values to the values from when it was created,
+% and all the DPos values to match Pos. It also saves and restores the value
+% of |\horoobjects| itself. This works by building up the
+% appropriate |\def| in the |\aftergroup| queue, and using |\horo@fterdef|
+% to put the definitions of the individual variables right inside the body
+% of the |\def|. So it's |\def|s within |\def|s going into the queue.
+% Several different approaches for this had to be tried before I found one
+% that didn't cause \TeX\ to complain about memory.
+% \begin{macrocode}
+\def\horosaveobjects#1{%
+ \begingroup
+ \aftergroup\def\aftergroup#1\aftergroup{%
+ \horo@fterdef\horoobjects
+ \horoforeach{\horoobjects}{\horo@svo@a}%
+ \aftergroup\horo@svo@b
+ \aftergroup}%
+ \endgroup
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\horo@svo@a}
+% First internal: this adds definitions for Pos and Vel to the |\aftergroup|
+% queue.
+% \begin{macrocode}
+\def\horo@svo@a#1{%
+ \expandafter\horo@fterdef\csname horo#1Pos\endcsname
+ \expandafter\horo@fterdef\csname horo#1Vel\endcsname
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\horo@svo@b}
+% Second internal: copies Pos to DPos on all objects. This gets invoked by
+% the restore-objects command we are creating, after it has restored Pos on
+% all objects.
+% \begin{macrocode}
+\def\horo@svo@b{%
+ \horocopyvar{\horoobjects}{Pos}{DPos}%
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\horosavecusps}
+% This is the same general deal as |\horosaveobjects|, but it saves
+% |\horocusps|, |\hororightcoord|, and the Pos of all cusps in |\horocusps|.
+% The DPos will be set to Pos on restore.
+% \begin{macrocode}
+\def\horosavecusps#1{%
+ \begingroup
+ \aftergroup\def\aftergroup#1\aftergroup{%
+ \edef\hororightcoord{\hororightcoord}%
+ \horo@fterdef\horocusps\horo@fterdef\hororightcoord
+ \horoforeach{\horocusps}{\horo@svc@a}%
+ \aftergroup\horo@svc@b
+ \aftergroup}%
+ \endgroup
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\horo@svc@a}
+% Save Pos of a cusp to the |\aftergroup| queue.
+% \begin{macrocode}
+\def\horo@svc@a#1{%
+ \expandafter\horo@fterdef\csname horo#1Pos\endcsname
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\horo@svc@b}
+% Copy Pos to DPos; the difference from |\horo@svo@b| is that here we do it
+% to all cusps instead of all objects.
+% \begin{macrocode}
+\def\horo@svc@b{%
+ \horocopyvar{\horocusps}{Pos}{DPos}%
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \subsubsection{Sexagesimal arithmetic}
+% These routines handle a number of conversions between DMS (degree, minute,
+% and second), DDMS (direction, degree, minute, and second),
+% SDMS (Zodiac sign, degree, minute, second), HMS (hour,
+% minute, second), and flat decimal (which is usually the number of hours or
+% degrees). They also handle typesetting things in these kinds of formats.
+%
+% We generally store flat decimal numbers in macro definitions. For
+% arithmetic they get assigned to
+% dimension registers encoded as 1 degree = 1 point. Then when
+% they get transformed into count registers they end up encoded as
+% 1 degree = 65536 counts. That gives 18.2044 counts per second of
+% arc, coincidentally very close to the original IBM PC's timer tick
+% rate of 18.2065 ticks per second of time, which was a
+% convenient fraction of the NTSC colour burst frequency. We have
+% just enough bits of precision to be reasonably sure of converting
+% DMS format to this format, doing a little bit of arithmetic, and
+% converting back while keeping the errors less than a second of arc. If
+% you want to calculate insane harmonics to subsecond precision (I have read
+% of people seriously attempting the 105th harmonic) then you're out
+% of luck, but you shouldn't be doing that anyway because your native
+% certainly didn't give you an accurate enough birth time for it to
+% be valid.
+%
+% The decimal number under consideration at the moment is often stored in
+% |\horo@data|, or in the form of a number of points in |\dimen@|, although
+% some of these macros take arguments instead. Output is returned in
+% several ways. Generally the calling
+% convention is determined by what's most convenient in the macros that
+% will call these ones.
+%
+% \begin{macro}{\horo@twodig}
+% Add a leading zero to a nonnegative integer to make it at least two digits;
+% useful for the part after the colon in times like ``12:03.''
+% \begin{macrocode}
+\def\horo@twodig#1{\ifnum#1<10\relax\edef#1{0#1}\fi}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\horo@ddms}
+% Takes a direction (one letter from NSEW), degree, minute, and second and
+% translates it to decimal. South and West are considered to be negative.
+% Note the input format: direction is one argument, but degree, minute, and
+% second are separated by colons, and an exotic $\mathcal{Q}$ terminates.
+% The output goes to redefine the last argument.
+% \begin{macrocode}
+\def\horo@ddms#1#2:#3:#4Q#5{%
+ \def\horo@data{}%
+ \uppercase{\if#1S\def\horo@data{-}\fi\if#1W\def\horo@data{-}\fi}%
+ \dimen@=#4\p@
+ \divide\dimen@ by 60\relax
+ \advance\dimen@ by #3\p@
+ \divide\dimen@ by 60\relax
+ \advance\dimen@ by #2\p@
+ \edef#5{\horo@data\TG@rem@pt\dimen@}%
+ \trimspaces{#5}%
+}
+% \end{macrocode}
+% \end{macro}
+%
+% Now, some configuration for the smart-rounding macros. This is a bit
+% complicated because of the diversity of rounding modes the user might
+% want. The general idea is that we convert decimal to sexagesimal in
+% several stages corresponding to the mixed-based digits of the result, most
+% significant down to least significant (i.e.\ sign, degrees, minutes,
+% seconds). At each stage we are rounding down, taking the floor function.
+% However, at some stage we may add an offset to make the floor function round
+% to nearest. For a pure round to nearest, that offset corresponds to half
+% the size we're rounding to, and we add right at the start. But if we're
+% trying to respect higher-digit boundaries, we'll add the offset later,
+% because the higher digits should always have the values they would have
+% with truncation. In that case, it becomes possible for the rounded-to digit
+% to have an out-of-range value; so there's a flag for whether to expose
+% that or round it down. Finally, because configuring all that is such a
+% mess, we have some convenience macros that preset commonly-used modes, and
+% a super-convenience mode that attempts to auto-select a reasonable
+% rounding mode depending on context.
+%
+% \begin{macro}{\horo@r@offset}
+% Amount to add to |\dimen@| when we're ready to add the offset. Default is
+% for ``transparent truncate'' mode.
+% \begin{macrocode}
+\def\horo@r@offset{1sp}%
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\horo@r@offdig}
+% Digit before which to apply the offset. May be Z for Zodiac sign, D for
+% degrees, M for minutes, S for seconds, anything else will not add the
+% offset at all. Default is add at the start.
+% \begin{macrocode}
+\def\horo@r@offdig{Z}%
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\ifhororoundclamp}
+% Boolean flag: should we clamp rounded digits to their expected range?
+% Default no.
+% \begin{macrocode}
+\newif\ifhororoundclamp\hororoundclampfalse
+% \end{macrocode}
+% \end{macro}
+%
+% Preset rounding modes covering all the reasonable ones. First we offer
+% basic truncation, both the transparent version (which is default) and the
+% strict version.
+% \begin{macrocode}
+\def\hororoundstricttruncate{\def\horo@r@offdigit{X}}
+\def\hororoundtruncate{\def\horo@r@offset{1sp}\def\horo@r@offdigit{Z}}
+% \end{macrocode}
+%
+% Now, pure round to nearest whatever.
+% \begin{macrocode}
+\def\hororoundtosec{\def\horo@r@offset{9sp}\def\horo@r@offdigit{Z}}
+\def\hororoundtomin{\def\horo@r@offset{546sp}\def\horo@r@offdigit{Z}}
+\def\hororoundtodeg{\def\horo@r@offset{0.5pt}\def\horo@r@offdigit{Z}}
+% \end{macrocode}
+%
+% Round to a lower digit but keep the boundaries of a higher digit. This
+% may result in out-of-range lower digits if |\hororoundclampfalse| is in
+% force.
+% \begin{macrocode}
+\def\hororoundtoseckeepsign{\def\horo@r@offset{9sp}\def\horo@r@offdigit{D}}
+\def\hororoundtoseckeepdeg{\def\horo@r@offset{546sp}\def\horo@r@offdigit{M}}
+\def\hororoundtoseckeepmin{\def\horo@r@offset{0.5pt}\def\horo@r@offdigit{S}}
+\def\hororoundtominkeepsign{\def\horo@r@offset{546sp}\def\horo@r@offdigit{D}}
+\def\hororoundtominkeepdeg{\def\horo@r@offset{0.5pt}\def\horo@r@offdigit{M}}
+\def\hororoundtodegkeepsign{\def\horo@r@offset{0.5pt}\def\horo@r@offdigit{D}}
+% \end{macrocode}
+%
+% \begin{macro}{\ifhororoundauto}
+% Boolean flag: should the system automatically choose a reasonable rounding
+% mode when it's about to do rounding?
+% \begin{macrocode}
+\newif\ifhororoundauto\hororoundautotrue
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\horo@d@dms@@}
+% This is an internal macro used in truncation and rounding. The first
+% argument is a macro name representing the digit to extract; the second is
+% the greatest value to allow for that digit if |\hororoundclamptrue| is
+% active. The current value of |\dimen@| gets truncated to an integer
+% number of points, and clamped if appropriate. That integer gets stored as
+% the |\horo@fterdef| definition of the macro whose name was passed in, and
+% then it gets subtracted out of |\dimen@| and the remaining fractional
+% part is multiplied by 60. The idea here is that we're extracting the
+% sexagesimal digits of the number, going from decimal degrees (or hours) to
+% integer degrees and decimal minutes; from decimal minutes to integer
+% minutes and decimal seconds; or from decimal seconds to integer seconds
+% and decimal treyf, which will be discarded.
+% \begin{macrocode}
+\def\horo@d@dms@@#1#2{%
+ \count0=\dimen@\relax
+ \divide\count0by65536\relax
+ \ifhororoundclamp\ifnum\count0>#2 \count0=#2\relax\fi\fi
+ \edef#1{\the\count0}%
+ \horo@fterdef#1%
+ \advance\dimen@-\count0\p@
+ \multiply\dimen@ 60\relax
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\horo@d@dms@}
+% Do a decimal to sexagesimal conversion using simple truncation.
+% This is used internally for angles passed to external software. The magic
+% number 100000 is guaranteed to exceed any digit value, so digits will
+% never be clamped. The digits go into the |\horo@fterdef| queue, so this
+% must be called in a group and the results appear after the group.
+% \begin{macrocode}
+\def\horo@d@dms@{%
+ \advance\dimen@1sp\relax
+ \horo@d@dms@@\horo@d@deg{100000}%
+ \horo@d@dms@@\horo@d@min{100000}%
+ \horo@d@dms@@\horo@d@sec{100000}%
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\horo@d@sdms}
+% Decimal to SDMS. The number of degrees past 0\horodegrees\AriesSymbol,
+% stored
+% at one point per degree in |\dimen@|, is converted to macros of decimal
+% integers representing Zodiac sign (1=Aries\ldots12=Pisces), degrees,
+% minutes, and seconds of arc in |\horo@d@sign|,
+% |\horo@d@deg|, |\horo@d@min|, and |\horo@d@sec| respectively. It obeys
+% all the complicated rounding instructions set by the above macros.
+%
+% First, we open a prophylactic group, and add the offset if we're adding it
+% before the sign.
+% \begin{macrocode}
+\def\horo@d@sdms{%
+ \begingroup
+ \def\horo@tmp{Z}\ifx\horo@r@offdigit\horo@tmp
+ \advance\dimen@\horo@r@offset\relax
+ \fi
+% \end{macrocode}
+%
+% Find the sign by converting |\dimen@| to a count register, and dividing by
+% 1966080, which is 30\horodegrees\ measured in counts at 65536 counts per
+% degree. We add one to the result, in a separate register, because signs
+% are one-based, and save the result in |\horo@d@sign| with |\horo@fterdef|
+% to preserve it outside the group.
+% \begin{macrocode}
+ \count0=\dimen@\relax
+ \divide\count0by1966080\relax
+ \count1=\count0\relax
+ \advance\count1by1\relax
+ \edef\horo@d@sign{\the\count1}%
+ \horo@fterdef\horo@d@sign
+% \end{macrocode}
+%
+% Subtract out the angle corresponding to the start of the sign, to leave
+% just the degree part in |\dimen@|.
+% \begin{macrocode}
+ \multiply\count0by30\relax%
+ \advance\dimen@-\count0\p@
+% \end{macrocode}
+%
+% Degrees digit: add the offset if this is where we're adding it, then
+% extract the degrees into |\horo@d@deg|.
+% \begin{macrocode}
+ \def\horo@tmp{D}\ifx\horo@r@offdigit\horo@tmp
+ \advance\dimen@\horo@r@offset\relax
+ \fi
+ \horo@d@dms@@\horo@d@deg{29}%
+% \end{macrocode}
+%
+% Minutes digit: add the offset if this is where we're adding it, then
+% extract the minutes into |\horo@d@min|.
+% \begin{macrocode}
+ \def\horo@tmp{M}\ifx\horo@r@offdigit\horo@tmp
+ \advance\dimen@\horo@r@offset\relax
+ \fi
+ \horo@d@dms@@\horo@d@min{59}%
+% \end{macrocode}
+%
+% Seconds digit: add the offset if this is where we're adding it, then
+% extract the seconds into |\horo@d@sec|.
+% \begin{macrocode}
+ \def\horo@tmp{S}\ifx\horo@r@offdigit\horo@tmp
+ \advance\dimen@\horo@r@offset\relax
+ \fi
+ \horo@d@dms@@\horo@d@sec{59}%
+ \endgroup
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\horo@d@dms}
+% Decimal to DMS. This is the same idea as |\horo@d@sdms| without the
+% handling of signs.
+% \begin{macrocode}
+\def\horo@d@dms{%
+ \begingroup
+ \def\horo@tmp{Z}\ifx\horo@r@offdigit\horo@tmp
+ \advance\dimen@ \horo@r@offset\relax
+ \fi
+ \def\horo@tmp{D}\ifx\horo@r@offdigit\horo@tmp
+ \advance\dimen@ \horo@r@offset\relax
+ \fi
+ \horo@d@dms@@\horo@d@deg{100000}%
+ \def\horo@tmp{M}\ifx\horo@r@offdigit\horo@tmp
+ \advance\dimen@ \horo@r@offset\relax
+ \fi
+ \horo@d@dms@@\horo@d@min{59}%
+ \def\horo@tmp{S}\ifx\horo@r@offdigit\horo@tmp
+ \advance\dimen@ \horo@r@offset\relax
+ \fi
+ \horo@d@dms@@\horo@d@sec{59}%
+ \endgroup
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\horodsmstext}
+% Typeset DSMS text. This might be invoked by the user to print a text
+% version of calculated positions. It calls |\horo@d@dms| and then typesets
+% the results with the defined symbols. When |\hororoundautotrue| is
+% active, this will automatically choose |\hororoundtoseckeepmin| rounding.
+% \begin{macrocode}
+\def\horodsmstext#1{%
+ \begingroup
+ \ifhororoundauto\hororoundtoseckeepmin\fi
+ \dimen@=#1\p@
+ \horo@d@sdms
+ \horo@d@deg\horodegrees\Zodiac{\horo@d@sign}%
+ \horo@d@min\horominutes\horo@d@sec\horoseconds
+ \endgroup
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\horotimetext}
+% Typeset DMS text as if it were a time, treating ``degrees'' as hours.
+% The minutes and seconds are forced to two digits so that times like
+% 12:03:04 will come out as such instead of as 12:3:4. No provision for
+% AM/PM; if you want that, you're on your own. When |\hororoundautotrue| is
+% active, this will automatically choose |\hororoundtruncate| rounding, on
+% the theory that the time was probably entered by the user earlier with
+% integer seconds and should be preserved.
+% \begin{macrocode}
+\def\horotimetext#1{%
+ \begingroup
+ \ifhororoundauto\hororoundtruncate\fi
+ \dimen@=#1\p@
+ \horo@d@sdms
+ \horo@twodig\horo@d@min\horo@twodig\horo@d@sec
+ \horo@d@deg:\horo@d@min:\horo@d@sec
+ \endgroup
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\horo@nsew}
+% This is an internal function for the next one: it strips the
+% positive/negative (not Zodiac) sign from |\dimen@|, making it positive,
+% but uses the sign to select one of the two arguments which will become the
+% definition of |\horo@calc@b|. The intended use is for typesetting things
+% like longitude that could be East or West.
+% \begin{macrocode}
+\def\horo@nsew#1#2{%
+ \ifdim\dimen@<\z@\relax
+ \def\horo@calc@b{#2}\multiply\dimen@ by-1\relax
+ \else
+ \def\horo@calc@b{#1}%
+ \fi
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\horolatlontext}
+% User-callable wrapper for |horo@nsew|. Typesets the first argument as a
+% number of degrees, minutes, and seconds, with the second and third
+% arguments added at the end for positive or negative respectively.
+% Intended for typesetting latitude or longitude. The default rounding is
+% |\hororoundtruncate|, to preserve user input.
+% \begin{macrocode}
+\def\horolatlontext#1#2#3{%
+ \begingroup
+ \ifhororoundauto\hororoundtruncate\fi
+ \dimen@=#1\p@\horo@nsew{#2}{#3}%
+ \horo@d@dms
+ \horo@d@deg\horodegrees%
+ \horo@d@min\horominutes\horo@d@sec\horoseconds~\horo@calc@b
+ \endgroup
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\hororxtext}
+% Typeset a ``retrograde'' symbol if the specified object is retrograde,
+% determined by whether its Vel is negative.
+% \begin{macrocode}
+\def\hororxtext#1{%
+ \begingroup
+ \dimen@\csname horo#1Vel\endcsname\p@
+ \ifdim\dimen@<\z@\relax
+ \horoRetrogradeSymbol
+ \fi
+ \endgroup
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \subsubsection{Setting all data at once}
+% \begin{macro}{\horocalcparms}
+% This sets the year, month, day, time of day, latitude, and longitude all
+% at once for user convenience, making use of the sexagesimal conversions.
+% \begin{macrocode}
+\def\horocalcparms#1#2#3#4#5#6{%
+ \edef\horocalcyear{#1}\edef\horocalcmonth{#2}\edef\horocalcday{#3}%
+ \horo@ddms N#4Q\horocalctime
+ \horo@ddms#5Q\horocalclon
+ \horo@ddms#6Q\horocalclat
+}
+% \end{macrocode}
+% \end{macro}
+%
+% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% \subsection{Astrolog Calculation Back End}
+%
+% These macros handle the interface to Astrolog, if it was selected. We
+% start by checking whether it \emph{was} selected:
+% \begin{macrocode}
+\ifhoro@strolog
+% \end{macrocode}
+%
+% \subsubsection{Name translation}
+% We define a bunch of macros that represent the short
+% strings used on the Astrolog command line to identify different objects
+% and cusps. We also define names in the reverse direction for translating
+% the abbreviations from Astrolog's format back to \textsf{horoscop}'s.
+% Some of those contain illegal characters for \TeX\ command names, so we
+% have to use |\expandafter\def\csname|.
+% \begin{macrocode}
+ \def\horoSun@strologname{Sun }\def\horo@stSunObj{Sun}
+ \def\horoMoon@strologname{Moo }\def\horo@stMooObj{Moon}
+ \def\horoMercury@strologname{Mer }\def\horo@stMerObj{Mercury}
+ \def\horoVenus@strologname{Ven }\def\horo@stVenObj{Venus}
+ \def\horoMars@strologname{Mar }\def\horo@stMarObj{Mars}
+ \def\horoJupiter@strologname{Jup }\def\horo@stJupObj{Jupiter}
+ \def\horoSaturn@strologname{Sat }\def\horo@stSatObj{Saturn}
+ \def\horoUranus@strologname{Ura }\def\horo@stUraObj{Uranus}
+ \def\horoNeptune@strologname{Nep }\def\horo@stNepObj{Neptune}
+ \def\horoPluto@strologname{Plu }\def\horo@stPluObj{Pluto}
+ \def\horoChiron@strologname{Chi }\def\horo@stChiObj{Chiron}
+ \def\horoCeres@strologname{Cer }\def\horo@stCerObj{Ceres}
+ \def\horoPallas@strologname{Pal }\def\horo@stPalObj{Pallas}
+ \def\horoJuno@strologname{Jun }\def\horo@stJunObj{Juno}
+ \def\horoVesta@strologname{Ves }\def\horo@stVesObj{Vesta}
+ \def\horoNorthNode@strologname{Nod }\def\horo@stNodObj{NorthNode}
+ \def\horoSouthNode@strologname{S.N }
+ \expandafter\def\csname horo@stS.NObj\endcsname{SouthNode}
+ \def\horoLilith@strologname{Lil }\def\horo@stLilObj{Lilith}
+% \end{macrocode}
+%
+% Zodiac signs and cusps only need to go in the reverse direction.
+% The signs expand to the start of the sign in degrees.
+% \begin{macrocode}
+ \def\horo@stAscObj{CuspI}
+ \expandafter\def\csname horo@st2ndObj\endcsname{CuspII}
+ \expandafter\def\csname horo@st3rdObj\endcsname{CuspIII}
+ \def\horo@stNadObj{CuspIV}
+ \expandafter\def\csname horo@st5thObj\endcsname{CuspV}
+ \expandafter\def\csname horo@st6thObj\endcsname{CuspVI}
+ \def\horo@stDesObj{CuspVII}
+ \expandafter\def\csname horo@st8thObj\endcsname{CuspVIII}
+ \expandafter\def\csname horo@st9thObj\endcsname{CuspIX}
+ \def\horo@stMidObj{CuspX}
+ \expandafter\def\csname horo@st11tObj\endcsname{CuspXI}
+ \expandafter\def\csname horo@st12tObj\endcsname{CuspXII}
+ \def\horo@stAriSign{0}
+ \def\horo@stTauSign{30}
+ \def\horo@stGemSign{60}
+ \def\horo@stCanSign{90}
+ \def\horo@stLeoSign{120}
+ \def\horo@stVirSign{150}
+ \def\horo@stLibSign{180}
+ \def\horo@stScoSign{210}
+ \def\horo@stSagSign{240}
+ \def\horo@stCapSign{270}
+ \def\horo@stAquSign{300}
+ \def\horo@stPisSign{330}
+% \end{macrocode}
+%
+% \subsubsection{House systems}
+% And, similarly, a set of macros the user can use to choose a house system.
+% These work by redefining |\horo@housenumber| to the integer codes Astrolog
+% uses.
+%
+% \begin{macrocode}
+ \def\horoPlacidusHouses{\def\horo@housenumber{0}}
+ \def\horoKochHouses{\def\horo@housenumber{1}}
+ \def\horoEqualHouses{\def\horo@housenumber{2}}
+ \def\horoCampanusHouses{\def\horo@housenumber{3}}
+ \def\horoMeridianHouses{\def\horo@housenumber{4}}
+ \def\horoRegiomontanusHouses{\def\horo@housenumber{5}}
+ \def\horoPorphyryHouses{\def\horo@housenumber{6}}
+ \def\horoMorinusHouses{\def\horo@housenumber{7}}
+ \def\horoPolichPageHouses{\def\horo@housenumber{8}}
+ \def\horoAlcabitusHouses{\def\horo@housenumber{9}}
+ \def\horoEqualMCHouses{\def\horo@housenumber{10}}
+ \def\horoNeoPorphyryHouses{\def\horo@housenumber{11}}
+ \def\horoWholeHouses{\def\horo@housenumber{12}}
+ \def\horoVedicHouses{\def\horo@housenumber{13}}
+% \end{macrocode}
+%
+% \subsubsection{Interface stuff}
+% Define a read for Astrolog's output, and a name for the temporary file.
+% \begin{macrocode}
+ \newread\horo@tmpfile
+ \edef\horo@tmpfname{\jobname.hor}%
+% \end{macrocode}
+%
+% \begin{macro}{\horoastrologopt}
+% The |\horoastrologopt| macro is interpolated onto the Astrolog command
+% line, so the user can set it if they have extra options to pass.
+% \begin{macrocode}
+ \def\horoastrologopt{}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\horoobjects}
+% Default list of objects to calculate.
+% \begin{macrocode}
+ \def\horoobjects{Sun,Moon,Mercury,Venus,Mars,Jupiter,Saturn,%
+ Uranus,Neptune,Pluto,NorthNode,Lilith,%
+ Chiron,Ceres,Pallas,Juno,Vesta}
+% \end{macrocode}
+% \end{macro}
+%
+% Placidus houses are the default:
+% \begin{macrocode}
+ \horoPlacidusHouses
+% \end{macrocode}
+%
+% \subsubsection{The actual calculation}
+% \begin{macro}{\horocalculate}
+% Okay, here's where the excitement happens. This macro takes the current
+% chart data from the |\horocalcyear|, |\horocalcmonth|, |\horocalcday|,
+% |\horocalctime|, |\horocalclat|, and |\horocalclong| macros, along with
+% various ancillary configuration macros, and runs Astrolog.
+%
+% First we open the definition, and a group which will be used to prevent
+% macro and register pollution.
+% \begin{macrocode}
+ \def\horocalculate{%
+ \begingroup
+% \end{macrocode}
+%
+% We want to build up a list of all the objects we'll compute,
+% space separated, expressed in Astrolog's own abbreviations. That list
+% will go on the
+% Astrolog command line. Cusps always get computed. We build the list
+% by the same trick used earlier in
+% |\horosaveobjects|: building up a |\def| command in the |\aftergroup|
+% queue while we run a loop inside a group to decide what goes there. The
+% macro we are defining is |\horo@calc@a|. In the loop we execute
+% |\horo@calc@c| on each object or cusp. It adds a space and the
+% appropriate |\horo|\meta{object}|@strologname| macro to the |\aftergroup|
+% queue.
+% \begin{macrocode}
+ \begingroup
+ \aftergroup\def\aftergroup\horo@calc@a\aftergroup{%
+ \horoforeach{\horoobjects}{\horo@calc@c}%
+ \aftergroup}%
+ \endgroup
+% \end{macrocode}
+% So at this point |\horo@calc@a| contains the list of objects.
+%
+% Now we get the time of day, which is stored in decimal hours, into hours
+% and minutes format and put it in |\horo@calc@d|.
+% \begin{macrocode}
+ \dimen@\horocalctime\p@\horo@d@dms@\horo@twodig\horo@d@min
+ \edef\horo@calc@d{\horo@d@deg:\horo@d@min\space GMT\space}%
+% \end{macrocode}
+%
+% We process |\horocalclon| into degrees:minutes format with E or W for East
+% or West and put it in |\horo@calc@e|. The macro |\horo@calc@b| is used to
+% pass out the East/West letter.
+% \begin{macrocode}
+ \dimen@=\horocalclon\p@\horo@nsew EW%
+ \horo@d@dms@
+ \horo@twodig\horo@d@min
+ \edef\horo@calc@e{\horo@d@deg:\horo@d@min\horo@calc@b\space}%
+% \end{macrocode}
+%
+% Similarly, |\horocalclat| goes into degrees:minutes format with N or S for
+% North or South and put it in |\horo@calc@f|.
+% \begin{macrocode}
+ \dimen@=\horocalclat\p@\horo@nsew NS%
+ \horo@d@dms@
+ \horo@twodig\horo@d@min
+ \edef\horo@calc@f{\horo@d@deg:\horo@d@min\horo@calc@b\space}%
+% \end{macrocode}
+%
+% Now we run Astrolog with the set of options we've built.
+% \begin{macrocode}
+ \immediate\write18{%
+ astrolog\space
+ -o0 \horo@tmpfname\space
+ -c \horo@housenumber\space
+ -qa \horocalcmonth\space
+ \horocalcday\space
+ \horocalcyear\space
+ \horo@calc@d\horo@calc@e\horo@calc@f
+ -R0 \horo@calc@a
+ \horoastrologopt
+ }%
+% \end{macrocode}
+%
+% The output will have gone into the file named |\horo@tmpfname|. We open
+% it up and then call a parsing routine, which puts the results into
+% |\horo@fterdef|s. The |\ifhorocalculated| flag gets set to false; it will
+% be upgraded to true if we can successfully read anything out of the output
+% file.
+% \begin{macrocode}
+ \openin\horo@tmpfile=\horo@tmpfname\relax
+ \aftergroup\horocalculatedfalse
+ \horo@calc@parse
+ \closein\horo@tmpfile
+% \end{macrocode}
+%
+% Then the group ends, all the |\horo@fterdef|s happen, and that's the end
+% of |\horocalculate|.
+% \begin{macrocode}
+ \endgroup
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\horo@calc@c}
+% Internal macro for building up the object list. This takes its argument,
+% wraps it in |\horo| and |@strologname|, and adds the resulting token to
+% the |\aftergroup| queue.
+% \begin{macrocode}
+ \def\horo@calc@c#1{%
+ \expandafter\aftergroup\csname horo#1@strologname\endcsname
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\horo@calc@parse}
+% Parse the Astrolog output file. It has a few kinds of lines in it; the
+% ones we are interested in all start with |-YF|;\footnote{|-YF|ing
+% in designated areas only.} but every line contains at
+% least one space. So the first stage of parsing is to iterate over all the
+% lines by tail recursion and call |\horo@calc@parse@b|, which looks for
+% |-YF| lines.
+% \begin{macrocode}
+ \def\horo@calc@parse{%
+ \read\horo@tmpfile to \horo@calc@parse@a
+ \ifeof\horo@tmpfile\else
+ \expandafter\horo@calc@parse@b\horo@calc@parse@a\space x\space Q%
+ \horo@calc@parse
+ \fi
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\horo@YF}
+% Helper for |\horo@calc@parse@b|: simply expands to |-YF|.
+% \begin{macrocode}
+ \def\horo@YF{-YF}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\horo@calc@parse@b}
+% First stage of parsing a line of Astrolog output. Checks whether the
+% first space-separated word of the line is |-YF|, and if it is, calls
+% the second-stage parser |\horo@calc@parse@c| on the rest of the line.
+% \begin{macrocode}
+ \def\horo@calc@parse@b#1 #2Q{%
+ \def\horo@calc@parse@b@{#1}%
+ \ifx\horo@calc@parse@b@\horo@YF\horo@calc@parse@c#2Q\fi
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\horo@calc@parse@c}
+% Second stage of parsing a line of Astrolog output. We use \TeX\ delimited
+% argument parsing to find the fields on the line. They
+% are a bit complicated but correspond to object name; longitude in degree,
+% sign, decimal minutes; the latitude (which we ignore); the longitude speed
+% in degrees per day; and the distance. There's also some garbage at the
+% end as a result of the safety stuff added by |\horo@calc@parse|.
+% \begin{macrocode}
+ \def\horo@calc@parse@c#1: #2 #3 #4, #5 #6, #7 #8Q{%
+% \end{macrocode}
+%
+% First convert from degrees, sign, and decimal minutes, to decimal degrees:
+% \begin{macrocode}
+ \dimen@=#4\p@
+ \divide\dimen@ by 60\relax
+ \advance\dimen@ by #2\p@
+ \advance\dimen@ by \csname horo@st#3Sign\endcsname\p@
+% \end{macrocode}
+%
+% Save the result in Pos:
+% \begin{macrocode}
+ \expandafter\edef\csname
+ horo\csname horo@st#1Obj\endcsname Pos\endcsname{%
+ \TG@rem@pt\dimen@}%
+ \expandafter\horo@fterdef\csname
+ horo\csname horo@st#1Obj\endcsname Pos\endcsname
+% \end{macrocode}
+%
+% Save it in DPos as well:
+% \begin{macrocode}
+ \expandafter\edef\csname
+ horo\csname horo@st#1Obj\endcsname DPos\endcsname{%
+ \TG@rem@pt\dimen@}%
+ \expandafter\horo@fterdef\csname
+ horo\csname horo@st#1Obj\endcsname DPos\endcsname
+% \end{macrocode}
+%
+% Save the velocity, which is already nicely formatted in \#7, to Vel:
+% \begin{macrocode}
+ \expandafter\def\csname
+ horo\csname horo@st#1Obj\endcsname Vel\endcsname{#7}%
+ \expandafter\horo@fterdef\csname
+ horo\csname horo@st#1Obj\endcsname Vel\endcsname
+% \end{macrocode}
+%
+% Now we have at least a little bit of valid data, so things are probably
+% cool.
+% \begin{macrocode}
+ \aftergroup\horocalculatedtrue
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% End of the |\ifhoro@strolog| conditional:
+% \begin{macrocode}
+\fi
+% \end{macrocode}
+%
+% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% \subsection{Swiss Ephemeris Calculation Back End}
+%
+% The interface to Swiss Ephemeris goes via the |swetest|
+% command-line program. Unlike Astrolog, which gets invoked once to do all
+% objects, we run |swetest| once for each object and once more for
+% all cusps.
+%
+% Although |\ifhoro@ppendtmp| is only used in the case where |swetest| is
+% enabled, we have to define it outside the conditional because otherwise
+% \TeX\ will see the |\fi| that closes |\ifhoro@ppendtmp| as closing
+% something else, with resulting entertaining results.
+% \begin{macro}{\ifhoro@ppendtmp}
+% \begin{macrocode}
+\newif\ifhoro@ppendtmp\horo@ppendtmpfalse
+% \end{macrocode}
+% \end{macro}
+%
+% Then the rest of this section is conditional on the |swetest| option being
+% enabled.
+% \begin{macrocode}
+\ifhoro@swetest
+% \end{macrocode}
+%
+% \subsubsection{Command-line options}
+% One of these gets passed to \textsf{horoscop} according to the object
+% currently being calculated. Users who want to add other objects will need
+% to create the corresponding |\horo|\meta{object}|SEOpt| macros.
+% \begin{macrocode}
+ \def\horoSunSEOpt{-p0}
+ \def\horoMoonSEOpt{-p1}
+ \def\horoMercurySEOpt{-p2}
+ \def\horoVenusSEOpt{-p3}
+ \def\horoMarsSEOpt{-p4}
+ \def\horoJupiterSEOpt{-p5}
+ \def\horoSaturnSEOpt{-p6}
+ \def\horoUranusSEOpt{-p7}
+ \def\horoNeptuneSEOpt{-p8}
+ \def\horoPlutoSEOpt{-p9}
+ \def\horoChironSEOpt{-pD}
+ \def\horoPholusSEOpt{-pE}
+ \def\horoCeresSEOpt{-pF}
+ \def\horoPallasSEOpt{-pG}
+ \def\horoJunoSEOpt{-pH}
+ \def\horoVestaSEOpt{-pI}
+ \def\horoMeanNodeSEOpt{-pm}
+ \def\horoTrueNodeSEOpt{-pt}
+ \def\horoLilithSEOpt{-pA}
+% \end{macrocode}
+%
+% \changes{v0.91}{2008/07/15}{Fake SEOpt macros for always-calculated angles}
+% These next few are fake options; the Ascendant, MC, ARMC, and Vertex are
+% always calculated, and get their values through special handling instead
+% of the usual calculation mechanism, but if the user includes them in
+% |\horoobjects| we calculate the position of the Sun (overwritten later) so
+% as not to have trouble with an unknown object having been listed.
+% \begin{macrocode}
+ \def\horoAscendantSEOpt{-p0}
+ \def\horoMCSEOpt{-p0}
+ \def\horoARMCSEOpt{-p0}
+ \def\horoVertexSEOpt{-p0}
+% \end{macrocode}
+%
+% \begin{macro}{\horosweopt}
+% Any extra options can be passed here.
+% \begin{macrocode}
+ \def\horosweopt{}%
+% \end{macrocode}
+% \end{macro}
+%
+% \subsubsection{House systems}
+% Gauquelin sectors aren't included here because they break the basic model
+% of 12 houses; other things would have to change dramatically to use them
+% properly, and it's not clear whether people who want to typeset wheel
+% charts actually want to typeset them with 36 houses at all anyway.
+% Objects called Ascendant, MC, ARMC, and Vertex are always calculated, and
+% may be of interest (to manually add to |\horoobjects| after the
+% calculation) if using a house
+% system where they don't coincide with house cusps.
+% \changes{v0.91}{2008/07/07}{Added support for Krusinski houses with Swiss Ephemeris}
+% \begin{macrocode}
+ \def\horoAlcabitusHouses{\def\horo@houseletter{b}}
+ \def\horoAxialHouses{\def\horo@houseletter{x}}
+ \def\horoAzimuthalHouses{\def\horo@houseletter{h}}
+ \def\horoCampanusHouses{\def\horo@houseletter{c}}
+ \def\horoEqualHouses{\def\horo@houseletter{a}}
+ \def\horoKochHouses{\def\horo@houseletter{k}}
+ \def\horoKrusinskiHouses{\def\horo@houseletter{U}}
+ \def\horoMorinusHouses{\def\horo@houseletter{m}}
+ \def\horoPlacidusHouses{\def\horo@houseletter{p}}
+ \def\horoPolichPageHouses{\def\horo@houseletter{t}}
+ \def\horoPorphyryHouses{\def\horo@houseletter{o}}
+ \def\horoRegiomontanusHouses{\def\horo@houseletter{r}}
+ \def\horoVehlowHouses{\def\horo@houseletter{v}}
+% \end{macrocode}
+%
+% \subsubsection{Interface stuff}
+% Create a new read for the temporary file and save its name.
+% \begin{macrocode}
+ \newread\horo@tmpfile
+ \edef\horo@tmpfname{\jobname.hor}
+% \end{macrocode}
+%
+% \begin{macro}{\horo@readdata}
+% Read a line from the data file; flag a calculation failure if there's
+% nothing to read. The result goes into |\horo@data|. The line of data is
+% expected to be a decimal number with possible leading or trailing spaces,
+% which we trim off before saving it.
+% \begin{macrocode}
+ \def\horo@readdata{%
+ \ifeof\horo@tmpfile
+ \def\horo@data{0.0}%
+ \horocalculatedfalse
+ \else
+ \begingroup
+ \let\do\@makeother\dospecials
+ \read\horo@tmpfile to \horo@data
+ \trimspaces\horo@data
+ \horo@fterdef\horo@data
+ \endgroup
+ \fi
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\horo@readpos}
+% Read a line from the data file and put it into Pos and DPos of the
+% specified object.
+% \begin{macrocode}
+ \def\horo@readpos#1{%
+ \horo@readdata
+ \expandafter\let\csname horo#1Pos\endcsname\horo@data
+ \expandafter\let\csname horo#1DPos\endcsname\horo@data
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\horo@readposvel}
+% Read (D)Pos as above, and then also read the Vel of the same object.
+% \begin{macrocode}
+ \def\horo@readposvel#1{%
+ \horo@readpos{#1}%
+ \horo@readdata
+ \expandafter\let\csname horo#1Vel\endcsname\horo@data
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\horoobjects}
+% Default object list for Swiss Ephemeris.
+% \begin{macrocode}
+ \def\horoobjects{Sun,Moon,Mercury,Venus,Mars,Jupiter,Saturn,%
+ Uranus,Neptune,Pluto,MeanNode,Lilith,%
+ Chiron,Ceres,Pallas,Juno,Vesta}
+% \end{macrocode}
+% \end{macro}
+%
+% Placidus houses are default:
+% \begin{macrocode}
+ \horoPlacidusHouses
+% \end{macrocode}
+%
+% \subsubsection{Calculation routines}
+% \begin{macro}{\horo@calcobj@}
+% Calculate the position \emph{or} velocity of an object. The second
+% argument is either ``s'' for position, or ``l'' for velocity; these are
+% option letters for |swetest|'s format string. The results will go
+% into the temporary file to be read later.
+% \begin{macrocode}
+ \def\horo@calcobj@#1#2{%
+% \end{macrocode}
+%
+% Start by opening a prophylactic group:
+% \begin{macrocode}
+ \begingroup
+% \end{macrocode}
+%
+% Convert the time of day to hours, minutes, and seconds:
+% \begin{macrocode}
+ \dimen@\horocalctime\p@\horo@d@dms@
+ \horo@twodig\horo@d@min\horo@twodig\horo@d@sec
+% \end{macrocode}
+%
+% Then do a shell escape, filling in all the appropriate options. The
+% formats being used (passed in through \#2) are such as to create lines of
+% output containing only decimal numbers, with a few harmless stray spaces
+% before or after.
+%
+% Note the use of |\ifhoro@ppendtmp|. It starts out false, so only one |>|
+% is used on the command line and the file gets overwritten.
+% \begin{macrocode}
+ \immediate\write18{%
+ swetest -f#2 -head\space
+ -b\horocalcday.\horocalcmonth.\horocalcyear\space
+ -ut\horo@d@deg:\horo@d@min:\horo@d@sec\space
+ \csname horo#1SEOpt\endcsname\space
+ \horosweopt\space
+ \ifhoro@egrep| egrep '^[ 0-9.-]+'\space\fi
+ >\ifhoro@ppendtmp >\fi\space
+ \horo@tmpfname
+ }%
+% \end{macrocode}
+%
+% But after closing the prophylactic group\ldots
+% \begin{macrocode}
+ \endgroup
+% \end{macrocode}
+%
+% \ldots we set the flag true so that subsequent calls to |swetest|
+% will append instead of overwriting.
+% \begin{macrocode}
+ \horo@ppendtmptrue
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\horo@calcobj}
+% Simply invokes |\horo@calcobj| twice to get both position and velocity.
+% \begin{macrocode}
+ \def\horo@calcobj#1{%
+ \horo@calcobj@{#1}{l}%
+ \horo@calcobj@{#1}{s}%
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\horocalculate}
+% Main calculation macro. This starts by creating an option for cusp
+% calculation, as if ``Cusps'' was the name of a legitimate object. It sets
+% |\horo@ppendtmpfalse| to force the temporary file to be overwritten, and
+% |\horocalculatedtrue| (to be possibly turned off if there is trouble
+% reading the results). Then it uses a |\horoforeach| to call
+% |\horo@calcobj| to get position and speed for all the regular objects.
+% The internal function |\horo@calcobj@| is called as if it were going to
+% compute the position of the Cusps object, but that actually writes 16
+% numbers to the temporary file.
+% \begin{macrocode}
+ \def\horocalculate{%
+ \edef\horoCuspsSEOpt{-house\horocalclon,\horocalclat,%
+ \horo@houseletter\space-p}%
+ \horo@ppendtmpfalse
+ \horocalculatedtrue
+ \horoforeach{\horoobjects}{\horo@calcobj}%
+ \horo@calcobj@{Cusps}{l}%
+% \end{macrocode}
+%
+% Now with all the data in the temporary file, we read it in. Open the
+% file, read position and velocity for all the regular objects, and then
+% read the cusps (12 of them) and other things added by |swetest| (4
+% of those) with another loop.
+% \begin{macrocode}
+ \openin\horo@tmpfile=\horo@tmpfname\relax
+ \horoforeach{\horoobjects}{\horo@readposvel}%
+ \horoforeach{\horocusps,Ascendant,MC,ARMC,Vertex}{\horo@readpos}%
+ \closein\horo@tmpfile\relax
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% End the |\ifhoro@swetest| conditional:
+% \begin{macrocode}
+\fi
+% \end{macrocode}
+%
+% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% \subsection{Low-Level Chart Graphics}
+%
+% These macros are a grab bag of utilities for drawing bits and pieces of
+% wheel charts, used by the higher-level routines to actually draw complete
+% charts.
+%
+% \subsubsection{Configuration stuff}
+% \begin{macro}{\ifhorodrawcusps}
+% Setting for whether cusps should be drawn in ready-made wheel charts. The
+% reason the user might not want that would be if they're trying to make do
+% without a birth time. It has to be declared in this unconditional context
+% for parsing reasons.
+% \begin{macrocode}
+\newif\ifhorodrawcusps\horodrawcuspstrue
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\ifhoroboldangles}
+% Similar setting for whether angular-house cusps should be drawn extra
+% bold. A user who really doesn't want cusps must turn off all of
+% |\ifhorodrawcusps|, |\ifhoroboldangles|, and |\ifhoroanglearrows|,
+% as well as (probably) internal house labels; that is to allow drawing of
+% angular cusps and not other cusps, should the user want such a thing.
+% \begin{macrocode}
+\newif\ifhoroboldangles\horoboldanglestrue
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\ifhoroanglearrows}
+% Setting for whether to draw angular house cusps as arrows instead of
+% regular lines.
+% \begin{macrocode}
+\newif\ifhoroanglearrows\horoanglearrowstrue
+% \end{macrocode}
+% \end{macro}
+%
+% Now we can enter a conditional on wheel charts not being disabled by
+% package option.
+% \begin{macrocode}
+\ifhoro@wheels
+% \end{macrocode}
+%
+% \begin{macro}{\horounitlength}
+% This determines the size of the |horoscope| environment, which is 100
+% unit-lengths square. The default value is a little less than $1/100$ of
+% |\textwidth| because we're going to want to put things with their centres
+% on a circle of
+% diameter 100, and the things may actually spill a little outside the
+% circle. Exact value determined by trial and error, and depending on the
+% user's application may need to be changed significantly.
+% \begin{macrocode}
+\newlength{\horounitlength}
+\setlength{\horounitlength}{0.00952\textwidth}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\horoanglecuspwidth}
+% Line width to use in drawing angular cusps when |\horoboldangles| is
+% turned on.
+% \begin{macrocode}
+\newlength{\horoanglecuspwidth}
+\setlength{\horoanglecuspwidth}{1.44pt}
+% \end{macrocode}
+% \end{macro}
+%
+% \subsubsection{Horoscope environment and chart labels}
+% \begin{environment}{horoscope}
+% This is the basic environment in which we'll draw charts. It's just a
+% |picture| of size $100\times100$ units with the origin in the middle.
+% \begin{macrocode}
+\newenvironment{horoscope}{%
+ \setlength{\unitlength}{\horounitlength}%
+ \begin{picture}(100,100)(-50,-50)%
+}{%
+ \end{picture}%
+}
+% \end{macrocode}
+% \end{environment}
+%
+% We also have macros to be used inside a |horoscope| to typeset notes for
+% the whole chart at the centre or any of the four corners of the chart, in
+% what might otherwise be wasted space.
+%
+% \begin{macro}{\horoCnote}
+% \begin{macrocode}
+\newcommand{\horoCnote}[1]{%
+ \put(0,0){\makebox(0,0){\parbox{75\unitlength}{\centering #1}}}%
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\horoULnote}
+% \begin{macrocode}
+\newcommand{\horoULnote}[1]{%
+ \put(-50,50){\makebox(40,0)[t]{\parbox[t]{40\unitlength}{\raggedright #1}}}%
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\horoURnote}
+% \begin{macrocode}
+\newcommand{\horoURnote}[1]{%
+ \put(10,50){\makebox(40,0)[t]{\parbox[t]{40\unitlength}{\raggedleft #1}}}%
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\horoLLnote}
+% \begin{macrocode}
+\newcommand{\horoLLnote}[1]{%
+ \put(-50,-50){\makebox(40,0)[b]{\parbox[t]{40\unitlength}{\raggedright #1}}}%
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\horoLRnote}
+% \begin{macrocode}
+\newcommand{\horoLRnote}[1]{%
+ \put(10,-50){\makebox(40,0)[b]{\parbox[t]{40\unitlength}{\raggedleft #1}}}%
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \subsubsection{Scratch dimension registers}
+% We define our own aliases for eight dimension registers. \LaTeX\ or other
+% packages probably use these same registers, but we always use them within
+% a group in such a way as to not conflict.
+% \begin{macrocode}
+\dimendef\horo@dim@x=1\relax
+\dimendef\horo@dim@y=2\relax
+\dimendef\horo@dim@xa=3\relax
+\dimendef\horo@dim@ya=4\relax
+\dimendef\horo@dim@xb=5\relax
+\dimendef\horo@dim@yb=6\relax
+\dimendef\horo@dim@xc=7\relax
+\dimendef\horo@dim@yc=8\relax
+% \end{macrocode}
+%
+% \subsubsection{Polar-coordinate puts}
+% These are the simplest graphics operations in polar coordinates: putting
+% an arbitrary graphics object at a polar-coordinate location in a |picture|
+% environment, drawing a radial (constant-$\theta$) line segment, or drawing
+% a line segment between two arbitrary points. These are designed for
+% internal use and may expand arguments in a less than friendly way, so
+% although they work well for our higher-level macros they perhaps should
+% not be used incautiously.
+%
+% \begin{macro}{\horo@putpolar}
+% Arguments are $r$, $\theta$, and the object to be |\put| at those
+% coordinates. The centre of the object goes at the specified coordinates.
+% Implementation is straightforward: we just expand and save
+% the polar coordinates to temporary macros, run |\horo@polarconvert| to
+% convert to Cartesian, and then do a |\put|.
+% \begin{macrocode}
+\def\horo@putpolar#1#2#3{%
+ \begingroup
+ \edef\p@one{#1}\edef\p@two{#2}%
+ \horo@polarconvert\p@one\p@two\horo@dim@x\horo@dim@y
+ \put(\TG@rem@pt\horo@dim@x,\TG@rem@pt\horo@dim@y){\makebox(0,0){#3}}%
+ \endgroup
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\horoputradial}
+% Draw a radial; that is, a line segment at a constant $\theta$ coordinate.
+% Arguments are the inner radius, the length, and $\theta$. Implementation
+% is straightforward. One small gotcha is that instead of adding the inner
+% radius and length to get the outer radius, we treat
+% $(\mathit{length},\theta)$ as a vector and do the addition on the
+% Cartesian side, because that saves some shuffling between macro
+% definitions and dimension registers.
+% \changes{v0.92}{2013/05/15}{Replace \cs{drawline} with \cs{Line}}
+% \begin{macrocode}
+\def\horoputradial#1#2#3{%
+ \begingroup
+ \edef\p@one{#1}\edef\p@two{#2}\edef\p@three{#3}%
+ \horo@polarconvert\p@one\p@three\horo@dim@xa\horo@dim@ya
+ \horo@polarconvert\p@two\p@three\horo@dim@xb\horo@dim@yb
+ \advance\horo@dim@xb by\horo@dim@xa
+ \advance\horo@dim@yb by\horo@dim@ya
+ \Line(\TG@rem@pt\horo@dim@xa,\TG@rem@pt\horo@dim@ya)%
+ (\TG@rem@pt\horo@dim@xb,\TG@rem@pt\horo@dim@yb)%
+ \endgroup
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\horoputline}
+% This is the more general line-segment primitive: it takes two $(r,\theta)$
+% pairs and draws a line between them.
+% \changes{v0.92}{2013/05/15}{Replace \cs{drawline} with \cs{Line}}
+% \begin{macrocode}
+\def\horoputline#1#2#3#4{%
+ \begingroup
+ \edef\p@one{#1}\edef\p@two{#2}\edef\p@three{#3}\edef\p@four{#4}%
+ \horo@polarconvert\p@one\p@two\horo@dim@xa\horo@dim@ya
+ \horo@polarconvert\p@three\p@four\horo@dim@xb\horo@dim@yb
+ \Line(\TG@rem@pt\horo@dim@xa,\TG@rem@pt\horo@dim@ya)%
+ (\TG@rem@pt\horo@dim@xb,\TG@rem@pt\horo@dim@yb)%
+ \endgroup
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \subsubsection{Arrowheads}
+% Although \LaTeX\ can draw arrows (which it calls ``vectors''), the
+% implementation has annoying limitations that make it unsuitable for use in
+% \textsf{horoscop}'s charts. Here we define our own arrowhead-drawing
+% routine, with a different set of annoying limitations.
+%
+% \begin{macro}{\horoputarrowhead}
+% Draw an arrowhead with its tip at $(r=\#1,\theta=\#2)$, pointing outward
+% from the origin.
+% The arrowhead is an appropriately scaled and rotated version of the
+% nonconvex polygon with Cartesian vertex coordinates $(0,1)$, $(1,0)$,
+% $(0,-1)$, $(3,0)$. The \#3 argument is equal to the unit length of that
+% coordinate system, measured in horoscope length units.
+%
+% Implementation starts by opening a group and saving the arguments in macros.
+% \begin{macrocode}
+\def\horoputarrowhead#1#2#3{%
+ \begingroup
+ \edef\horo@pa@r{#1}\edef\horo@pa@th{#2}%
+ \edef\horo@pa@sc@le{#3}%
+% \end{macrocode}
+%
+% Convert tip coordinates to Cartesian.
+% \begin{macrocode}
+ \horo@polarconvert\horo@pa@r\horo@pa@th\horo@dim@x\horo@dim@y
+% \end{macrocode}
+%
+% Compute a vector in the direction of the tip, used for offsetting its
+% coordinates to find the coordinates of the other vertices. This vector
+% corresponds to a unit vector in the $+X$ direction of the coordinate
+% system mentioned above.
+% \begin{macrocode}
+ \horo@polarconvert\horo@pa@sc@le\horo@pa@th\horo@dim@xa\horo@dim@ya
+% \end{macrocode}
+%
+% Compute the Cartesian coordinates of the two vertices on either side; each
+% is 3 units back from the tip in the $-X$ direction and $\pm1$ unit off to
+% the side.
+% \begin{macrocode}
+ \horo@dim@xb=\horo@dim@x\relax\horo@dim@yb=\horo@dim@y\relax
+ \advance\horo@dim@xb by-3\horo@dim@xa\relax
+ \advance\horo@dim@yb by-3\horo@dim@ya\relax
+ \advance\horo@dim@xb by-\horo@dim@ya\relax
+ \advance\horo@dim@yb by\horo@dim@xa\relax
+ \horo@dim@xc=\horo@dim@x\relax\horo@dim@yc=\horo@dim@y\relax
+ \advance\horo@dim@xc by-3\horo@dim@xa\relax
+ \advance\horo@dim@yc by-3\horo@dim@ya\relax
+ \advance\horo@dim@xc by\horo@dim@ya\relax
+ \advance\horo@dim@yc by-\horo@dim@xa\relax
+% \end{macrocode}
+%
+% Compute the Cartesian coordinates of the final vertex, at the back of the
+% arrowhead. The sequencing is careful because of not wanting to use an
+% extra pair of registers; the |@xa| series used to hold the offset vector
+% and will now hold the vertex coordinates.
+% \begin{macrocode}
+ \multiply\horo@dim@xa by-2\relax\multiply\horo@dim@ya by-2\relax
+ \advance\horo@dim@xa by\horo@dim@x\relax
+ \advance\horo@dim@ya by\horo@dim@y\relax
+% \end{macrocode}
+%
+% Plot the arrowhead, using \textsf{pict2e}'s |\polygon*| macro.
+% \changes{v0.92}{2013/05/15}{Replace \cs{blacken}\cs{path} with \cs{polygon*}}
+% \begin{macrocode}
+ \polygon*%
+ (\TG@rem@pt\horo@dim@x,\TG@rem@pt\horo@dim@y)%
+ (\TG@rem@pt\horo@dim@xb,\TG@rem@pt\horo@dim@yb)%
+ (\TG@rem@pt\horo@dim@xa,\TG@rem@pt\horo@dim@ya)%
+ (\TG@rem@pt\horo@dim@xc,\TG@rem@pt\horo@dim@yc)%
+ (\TG@rem@pt\horo@dim@x,\TG@rem@pt\horo@dim@y)%
+ \endgroup
+}
+% \end{macrocode}
+% \end{macro}
+
+% \subsubsection{Polar-coordinate curves}
+% Some chart types need to draw curves that are neither radial line segments
+% nor origin-centric circular arcs. For that matter, they need
+% origin-centric circular arcs, which are non-trivial. The curves defined
+% here are cubic B\'{e}zier splines with two endpoints specified in polar
+% coordinates and two control points both set to the value of this vector
+% formula:
+% \[
+% \mathbf{c} = 2\mathbf{m} - \frac{1}{2}(\mathbf{a}+\mathbf{b})
+% \]
+% where $\mathbf{c}$ is the control point, $\mathbf{a}$ and $\mathbf{b}$ are
+% the endpoints, and $\mathbf{m}$ is their \emph{polar} midpoint: the point
+% whose $r$ coordinate is the average of the $r$ coordinates of $\mathbf{a}$
+% and $\mathbf{b}$, and whose $\theta$ coordinate is midway between theirs,
+% going the shorter direction around the circle.
+%
+% This formula was derived by educated trial and error. If the endpoints
+% happen to have the same $r$, it is a reasonable approximation of the
+% origin-centric arc as long as they're within about 30\horodegrees\ of each
+% other, and it looks halfway acceptable even at larger distances.
+% Interesting special effects are obtained if the $r$ values do not match.
+%
+% \begin{macro}{\horoputcurve}
+% Draw a smooth curve connecting $(r=\#1,\theta=\#2)$ to
+% $(r=\#3,\theta=\#4)$. Implementation starts by opening a group and saving
+% all the arguments in macros.
+% \begin{macrocode}
+\def\horoputcurve#1#2#3#4{%
+ \begingroup
+ \edef\horo@pc@r@ne{#1}\edef\horo@pc@th@ne{#2}%
+ \edef\horo@pc@rtw@{#3}\edef\horo@pc@thtw@{#4}%
+% \end{macrocode}
+%
+% Both $\theta$ coordinates are subjected to |\horo@chartrotate|.
+% \begin{macrocode}
+ \dimen@=\horo@pc@th@ne\p@\relax\horo@chartrotate
+ \edef\horo@pc@th@ne{\TG@rem@pt\dimen@}%
+ \dimen@=\horo@pc@thtw@\p@\relax\horo@chartrotate
+ \edef\horo@pc@thtw@{\TG@rem@pt\dimen@}%
+% \end{macrocode}
+%
+% Convert first endpoint to Cartesian.
+% \begin{macrocode}
+ \horo@polarconvert\horo@pc@r@ne\horo@pc@th@ne\horo@dim@xa\horo@dim@ya
+% \end{macrocode}
+%
+% Convert second endpoint to Cartesian.
+% \begin{macrocode}
+ \horo@polarconvert\horo@pc@rtw@\horo@pc@thtw@\horo@dim@xb\horo@dim@yb
+% \end{macrocode}
+%
+% Compute the polar-coordinate midpoint. Radius is simple average, but
+% angle must go through |\horo@midpoint| to handle cases like wrapping
+% around 360\horodegrees.
+% \begin{macrocode}
+ \dimen@=\horo@pc@r@ne\p@\relax
+ \advance\dimen@ by\horo@pc@rtw@\p@\relax
+ \divide\dimen@ by2\relax
+ \edef\horo@pc@rmid{\TG@rem@pt\dimen@}%
+ \horo@midpoint\horo@pc@th@ne\horo@pc@thtw@
+ \edef\horo@pc@thmid{\TG@rem@pt\dimen@}%
+% \end{macrocode}
+%
+% Convert midpoint to Cartesian.
+% \begin{macrocode}
+ \horo@polarconvert\horo@pc@rmid\horo@pc@thmid\horo@dim@x\horo@dim@y
+% \end{macrocode}
+%
+% Compute the control point, which basically means moving the control point
+% away from the polar midpoint by an amount equal to and opposite from the
+% difference between it and the Cartesian midpoint. Recall that
+% \textsf{epic}'s spline curves are based on the Chaikin technique of
+% cutting corners off a polyline until it looks like a smooth curve. With
+% the switch to \textsf{pict2e} we are no longer using classic \LaTeX\
+% splines, but the underlying concept of a cubic spline should remain
+% the same. The initial polyline looks like two sides of a triangle, with
+% the remaining side being the segment directly connecting the two
+% endpoints. If we place the control point \emph{twice} as far away from
+% that direct segment as the polar midpoint would be, then after we're
+% finished cutting corners the middle of the remaining curve should end up
+% pretty close to half its original (control point) distance from the
+% Cartesian midpoint, and \emph{the same distance} as the polar midpoint
+% would be---thus passing through the polar midpoint. We want it to pass
+% through the polar midpoint at least in the important special case of
+% drawing an origin-centred arc. That's the education behind the educated
+% guess of the control point formula. In actual fact it doesn't work
+% perfectly because the cut ratio isn't right, but the result looks good
+% anyway.
+% \begin{macrocode}
+ \multiply\horo@dim@x by -4\relax
+ \advance\horo@dim@x by \horo@dim@xa\relax
+ \advance\horo@dim@x by \horo@dim@xb\relax
+ \divide\horo@dim@x by -2\relax
+ \multiply\horo@dim@y by -4\relax
+ \advance\horo@dim@y by \horo@dim@ya\relax
+ \advance\horo@dim@y by \horo@dim@yb\relax
+ \divide\horo@dim@y by -2\relax
+% \end{macrocode}
+%
+% With all the relevant coordinates computed, plot the actual curve and end.
+% \changes{v0.92}{2013/05/16}{Replace \cs{spline} with \cs{cbezier}}
+% \begin{macrocode}
+ \cbezier(\TG@rem@pt\horo@dim@xa,\TG@rem@pt\horo@dim@ya)%
+ (\TG@rem@pt\horo@dim@x,\TG@rem@pt\horo@dim@y)%
+ (\TG@rem@pt\horo@dim@x,\TG@rem@pt\horo@dim@y)%
+ (\TG@rem@pt\horo@dim@xb,\TG@rem@pt\horo@dim@yb)%
+ \endgroup
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\horoconncurve}
+% This is the most common case of using |\horoputcurve|: drawing a little
+% connector to show the relationship between an object label (plotted at the
+% object's DPos) and a radial that shows the object's real location (plotted
+% at Pos). It draws a curve from radius \#1 and the Pos of object \#3, to
+% radius \#2 and the DPos of object \#3. Object name last to make it easy
+% to call inside a |\horoforeach|.
+% \begin{macrocode}
+\def\horoconncurve#1#2#3{%
+ \horoputcurve{#1}{\csname horo#3Pos\endcsname}%
+ {#2}{\csname horo#3DPos\endcsname}%
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \subsubsection{Locating objects}
+% These two simple macros are used to find where a given object should be
+% plotted, which is a frequent operation in the ready-made wheels.
+%
+% \begin{macro}{\horo@getobjdpos}
+% Gets the object's DPos and rotates it into chart coordinates.
+% \begin{macrocode}
+\def\horo@getobjdpos#1{%
+ \dimen@\csname horo#1DPos\endcsname\p@
+ \horo@chartrotate
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\horo@getobjsdms}
+% Gets the object's Pos (not DPos) and converts it into SDMS, which is what
+% you want if you're going to print a label saying where the object is in
+% the sky. Then also gets the DPos so you know where to print the label,
+% which might be different from the actual sky location if the object has
+% been adjusted.
+% \begin{macrocode}
+\def\horo@getobjsdms#1{%
+ \expandafter\dimen@\csname horo#1Pos\endcsname\p@
+ \horo@d@sdms
+ \horo@getobjdpos{#1}%
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \subsubsection{Cusps, ticks, and sign keys}
+% These display some landmark kinds of things that people like to have
+% in charts. Cusps are just lines radiating
+% out from the centre at locations determined by the chart data. Ticks are
+% similar radial lines that occur at regular intervals to create a sort of
+% angular ruler around the circle, allowing visual measurement of angles.
+% A sign key shows the locations of the Zodiac signs; it's simply the
+% twelve sign symbols arranged regularly around a circle. In this
+% subsection we also describe cusp labels, which show the degree, sign, and
+% minute of a house cusp (or, concievably, something else) written around
+% the circle at a constant radius.
+%
+% \begin{macro}{\horo@pr}
+% Helper for |\horoputradials|: draw a radial at the DPos of object \#3.
+% \begin{macrocode}
+\def\horo@pr#1#2#3{%
+ \horo@getobjdpos{#3}%
+ \horoputradial{#1}{#2}{\TG@rem@pt\dimen@}%
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\horoputradials}
+% Iterate through a list of objects drawing radials for each. Normally
+% you'd use this to draw the radial lines separating houses.
+% \begin{macrocode}
+\def\horoputradials#1#2#3{%
+ \horoforeach{#1}{\horo@pr{#2}{#3}}%
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\horo@pt}
+% Helper for |\horoputticks|. Puts one tick, advances |\dimen@|, and then
+% tail-recurses until we've gone around the whole circle.
+% \begin{macrocode}
+\def\horo@pt{%
+ \ifdim\dimen@<360\p@
+ {\horo@chartrotate
+ \horoputradial{\horo@pta}{\horo@ptb}{\TG@rem@pt\dimen@}}%
+ \advance\dimen@ by \horo@ptc\p@
+ \expandafter\horo@pt
+ \fi
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\horoputticks}
+% Repeats |\putradial{#1}{#2}| every \#3 degrees around the circle to create
+% a regular pattern. Implementation saves all the arguments into macros,
+% sets |\dimen@| to zero, and calls |\horo@pt| to do the actual plotting.
+% \begin{macrocode}
+\def\horoputticks#1#2#3{%
+ \begingroup
+ \edef\horo@pta{#1}\edef\horo@ptb{#2}\edef\horo@ptc{#3}%
+ \dimen@=\z@
+ \horo@pt
+ \endgroup
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\horo@pa}
+% Helper for |\horoputarrows|: draw an arrow, pointing outward, at the
+% DPos of object \#3.
+% \begin{macrocode}
+\def\horo@pa#1#2#3{%
+ \horo@getobjdpos{#3}%
+ \horoputarrowhead{#1}{\TG@rem@pt\dimen@}{#2}%
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\horoputarrows}
+% Iterate through a list of objects drawing arrows for each. Normally
+% you'd use this to draw the arrowheads for angular house cusps.
+% \begin{macrocode}
+\def\horoputarrows#1#2#3{%
+ \horoforeach{#1}{\horo@pa{#2}{#3}}%
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\horo@psk}
+% Helper for |\horoputsignkey|. This is another tail-recursive loop with
+% |\count0| as the loop counter, going from 0 to 11.\footnote{Well, it's
+% one louder, isn't it?} For each sign we
+% calculate the $\theta$ coordinate (of the middle of the sign, the
+% 15\horodegrees\ mark) and print the appropriate Zodiac symbol
+% at that angle and the chosen radius.
+% \begin{macrocode}
+\def\horo@psk{
+ \ifnum\count0<12\relax
+ \dimen@=30pt\relax
+ \dimen@\count0\dimen@\relax
+ \advance\dimen@ by 15pt\relax
+ \horo@chartrotate
+ \advance\count0 by 1%
+ \horo@putpolar{\horo@radius}{\TG@rem@pt\dimen@}%
+ {\Zodiac{\the\count0}}%
+ \expandafter\horo@psk
+ \fi
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\horoputsignkey}
+% Driver for plotting a sign key. It just saves the argument, sets the loop
+% counter to zero, and invokes |\horo@psk|.
+% \begin{macrocode}
+\def\horoputsignkey#1{%
+ \begingroup
+ \def\horo@radius{#1}%
+ \count0=0\relax
+ \horo@psk
+ \endgroup
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\horoputcusplabel}
+% Make a label for a house cusp or (astrological) angle. This is a preview
+% of the techniques used in the object label code later on. The arguments
+% are the radius, the angular spacing in degrees between the three elements
+% of the label, and the object to label.
+%
+% First we open a
+% prophylactic group and get the object's location data, both its Pos in
+% SDMS (which is what the label will \emph{say}) and its DPos (which is
+% \emph{where} the label will appear).
+% \begin{macrocode}
+\def\horoputcusplabel#1#2#3{%
+ \begingroup
+ \horo@getobjsdms{#3}%
+% \end{macrocode}
+%
+% The sign part of the label is straightforwardly set at DPos and the
+% specified radius.
+% \begin{macrocode}
+ \horo@putpolar{#1}{\TG@rem@pt\dimen@}{\Zodiac{\horo@d@sign}}%
+% \end{macrocode}
+%
+% Determining reading direction: the label is intended to be read in a
+% circular direction that points away from the 135\horodegrees\ mark,
+% which is at the upper left of the chart. That way it will come as close
+% as possible to reading either left to right or top to bottom. That means
+% if the label's centre location $\theta$ coordinate is less than
+% 135\horodegrees\ or more than 315\horodegrees, then the reading direction
+% will be turnwise and otherwise it will be widdershins.
+% The |\horo@pcl@s| macro is set to T or W accordingly.
+% \begin{macrocode}
+ \def\horo@pcl@s{W}%
+ \ifdim\dimen@<135\p@\def\horo@pcl@s{T}\fi
+ \ifdim\dimen@>315\p@\def\horo@pcl@s{T}\fi
+% \end{macrocode}
+%
+% Typeset the part of the label that goes \#2 degrees turnwise of the
+% sign symbol. If the reading direction is turnwise, then this will be the
+% end of the label---the minutes part. Otherwise it will be the degrees
+% part. This happens inside a group so that |\dimen@| will be restored to
+% the $\theta$ of the sign symbol afterward.
+% \begin{macrocode}
+ \begingroup
+ \advance\dimen@ by -#2\p@\horo@fixdimen@
+ \horo@putpolar{#1}{\TG@rem@pt\dimen@}{%
+ \expandafter\if\horo@pcl@s T%
+ \horo@d@min\horominutes%
+ \else
+ \horo@d@deg\horodegrees%
+ \fi
+ }%
+ \endgroup
+% \end{macrocode}
+%
+% Typeset the part of the label that goes \#2 degrees widdershins of the
+% sign symbol. Essentially the same logic as the other part above, except
+% that this time we don't need to save |\dimen@| because it won't be used
+% again.
+% \begin{macrocode}
+ \advance\dimen@ by #2\p@\horo@fixdimen@
+ \horo@putpolar{#1}{\TG@rem@pt\dimen@}{%
+ \expandafter\if\horo@pcl@s T%
+ \horo@d@deg\horodegrees%
+ \else
+ \horo@d@min\horominutes%
+ \fi
+ }%
+ \endgroup
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \subsubsection{Object labels}
+% In general, an object label is printed in a radial direction with up to
+% six chunks (object symbol, sign symbol, degrees, minutes, seconds,
+% retrograde symbol) at equally spaced radii; the $\theta$ of all of them is
+% determined by the DPos, and the sequence in which they're printed (which
+% chunk is closest to the centre and which is furthest) is determined by
+% $\theta$ to create a consistent reading direction. We offer a few
+% variations to provide varying levels of control over the details.
+%
+% \begin{macro}{\horoputobjsymbol}
+% Put the symbol for object \#2 at its DPos and radius \#1.
+% \begin{macrocode}
+\def\horoputobjsymbol#1#2{%
+ \begingroup
+ \horo@getobjdpos{#2}%
+ \horo@putpolar{#1}{\TG@rem@pt\dimen@}{\csname #2Symbol\endcsname}%
+ \endgroup
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\horo@pol@i}
+% Support for the smarter object-labelling macros. Opens a group, sets
+% |\dimen1| to \#1$+$\#2, and gets the DPos and SDMS of Pos for object \#3.
+% Based on DPos, the macro |\horo@pol@s| is set to indicate reading
+% direction: H for hubward or R for rimward to make the reading
+% direction be as far from the 135\horodegrees\ mark\footnote{Great
+% A'Tuin's left rear flipper.} as possible.
+% \begin{macrocode}
+\def\horo@pol@i#1#2#3{%
+ \begingroup
+ \dimen1=#1\p@\advance\dimen1by#2\p@
+ \horo@getobjsdms{#3}%
+ \def\horo@pol@s{H}%
+ \ifdim\dimen@<45\p@\def\horo@pol@s{R}\fi
+ \ifdim\dimen@>225\p@\def\horo@pol@s{R}\fi
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\horoputobjdeglabel}
+% Typeset a label consisting of the object's degree and sign. Invokes
+% |\horo@pol@i|, and then typesets the sign symbol and degree in an order
+% determined by reading direction so that degree will read first. Arguments
+% are radius of the innermost chunk, radius step size between the two
+% chunks, and object name.
+% \begin{macrocode}
+\def\horoputobjdeglabel#1#2#3{%
+ \horo@pol@i{#1}{#2}{#3}%
+ \expandafter\if\horo@pol@s H%
+ \horo@putpolar{#1}{\TG@rem@pt\dimen@}{\Zodiac{\horo@d@sign}}%
+ \horo@putpolar{\TG@rem@pt\dimen1}{\TG@rem@pt\dimen@}%
+ {\horo@d@deg\horodegrees}%
+ \else
+ \horo@putpolar{#1}{\TG@rem@pt\dimen@}{\horo@d@deg\horodegrees}%
+ \horo@putpolar{\TG@rem@pt\dimen1}{\TG@rem@pt\dimen@}%
+ {\Zodiac{\horo@d@sign}}%
+ \fi
+ \endgroup
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\horoputobjminlabel}
+% Much the same as |\horoputobjdegreelabel| but makes a three-chunk label
+% that reads degrees, sign, minutes.
+% \begin{macrocode}
+\def\horoputobjminlabel#1#2#3{%
+ \horo@pol@i{#1}{#2}{#3}%
+ \expandafter\if\horo@pol@s H%
+ \horo@putpolar{#1}{\TG@rem@pt\dimen@}%
+ {\horo@d@min\horominutes}%
+ \horo@putpolar{\TG@rem@pt\dimen1}{\TG@rem@pt\dimen@}%
+ {\Zodiac{\horo@d@sign}}%
+ \advance\dimen1by#2\p@
+ \horo@putpolar{\TG@rem@pt\dimen1}{\TG@rem@pt\dimen@}%
+ {\horo@d@deg\horodegrees}%
+ \else
+ \horo@putpolar{#1}{\TG@rem@pt\dimen@}%
+ {\horo@d@deg\horodegrees}%
+ \horo@putpolar{\TG@rem@pt\dimen1}{\TG@rem@pt\dimen@}%
+ {\Zodiac{\horo@d@sign}}%
+ \advance\dimen1by#2\p@
+ \horo@putpolar{\TG@rem@pt\dimen1}{\TG@rem@pt\dimen@}%
+ {\horo@d@min\horominutes}%
+ \fi
+ \endgroup
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\horoputobjseclabel}
+% Typesets a four-chunk label reading degrees, sign, minutes, seconds.
+% \begin{macrocode}
+\def\horoputobjseclabel#1#2#3{%
+ \horo@pol@i{#1}{#2}{#3}%
+ \expandafter\if\horo@pol@s H%
+ \horo@putpolar{#1}{\TG@rem@pt\dimen@}%
+ {\horo@d@sec\horoseconds}%
+ \horo@putpolar{\TG@rem@pt\dimen1}{\TG@rem@pt\dimen@}%
+ {\horo@d@min\horominutes}%
+ \advance\dimen1by#2\p@
+ \horo@putpolar{\TG@rem@pt\dimen1}{\TG@rem@pt\dimen@}%
+ {\Zodiac{\horo@d@sign}}%
+ \advance\dimen1by#2\p@
+ \horo@putpolar{\TG@rem@pt\dimen1}{\TG@rem@pt\dimen@}%
+ {\horo@d@deg\horodegrees}%
+ \else
+ \horo@putpolar{#1}{\TG@rem@pt\dimen@}%
+ {\horo@d@deg\horodegrees}%
+ \horo@putpolar{\TG@rem@pt\dimen1}{\TG@rem@pt\dimen@}%
+ {\Zodiac{\horo@d@sign}}%
+ \advance\dimen1by#2\p@
+ \horo@putpolar{\TG@rem@pt\dimen1}{\TG@rem@pt\dimen@}%
+ {\horo@d@min\horominutes}%
+ \advance\dimen1by#2\p@
+ \horo@putpolar{\TG@rem@pt\dimen1}{\TG@rem@pt\dimen@}%
+ {\horo@d@sec\horoseconds}%
+ \fi
+ \endgroup
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\horoputrxlabel}
+% Checks the Vel of object \#2. If it is negative, typesets
+% |\horoRetrogradeSymbol| at radius \#1 to indicate ``retrograde.''
+% \begin{macrocode}
+\def\horoputrxlabel#1#2{%
+ \begingroup
+ \dimen@\csname horo#2Vel\endcsname\p@
+ \ifdim\dimen@<\z@\relax
+ \horo@getobjdpos{#2}%
+ \horo@putpolar{#1}{\TG@rem@pt\dimen@}{\horoRetrogradeSymbol}%
+ \fi
+ \endgroup
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\horoputsmartlabel}
+% This is the do-everything label macro. It takes one argument which is the
+% object name, but it's sensitive to the definitions of several other
+% macros, most notably |\horo@lblone| and |\horo@lbltwo|. Each of those is a
+% string consisting of some combination of the letters (d, m, s, z, y, r)
+% for Degrees, Minutes, Seconds, Zodiac sign symbol, object sYmbol, and
+% possible Retrograde, respectively. They represent the sequence of chunks
+% to typeset reading in an \emph{inward} direction, for cases where the
+% preferred reading direction is inward for |\horo@lblone| or outward for
+% |\horo@lbltwo|. The reason to do it that way is that one typically wants
+% the order of some chunks to change with reading direction but not others.
+% A typical setting would be |\horo@lblone| equal to ``ydzmr'' and
+% |\horo@lbltwo| equal to ``ymzdr''. Then the degrees, sign, and minute
+% will always read in that order as closely as possible to top to bottom and
+% left to right, but the object symbol will always be on
+% the outside and the optional retrograde symbol always on the inside.
+% Proper handling and configuration of reading direction is the major
+% complication in this macro and responsible for much of the complexity of
+% its support macros.
+%
+% The implementation at this high level is fairly simple: it wraps
+% everything in a group to prevent pollution, gets the DPos and SDMS Pos of
+% the object, and figures out the reading direction into |\horo@pol@s|.
+% The |\dimen1| register is set to |\horo@outerrad|, which is the radius at
+% which we'll place the outermost chunk. Then depending on the reading
+% direction it calls |\horo@psl| with either |\horo@lblone| or
+% |\horo@lbltwo| and a $\mathcal{Q}$ (which is still exotic, remember) to
+% aid in parsing.
+% \begin{macrocode}
+\def\horoputsmartlabel#1{%
+ \begingroup
+ \horo@getobjsdms{#1}%
+ \def\horo@psl@o{#1}%
+ \def\horo@pol@s{H}%
+ \ifdim\dimen@<45\p@\def\horo@pol@s{R}\fi
+ \ifdim\dimen@>225\p@\def\horo@pol@s{R}\fi
+ \dimen1=\horo@outerrad\p@\relax
+ \expandafter\if\horo@pol@s H%
+ \expandafter\horo@psl\horo@lblone Q%
+ \else
+ \expandafter\horo@psl\horo@lbltwo Q%
+ \fi
+ \endgroup
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\horo@psl}
+% Main chunk-putting code for |\horoputsmartlabel|. This is a
+% tail-recursive loop that iterates through the format string typesetting
+% one chunk per letter until it hits the terminating $\mathcal{Q}$. For
+% each chunk it calls |\horo@psl@| to actually typeset the chunk, and
+% subtracts |\horo@delta| from |\dimen1|, which is where we're storing the
+% current radius, initially |\horo@outerrad|.
+% \begin{macrocode}
+\def\horo@psl#1{%
+ \def\horo@psl@a{#1}%
+ \ifx\horo@psl@a\horo@cue\relax
+ \else
+ \horo@putpolar{\TG@rem@pt\dimen1}{\TG@rem@pt\dimen@}%
+ {\horo@psl@#1}%
+ \advance\dimen1by-\horo@delta\p@\relax
+ \expandafter\horo@psl
+ \fi
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\horo@psl@}
+% Typeset a single chunk. This is simply a bunch of |\if|s that identify
+% the chunk type and typeset the appropriate data.
+% \begin{macrocode}
+\def\horo@psl@#1{%
+ \if#1d\relax\horo@d@deg\horodegrees\fi
+ \if#1m\relax\horo@d@min\horominutes\fi
+ \if#1s\relax\horo@d@sec\horoseconds\fi
+ \if#1z\relax\Zodiac{\horo@d@sign}\fi
+ \if#1y\relax\csname \horo@psl@o Symbol\endcsname\fi
+ \if#1r\relax
+ \begingroup
+ \dimen@\csname horo\horo@psl@o Vel\endcsname\p@
+ \ifdim\dimen@<\z@\relax\horoRetrogradeSymbol\fi
+ \endgroup
+ \fi
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\horoscanlabels}
+% User interface to set up |\horo@lblone| and |\horo@lbltwo|. The argument
+% may be a format string in the format described above, or \emph{two} of
+% them separated by a slash. If one, then both formats are set to it. If
+% two, then the first goes into |\horo@lblone| and the second into
+% |\horo@lbltwo|. The implementation works by calling the helper
+% |\horo@scanlabels@| with two copies of \#1 and some terminating stuff so
+% that it can read the first two slash-terminated arguments and get either
+% the user's two strings, or the user's one string repeated twice.
+% \begin{macrocode}
+\def\horoscanlabels#1{%
+ \horo@scanlabels@ #1/#1/xQ%
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\horo@scanlabels@}
+% Helper for |\horoscanlabels|. Looks for two slash-terminated arguments
+% and then throws out everything up to the $\mathcal{Q}$. The arguments go
+% into |\horo@lblone| and |\horo@lbltwo|, but we also take the opportunity
+% to scan \#1 for length, using the helper macro |\horo@scanlabels@@| which
+% searches for a $\mathcal{Q}$ bumping the |\count0| register for every
+% letter it sees. The result of that scan goes into |\horolbllen|, and may
+% be used to automatically adjust radius step and text size.
+% \begin{macrocode}
+\def\horo@scanlabels@#1/#2/#3Q{%
+ \def\horo@lblone{#1}%
+ \def\horo@lbltwo{#2}%
+ \begingroup
+ \count0=0\relax
+ \horo@scanlabels@@#1Q%
+ \edef\horolbllen{\the\count0}%
+ \horo@fterdef\horolbllen
+ \endgroup
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\horo@scanlabels@@}
+% Helper macro for |\horo@scanlabels@|: tail-recursive loop to count letters
+% in a $\mathcal{Q}$-terminated string.
+% \begin{macrocode}
+\def\horo@scanlabels@@#1{%
+ \def\horo@sls@@a{#1}%
+ \ifx\horo@sls@@a\horo@cue\relax
+ \else
+ \advance\count0by1\relax
+ \expandafter\horo@scanlabels@@
+ \fi
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\horosetsmartradii}
+% Sets up the radii for |\horoputsmartlabel| in a semi-intelligent way,
+% sensitive to the label format string length from the previous macro. The
+% outer radius is set to \#1. The step size (distance between chunks) is
+% set to $\#2-n\cdot\#3$ where $n$ is the number of chunks specified in the
+% (inward-reading) label format string. The idea is that with more chunks,
+% you want them to be closer together. However, simply allocating a fixed
+% amount of space and dividing by the number of chunks is suboptimal because
+% with few chunks they end up too far apart; it's better, if the user
+% selects fewer chunks than the chart was originally designed for, to spread
+% them out a little but also leave substantial extra space on the inside
+% side. A more rigorous solution might involve using \TeX's fancy
+% variable-stretchability glue to create something that could be thought of
+% as a ``radial list'' comparable to horizontal and vertical lists.
+% \begin{macrocode}
+\def\horosetsmartradii#1#2#3{
+ \def\horo@outerrad{#1}%
+ \begingroup
+ \dimen@=#3\p@\relax
+ \multiply\dimen@ by -\horolbllen\relax
+ \advance\dimen@ by #2\p@\relax
+ \edef\horo@delta{\TG@rem@pt\dimen@}%
+ \horo@fterdef\horo@delta
+ \endgroup
+}
+% \end{macrocode}
+% \end{macro}
+%
+% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% \subsection{Aspect Web}
+%
+% These routines typeset a web of lines that indicate aspects, with symbols
+% on their midpoints to clarify which aspects are which. The aspects are
+% automatically recognized, with some limited support for orbs and such, but
+% it's up to the user to do it manually if they want better control over
+% exactly which aspects will be shown.
+%
+% At this point in the code we no longer need to use exotic $\mathcal{Q}$
+% for parsing, and we're going to need regular Q for use in spelling things
+% like ``Quincunx,'' so we have to make Q mundane again. We drop
+% temporarily out of the |\ifhoro@wheels| conditional to do it so that
+% things will not be left in a screwed-up state in the event |nowheels| has
+% been selected.
+% \begin{macrocode}
+\fi
+%% MAKING Q MUNDANE HERE!
+\catcode`\Q=11
+\ifhoro@wheels
+% \end{macrocode}
+%
+% \subsubsection{Configuration settings}
+% \begin{macro}{\horoaspectobjectsa}
+% List of objects that can appear on one side of an aspect relation. By
+% default, all objects.
+% \begin{macrocode}
+\def\horoaspectobjectsa{\horoobjects}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\horoaspectobjectsb}
+% List of objects that can appear on the other side of an aspect relation.
+% This is separated from |\horoaspectobjectsa| so that you can set one to
+% all objects and the other to only ``major'' objects, to prevent counting
+% aspects that involve only ``minor'' objects.
+% \begin{macrocode}
+\def\horoaspectobjectsb{\horoobjects}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\horoaspects}
+% This lists the aspect types that will be recognized. Note conjunctions
+% are not normally listed because they don't need to be marked in the aspect
+% web, though if one wanted to add conjunction symbols on top of the ticks
+% to really flag conjunctions, then that would be possible.
+% \begin{macrocode}
+\def\horoaspects{Opposition,Trine,Square,Sextile}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\ifhoroaspectweb}
+% Configuration flag for the ready-made wheels: whether they should or
+% shouldn't put an aspect web in the middle of the wheel.
+% \begin{macrocode}
+\newif\ifhoroaspectweb\horoaspectwebtrue
+% \end{macrocode}
+% \end{macro}
+%
+% \subsubsection{Per-aspect-type configuration}
+% First we state the angular separation that defines each aspect. Only
+% longitude aspects are supported; parallel/antiparallel aren't shown.
+% \begin{macrocode}
+\def\horoConjunctionAngle{0}
+\def\horoOppositionAngle{180}
+\def\horoTrineAngle{120}
+\def\horoSquareAngle{90}
+\def\horoQuintileAngle{72}
+\def\horoBiquintileAngle{144}
+\def\horoSextileAngle{60}
+\def\horoQuincunxAngle{150}
+\def\horoSemisextileAngle{30}
+\def\horoSemisquareAngle{45}
+\def\horoSesquiquadrateAngle{135}
+% \end{macrocode}
+%
+% Then the orb for each aspect. This package supports only a very simple
+% model for orb, in which it's determined solely by the aspect type.
+% Advanced users can do clever things with redrawing a couple of aspect webs
+% for different objects, to get orbs depending on the objects involved or on
+% other variables.
+% \begin{macrocode}
+\def\horoConjunctionOrb{6}
+\def\horoOppositionOrb{6}
+\def\horoTrineOrb{5}
+\def\horoSquareOrb{5}
+\def\horoQuintileOrb{2}
+\def\horoBiquintileOrb{2}
+\def\horoSextileOrb{4}
+\def\horoQuincunxOrb{3}
+\def\horoSemisextileOrb{3}
+\def\horoSemisquareOrb{2}
+\def\horoSesquiquadrateOrb{2}
+% \end{macrocode}
+%
+% \subsubsection{Drawing the aspect web}
+% \begin{macro}{\horoputaspect}
+% Draw a single aspect. The arguments are \#1 radius of the endpoints, \#2
+% and \#3 the $\theta$ coordinates of the endpoints, and \#4 the symbol to
+% display at the midpoint of the aspect. Implementation starts by opening a
+% group and saving the arguments to macros.
+% \begin{macrocode}
+% radius theta1 theta2 symbol
+\def\horoputaspect#1#2#3#4{%
+ \begingroup
+ \edef\p@one{#1}\edef\p@two{#2}\edef\p@three{#3}%
+% \end{macrocode}
+%
+% Apply chart rotation to both $\theta$ coordinates:
+% \begin{macrocode}
+ \dimen@=\p@two\p@\relax\horo@chartrotate\edef\p@two{\TG@rem@pt\dimen@}%
+ \dimen@=\p@three\p@\relax\horo@chartrotate\edef\p@three{\TG@rem@pt\dimen@}%
+% \end{macrocode}
+%
+% Convert endpoints to polar and draw the line segment representing the
+% aspect:
+% \changes{v0.92}{2013/05/15}{Replace \cs{drawline} with \cs{Line}}
+% \begin{macrocode}
+ \horo@polarconvert\p@one\p@two\horo@dim@xa\horo@dim@ya
+ \horo@polarconvert\p@one\p@three\horo@dim@xb\horo@dim@yb
+ \Line(\TG@rem@pt\horo@dim@xa,\TG@rem@pt\horo@dim@ya)%
+ (\TG@rem@pt\horo@dim@xb,\TG@rem@pt\horo@dim@yb)%
+% \end{macrocode}
+%
+% Compute the midpoint by doing an average on the Cartesian coordinates:
+% \begin{macrocode}
+ \advance\horo@dim@xa by\horo@dim@xb
+ \advance\horo@dim@ya by\horo@dim@yb
+ \divide\horo@dim@xa by2\divide\horo@dim@ya by2%
+% \end{macrocode}
+%
+% Put the symbol at the midpoint and end.
+% \begin{macrocode}
+ \put(\TG@rem@pt\horo@dim@xa,\TG@rem@pt\horo@dim@ya){\makebox(0,0){#4}}%
+ \endgroup
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\horo@aa}
+% \changes{v0.91}{2008/08/30}{Fixed only-checking-one-direction bug}
+% Helper for more automated aspect drawing: this checks whether there is an
+% aspect (with angular separation of $\#1\pm\#2$) between objects \#5 and
+% \#6, and if so, draws an aspect between them with endpoint radius \#3 and
+% symbol \#4. The two object names come last because this is meant to be
+% used in a |\horo@dblforeach|.
+% \begin{macrocode}
+\def\horo@aa#1#2#3#4#5#6{%
+ \dimen@\csname horo#5Pos\endcsname\p@
+ \advance\dimen@ by -\csname horo#6Pos\endcsname\p@
+ \horo@fixdimen@diff
+ \ifdim\dimen@<\z@\relax\multiply\dimen@ by -1\relax\fi
+ \advance\dimen@ by -#1\p@
+ \horo@fixdimen@diff
+ \ifdim\dimen@<\z@\relax\multiply\dimen@ by -1\relax\fi
+ \ifdim\dimen@<#2\p@\relax
+ \horoputaspect{#3}{\csname horo#5Pos\endcsname}%
+ {\csname horo#6Pos\endcsname}{#4}%
+ \fi
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\horoautoaspect}
+% Wrapper for |\horo@aa|: runs the |\horo@dblforeach| inside a group. This
+% does all the checking and drawing for one aspect type.
+% \begin{macrocode}
+\def\horoautoaspect#1#2#3#4#5#6{%
+ \begingroup
+ \horo@dblforeach{#1}{#2}{\horo@aa{#3}{#4}{#5}{#6}}%
+ \endgroup
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\horo@aas}
+% Helper for |\horoautoaspects|: calls |\horoautoaspect| to do one aspect
+% type, using configured settings. Argument \#1 is radius and \#2 is the
+% aspect type name. Note that this does every pair of one object from
+% |\horoaspectobjectsa| and one from |\horoaspectobjectsb|, which will quite
+% possibly hit a given pair twice, once in each direction
+% (e.g.\ Sun/Moon and Moon/Sun) Normally that will not be a problem; it
+% only means typesetting an identical aspect twice, one on top of the other.
+% \begin{macrocode}
+\def\horo@aas#1#2{%
+ \horoautoaspect{\horoaspectobjectsa}{\horoaspectobjectsb}%
+ {\csname horo#2Angle\endcsname}{\csname horo#2Orb\endcsname}%
+ {#1}{\csname horo#2Symbol\endcsname}%
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\horoautoaspects}
+% Do the entire aspect web by iterating over all configured aspect type
+% names. Most configuration settings come in through defined macros; the
+% sole argument is the radius.
+% \begin{macrocode}
+\def\horoautoaspects#1{%
+ \horoforeach{\horoaspects}{\horo@aas{#1}}%
+}
+% \end{macrocode}
+% \end{macro}
+%
+% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% \subsection{Internal House Labels}
+%
+% These support adding labels to the middles of houses. The labels are
+% treated (for the purposes of the adjustment code) as objects that take up
+% space in the house, so they make it much more likely for a house to end up
+% overfilled and having to expand. However, they also make it easier
+% to identify houses at a glance.
+%
+% Much of the support for these is actually incorporated into the
+% ``adjustment'' code below. At this point we only define configuration
+% data and the routines to actually print the labels.
+%
+% \begin{macro}{\ifhorointhouselabels}
+% Define an |\if| for controlling whether to use this feature.
+% \begin{macrocode}
+\newif\ifhorointhouselabels\horointhouselabelsfalse
+% \end{macrocode}
+% \end{macro}
+%
+% Allocate a \LaTeX\ counter for which house we're in.
+% \begin{macrocode}
+\newcounter{horohouse}
+% \end{macrocode}
+%
+% \begin{macro}{\horohouselabel}
+% The default form of a label is the counter value in upper-case Roman, but
+% this can be redefined if the user wants something else.
+% \begin{macrocode}
+\newcommand{\horohouselabel}{%
+ \Roman{horohouse}%
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\horo@houses}
+% List of the pseudo-objects used for internal house labels. This is the
+% only tricky bit in this section of code: the internal house labels are
+% treated as objects with names like ``CuspIM.'' Then we have macros with
+% names including strings like ``CuspIMPos,'' and that can be treated as
+% either the Pos of CuspIM, or the MPos of CuspI. Exploiting that ambiguity
+% allows for simpler use of the existing variable-copying code to do some
+% useful things with label positions.
+% \begin{macrocode}
+\def\horo@houses{CuspIM,CuspIIM,CuspIIIM,CuspIVM,CuspVM,CuspVIM,%
+ CuspVIIM,CuspVIIIM,CuspIXM,CuspXM,CuspXIM,CuspXIIM}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\horo@findcuspmid}
+% Finds the midpoint of a house, given (as arguments) the names of the
+% house's cusp and of the next house's cusp. Looks at the DPos of those two
+% cusps, puts the result into the MPos for the house (see above about the
+% Pos/MPos trick).
+% \begin{macrocode}
+\def\horo@findcuspmid#1#2{%
+ \horo@midpoint{\csname horoCusp#1DPos\endcsname}%
+ {\csname horoCusp#2DPos\endcsname}%
+ \expandafter\edef\csname horoCusp#1MPos\endcsname{\TG@rem@pt\dimen@}%
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\horo@findcuspmids}
+% Repeat |\horo@findcuspmid| for all twelve houses. This is done explicitly
+% because of the wrap-around between XII and I, which makes it non-trivial
+% to write a nice looping structure to do it.
+% \begin{macrocode}
+\def\horo@findcuspmids{%
+ \horo@findcuspmid{I}{II}\horo@findcuspmid{II}{III}%
+ \horo@findcuspmid{III}{IV}\horo@findcuspmid{IV}{V}%
+ \horo@findcuspmid{V}{VI}\horo@findcuspmid{VI}{VII}%
+ \horo@findcuspmid{VII}{VIII}\horo@findcuspmid{VIII}{IX}%
+ \horo@findcuspmid{IX}{X}\horo@findcuspmid{X}{XI}%
+ \horo@findcuspmid{XI}{XII}\horo@findcuspmid{XII}{I}%
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\horo@pihl}
+% Prints an internal house label given the radius at which to print as \#1
+% and the name of the midpoint (like CuspIM) as \#2. Also steps the
+% |horohouse| counter, which is probably being used to decide how the labels
+% look.
+% \begin{macrocode}
+\def\horo@pihl#1#2{%
+ \begingroup
+ \horo@getobjdpos{#2}%
+ \horo@putpolar{#1}{\TG@rem@pt\dimen@}{\horohouselabel}%
+ \stepcounter{horohouse}%
+ \endgroup
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\horoputinthouselabels}
+% Typesets a complete ring of twelve house labels. The sole argument is the
+% radius at which to put them.
+% \begin{macrocode}
+\def\horoputinthouselabels#1{%
+ \setcounter{horohouse}{1}%
+ \horoforeach{\horo@houses}{\horo@pihl{#1}}%
+}
+% \end{macrocode}
+% \end{macro}
+%
+% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% \subsection{Object and Cusp Adjustment}
+%
+% These macros implement a full-featured system for adjusting the location
+% of objects on the chart to prevent them from interfering with each other.
+% The basic concept involves two variables on each object and cusp: Pos and
+% DPos. Pos represents the true position of the object in the sky, normally
+% its longitude. That is also in some sense the ``preferred'' position for
+% the object or cusp on the chart. However, if necessary to avoid
+% interference, the object or cusp can be shifted to a new location. DPos
+% is the position where it will actually be displayed.
+%
+% Adjustment is done by an iterative spring-tensioning algorithm.
+% Everything starts out with DPos equal to Pos. Then in successive loops,
+% we examine whether any rules (such as ``no two objects within so many
+% degrees of each other'') are broken, and if so we shift things in such a
+% way as to reduce the rule violations. Things that are too close to each
+% other are mutually repelled away from each other. Things that are not in
+% their preferred locations are attracted towards their preferred locations.
+%
+% There are limits on how much these forces can affect the location of an
+% object, to prevent the system from running away or oscillating. We hope
+% (without formal proof, but it seems to be true in practice and in
+% principle it could probably be proved formally) that in successive
+% iterations the adjustments will get smaller and smaller until the system
+% settles down into a reasonably good solution. There are a few tricks
+% implemented to encourage that. If two successive iterations give results
+% that are almost the same (to the point that the difference would not be
+% visible to the viewer) then we figure it has converged and stop the loop.
+% There is also a limit on the absolute number of iterations that will be
+% allowed, in case it does run away.
+%
+% Ideally we would have a solution that doesn't involve moving any cusps,
+% because moved cusps end up having unappealing ``jogs'' when rendered.
+% That may or may not be possible. The system will first attempt a solution
+% without moving any cusps, but if it converges with no cusp movement and
+% the result isn't good enough, then it will unlock the cusps and continue
+% iterating.
+%
+% \subsubsection{Configuration settings}
+% \begin{macro}{\horosignificantadj}
+% Number of degrees of adjustment that will be considered ``significant''
+% and cause another iteration. This should be small enough that it won't be
+% visible in the output.
+% \begin{macrocode}
+\def\horosignificantadj{0.1}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\horocuspadjusttrigger}
+% This represents the percentage of the normal ``minimum'' distance between
+% objects and objects, or objects and cusps, below which houses will be
+% considered too cramped. If the converged solution without moving cusps
+% results in any distances becoming shorter than this percentage, which will
+% normally imply all the distances in that house are similarly cramped, then
+% cusp adjustment will be triggered.
+% \begin{macrocode}
+\def\horocuspadjusttrigger{65}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\horoadjcycles}
+% Maximum number of cycles (total) to permit. If convergence is not
+% detected after this many, then it'll just go ahead with the result of
+% the last one. The default of 30 is generous.
+% \begin{macrocode}
+\def\horoadjcycles{30}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\horoposattobj}
+% Strength of attraction between an object and its desired Pos value. This
+% is given as a divisor, so the default of 20 means that the adjustment to
+% bring an object towards its Pos will be equal to $1/20$ of the amount by
+% which it's currently displaced from there.
+% \begin{macrocode}
+\def\horoposattobj{20}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\horoposattcusp}
+% Strength of attraction between a cusp and its desired Pos value. The
+% default of 7 means cusps are attracted to their Pos locations about three
+% times as much as objects; but note that that's if we allow cusps to move
+% at all, which only happens if we're forced into it.
+% \begin{macrocode}
+\def\horoposattcusp{7}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\hororepulsion}
+% Basic divisor for repulsion between all pairs of things that are repelled
+% from each other.
+% \begin{macrocode}
+\def\hororepulsion{3}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\horomaxrepulsion}
+% Interference distance (in degrees) at which maximum repulsion is achieved.
+% If two objects interfere by more than this amount, they will be repelled
+% only as much as if they interfered this much.\footnote{Don't try this at
+% home, kids. Sharp cutoffs like this one tend to introduce nonlinearity into
+% the underlying system of partial differential equations, which in turn
+% tends to create catastrophic instability. The famous Tacoma Narrows
+% Bridge disaster is blamed on a similar effect: due to nonlinearity in the
+% actual behaviour of the system, the linear analysis performed by the
+% designers of the bridge was woefully inaccurate. The decision to use
+% sharp cutoffs in the particular case of \textsf{horoscop}'s object
+% adjustment system is supported by very careful testing, the fact that the
+% discontinuities are only in the second and higher derivatives,
+% and the basic harmlessness of the situation: in the worst imaginable
+% failure mode you'd just get a visually unappealing astrological chart.
+% It should
+% not be taken as an endorsement of sharp-cutoff designs in general.} The
+% case this is intended to cover is the one where an object somehow happens
+% to be completely on the other side of the chart from where it should be,
+% and out of order with everything else. If repulsion were unlimited, then
+% everything would be kicked around to the point of creating many more
+% constraint violations and the whole thing would take many iterations to
+% resolve itself. Limiting repulsion per pair of objects gives more chance
+% to resolve such situations reasonably.
+% \begin{macrocode}
+\def\horomaxrepulsion{5.0}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\horooomindist}
+% Object/object minimum distance. If objects are more than this distance
+% apart (and in the correct sequence with each other) then they will not
+% repel. When they're closer, including being on the wrong side of each
+% other, then repulsion increases linearly with the amount of interference
+% up to the maximum set by the previous macro. Note that this one is for
+% \emph{object/object} relationships only.
+% \begin{macrocode}
+\def\horooomindist{6.0}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\horoocmindist}
+% Object/cusp minimum distance.
+% \begin{macrocode}
+\def\horoocmindist{4.0}
+% \end{macrocode}
+% \end{macro}
+%
+% \subsubsection{Internal variables}
+% These are used to keep track of where we are in the iteration and whether
+% we want to continue. Note dropping temporarily out of
+% |\ifhoro@wheels| because doing |\newif| in a conditional context causes
+% parsing problems.
+% \begin{macrocode}
+\fi
+\newif\ifhoro@djusted\relax
+\newif\ifhoro@djustcusps\relax
+\ifhoro@wheels
+\countdef\horo@i=1\relax
+% \end{macrocode}
+%
+% \subsubsection{Support macros for adjustment iterations}
+% These do low-level tasks needed within a single cycle of adjusting objects or
+% cusps.
+%
+% \begin{macro}{\horo@findpdiff}
+% Find the distance in Pos between two objects or cusps named by the
+% arguments. Note we can also get the distance in DPos by tacking a D onto
+% the end of an object name. Result goes into |\dimen@|.
+% \begin{macrocode}
+\def\horo@findpdiff#1#2{%
+ \dimen@=\csname horo#1Pos\endcsname\p@
+ \multiply\dimen@ by -1\relax
+ \advance\dimen@ by\csname horo#2Pos\endcsname\p@
+ \horo@fixdimen@diff
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\horo@pplycorrection}
+% Apply a correction (which should be in |\dimen@|) to the DPos of the
+% specified object or cusp.
+% \begin{macrocode}
+\def\horo@pplycorrection#1{%
+ \advance\dimen@ by \csname horo#1DPos\endcsname\p@
+ \horo@fixdimen@
+ \expandafter\edef\csname horo#1DPos\endcsname{\TG@rem@pt\dimen@}%
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\horo@djo@}
+% Adjust an object or cusp against another. Arguments are \#1 the minimum
+% distance, \#2 the thing to adjust, and \#3 the thing to adjust it against.
+% Implementation starts by finding, and saving, the distance in Pos between
+% the two objects or cusps, which gives us a sanity check on whether they
+% should affect each other at all, and tells us on which side of each other
+% they should appear.
+% \begin{macrocode}
+\def\horo@djo@#1#2#3{%
+ \horo@findpdiff{#3}{#2}%
+ \horo@dim@x=\dimen@
+% \end{macrocode}
+%
+% If the distance in Pos is more than 45\horodegrees\ in either direction,
+% then we skip the rest of this. That prevents some bad nonconverging cases
+% if objects happen to get into very bad locations on the wrong side of the
+% chart; they'll only interact with the objects that they want to be near.
+% \begin{macrocode}
+ \ifdim\horo@dim@x<45\p@\relax
+ \ifdim\horo@dim@x>-45\p@\relax
+% \end{macrocode}
+%
+% Now find the difference in \emph{display} positions as opposed to sky
+% positions, and flip its sign depending on the saved Pos difference. The
+% result in |\dimen@| is a number that tells us how far apart the objects
+% are in the direction they're supposed to be, so it is negative if they are
+% on the wrong side of each other.
+% \begin{macrocode}
+ \horo@findpdiff{#3D}{#2D}%
+ \ifdim\horo@dim@x<\z@\multiply\dimen@ by -1\relax\fi
+% \end{macrocode}
+%
+% Subtract out the minimum distance. The result is positive if the objects
+% are on the correct side and separated by more than the minimum
+% distance---in which case we set the adjustment to zero. Otherwise it's a
+% negative number saying how far they are interfering. We hard-limit it by
+% |\horomaxrepulsion| on the other side, and then divide by
+% |\hororepulsion| to get the adjustment for the current cycle.
+% \begin{macrocode}
+ \advance\dimen@ by -#1\p@
+ \ifdim\dimen@>\z@
+ \dimen@=\z@
+ \else
+ \ifdim\dimen@<-\horomaxrepulsion\p@\relax
+ \dimen@=-\horomaxrepulsion\p@%
+ \fi
+ \divide\dimen@ by\hororepulsion\relax
+ \fi
+% \end{macrocode}
+%
+% If we flipped the sign earlier, flip it back. Then |\dimen@| will contain
+% the actual adjustment to apply to |\horo|\meta{\#2}|\DPos|.
+% \begin{macrocode}
+ \ifdim\horo@dim@x>\z@\multiply\dimen@ by -1\relax\fi
+% \end{macrocode}
+%
+% Apply the correction and end.
+% \begin{macrocode}
+ \horo@pplycorrection{#2}%
+ \fi
+ \fi
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\horo@djoo}
+% Adjust an object against an object. This is just the small amount of
+% additional intelligence needed on top of |\horo@djo@| to handle objects
+% versus objects. We check the arguments to make sure we aren't adjusting
+% the same object against itself, because that is handled separately later.
+% Also, the value of |\horooomindist| is picked up and passed into
+% |\horo@djo@|.
+% \begin{macrocode}
+\def\horo@djoo#1#2{%
+ \edef\horo@tmpa{#1}\edef\horo@tmpb{#2}%
+ \ifx\horo@tmpa\horo@tmpb\else
+ \horo@djo@{\horooomindist}{#1}{#2}%
+ \fi
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\horo@djoo@same}
+% The special case of object or cusp against itself: we find the difference
+% between its Pos and DPos, divide that by \#1 (which should be the spring
+% divisor, different for objects or cusps), and apply the result as a
+% correction.
+% \begin{macrocode}
+\def\horo@djoo@same#1#2{%
+ \horo@findpdiff{#2D}{#2}%
+ \divide\dimen@ by#1\relax
+ \horo@pplycorrection{#2}%
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\horo@djcheckmovement}
+% Check for whether an object or cusp has moved significantly in the current
+% cycle. That is, if DPos differs from SPos (which was set to DPos before
+% the current cycle) by more than |\horosignificantadj|, then set
+% |\horo@djustedtrue|.
+% \begin{macrocode}
+\def\horo@djcheckmovement#1{%
+ \horo@findpdiff{#1D}{#1S}%
+ \ifdim\dimen@<0\p@\relax\multiply\dimen@ by -1\relax\fi
+ \ifdim\dimen@>\horosignificantadj\p@\relax\horo@djustedtrue\fi
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \subsubsection{Single adjustment cycles}
+% These each do one complete cycle of adjusting objects or objects and
+% cusps. There are two versions because including cusps or not makes a big
+% enough difference to warrant a separate implementation.
+%
+% \begin{macro}{\horo@djobjcycle}
+% One cycle of adjusting objects against each other and against cusps.
+% Start by showing the user the current cycle number as a progress
+% indicator, and setting the |\ifhoro@djusted| flag to false because we
+% haven't moved anything yet this cycle.
+% \begin{macrocode}
+\def\horo@djobjcycle{%
+ \message{\the\horo@i}%
+ \horo@djustedfalse
+% \end{macrocode}
+%
+% Copy all the current DPos values to a new variable called SPos (``saved
+% position'') so we'll be able to check whether anything has moved.
+% \begin{macrocode}
+ \horocopyvar{\horoobjects}{DPos}{SPos}%
+% \end{macrocode}
+%
+% Adjust objects against objects.
+% \begin{macrocode}
+ \horo@dblforeach{\horoobjects}{\horoobjects}{\horo@djoo}%
+% \end{macrocode}
+%
+% Adjust objects against cusps. This is one-sided: objects move to
+% accomodate cusps, but cusps do not move to accomodate objects. Since (we
+% assume) nothing is both an object and a cusp, we can call the low-level
+% |\horo@djo@| directly instead of needing a wrapper like |\horo@adjoo|.
+% \begin{macrocode}
+ \horo@dblforeach{\horoobjects}{\horocusps}{\horo@djo@{\horoocmindist}}%
+% \end{macrocode}
+%
+% Adjust each object against itself; that is, handle its attraction to Pos,
+% its ``correct'' location in the sky.
+% \begin{macrocode}
+ \horoforeach{\horoobjects}{\horo@djoo@same{\horoposattobj}}%
+% \end{macrocode}
+%
+% Check for movement. This turns on the |\ifhoro@djusted| flag if the net
+% result of the current cycle has been to move anything a ``significant''
+% amount from the position we saved in SPos.
+% \begin{macrocode}
+ \horoforeach{\horoobjects}{\horo@djcheckmovement}%
+% \end{macrocode}
+%
+% If the flag has remained false, then we have convergence, and can blow out
+% of the loop by setting the counter to its terminating value.
+% \begin{macrocode}
+ \ifhoro@djusted\else\horo@i=\horoadjcycles\relax\fi
+% \end{macrocode}
+%
+% Loop test. If we aren't on the last loop (which could have happened
+% either naturally or because of the exception in the last line), then
+% advance the loop counter and schedule another tail-recursive iteration.
+% \begin{macrocode}
+ \ifnum\horoadjcycles>\horo@i\relax
+ \advance\horo@i by1\relax
+ \expandafter\horo@djobjcycle
+ \fi
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\horo@djcuspcycle}
+% Adjust all objects and cusps against each other. As in
+% |\horo@djobjcycle|, we start by displaying the iteration number, setting
+% the |\ifhoro@djusted| flag false, and saving all DPos values to SPos.
+% \begin{macrocode}
+\def\horo@djcuspcycle{%
+ \message{\the\horo@i}%
+ \horo@djustedfalse
+ \horocopyvar{\horoobjects,\horocusps}{DPos}{SPos}%
+% \end{macrocode}
+%
+% Do the adjustments. We use |\horo@djo@| for adjusting cusps against
+% objects and objects against cusps because nothing appears on both lists.
+% For cusps against cusps and objects against objects we use |\horo@djoo|
+% because it has the added handling for not adjusting anything against
+% itself.
+% \begin{macrocode}
+ \horo@dblforeach{\horocusps}{\horoobjects}{\horo@djo@{\horoocmindist}}%
+ \horo@dblforeach{\horocusps}{\horocusps}{\horo@djoo}%
+ \horo@dblforeach{\horoobjects}{\horoobjects}{\horo@djoo}%
+ \horo@dblforeach{\horoobjects}{\horocusps}{\horo@djo@{\horoocmindist}}%
+% \end{macrocode}
+%
+% Adjust objects and cusps towards their desired positions (Pos values).
+% Note that the logic is the same but the divisor passed in is
+% |\horoposattobj| or |\horoposattcusp| depending on whether we are
+% considering objects or cusps.
+% \begin{macrocode}
+ \horoforeach{\horoobjects}{\horo@djoo@same{\horoposattobj}}%
+ \horoforeach{\horocusps}{\horo@djoo@same{\horoposattcusp}}%
+% \end{macrocode}
+%
+% Check for movement and handle the tail-recursive loop, just like in
+% |\horo@dj|-|objcycle| except that we examine cusps as well as objects.
+% \begin{macrocode}
+ \horoforeach{\horoobjects,\horocusps}{\horo@djcheckmovement}%
+ \ifhoro@djusted\else\horo@i=\horoadjcycles\relax\fi
+ \ifnum\horoadjcycles>\horo@i\relax
+ \advance\horo@i by1\relax
+ \expandafter\horo@djcuspcycle
+ \fi
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \subsubsection{Support macros for main loop}
+% \begin{macro}{\horo@djsavedpos}
+% Use |\horo@fterdef| to pass the DPos of
+% an object or cusp outside the prophylactic group.
+% \begin{macrocode}
+\def\horo@djsavedpos#1{%
+ \expandafter\horo@fterdef\csname horo#1DPos\endcsname
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\horo@djcheckcusps}
+% This checks a pair of objects or cusps for excessive stress, to determine,
+% after we have a converged solution with only objects moving, whether we
+% need to try moving cusps too. It makes sure not to compare something
+% against itself, finds the absolute value of the distance in degrees
+% between the two things, and checks whether that is less than
+% |\horocuspadjusttrigger| percentage of the minimum distance which was
+% passed in through \#1. If so, there's too much stress, and the
+% |\ifhoro@djustcusps| flag gets turned on.
+% \begin{macrocode}
+\def\horo@djcheckcusps#1#2#3{%
+ \edef\horo@tmpa{#2}\edef\horo@tmpb{#3}%
+ \ifx\horo@tmpa\horo@tmpb
+ \else
+ \horo@findpdiff{#2D}{#3D}%
+ \ifdim\dimen@<\z@\multiply\dimen@ by-1\relax\fi
+ \ifdim\dimen@<45\p@\relax
+ \multiply\dimen@ by 100\relax
+ \divide\dimen@ by \horocuspadjusttrigger\relax
+ \ifdim\dimen@<#1\p@\relax\horo@djustcuspstrue\fi
+ \fi
+ \fi
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \subsubsection{Main loop}
+% \begin{macro}{\horoadjust}
+% This is the user-callable adjustment macro that does the whole task of
+% adjusting objects and possibly cusps to make them look good. The whole
+% works is conditional on the |\ifhorocalculated| flag; if there's no good
+% data in the initial Pos and DPos values, then the adjustment may not
+% converge and will be wasted effort in any case. An earlier version
+% actually used multiple passes to do the external program calls (much like
+% the way \BibTeX\ works), so |\horocalculatedfalse| was guaranteed to occur
+% on the first pass; now, assuming |\write18| support in the interpreter,
+% it's less probable, but still needs to be caught because people
+% \emph{will} attempt to run without the required |\write18| support.
+% \begin{macrocode}
+\def\horoadjust{%
+ \ifhorocalculated
+% \end{macrocode}
+%
+% Support for internal house labels: if they're turned on, then find the
+% house midpoints and add them as objects to |\horoobjects|, saving its old
+% value to be later restored.
+% \begin{macrocode}
+ \ifhorointhouselabels
+ \horo@findcuspmids
+ \horocopyvar{\horocusps}{MPos}{MDPos}%
+ \let\horo@savedobjlist\horoobjects
+ \edef\horoobjects{\horoobjects,\horo@houses}%
+ \fi
+% \end{macrocode}
+%
+% Get ready to run the loop. Prints an opening parenthesis as a message to
+% the user, to give some progress indication, and sets the loop counter to 1.
+% A session of |\horoadjust|
+% will give a message something like ``( 1 2 3 4 5 6 7 C 1 2 3 )'' showing
+% each cycle through the loop, and the decision to adjust cusps. That way
+% (since this requires a fair bit of processing) the user won't be left
+% hanging, wondering what \TeX\ is doing.
+% \begin{macrocode}
+ \begingroup
+ \message{(}%
+ \horo@i=1\relax
+% \end{macrocode}
+%
+% Do the actual adjustment cycles for objects only.
+% \begin{macrocode}
+ \horo@djobjcycle
+% \end{macrocode}
+%
+% Now to decide whether we need to adjust cusps as well. Start by setting
+% the flag false. Then check objects against objects, and objects against
+% cusps, for excessive stress. If we find any, then cusp adjustment will be
+% triggered. This assumes that cusps against cusps will
+% never be an issue, but that's probably reasonable: cusps only fall right
+% on top of each other when the house system is misbehaving (e.g. Placidus
+% at high latitudes), and even then it will only be a visual problem if
+% there are objects trapped in the resulting tiny houses, because the cusps
+% themselves take up negligible angular space.
+% \begin{macrocode}
+ \horo@djustcuspsfalse
+ \horo@dblforeach{\horoobjects}{\horoobjects}%
+ {\horo@djcheckcusps{\horooomindist}}%
+ \horo@dblforeach{\horoobjects}{\horocusps}%
+ {\horo@djcheckcusps{\horoocmindist}}%
+% \end{macrocode}
+%
+% If we do want to adjust cusps: give the user a ``C'' to let them know,
+% then set the loop counter back to 1 and do the cusp adjustment cycle.
+% \begin{macrocode}
+ \ifhoro@djustcusps
+ \message{C}%
+ \horo@i=1\relax
+ \horo@djcuspcycle
+ \fi
+% \end{macrocode}
+%
+% At this point everything is converged, or as close as we were able to get.
+% Print a terminating parenthesis for the user message and pass all the DPos
+% values we calculated out of the prophylactic group.
+% \begin{macrocode}
+ \message{)}%
+ \horoforeach{\horocusps,\horoobjects}{\horo@djsavedpos}%
+ \endgroup
+% \end{macrocode}
+%
+% Finally, restore the |\horoobjects| list if we tampered with it earlier.
+% \begin{macrocode}
+ \ifhorointhouselabels\let\horoobjects\horo@savedobjlist\fi
+ \fi
+}
+% \end{macrocode}
+% \end{macro}
+%
+% At this point we end the |\ifhoro@wheels| conditional.
+% \begin{macrocode}
+\fi
+% \end{macrocode}
+%
+% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% \subsection{Support Macros for Ready-Made Wheels}
+%
+% These provide some low-level operations specific to the ready-made
+% wheel templates.
+%
+% At this point we open a conditional so that users can
+% turn off this support if they won't be using it.
+% \begin{macrocode}
+\ifhoro@templates
+% \end{macrocode}
+%
+% \subsubsection{Recognizing houses}
+% Some of the templates treat objects differently depending on in which house,
+% or which kind of house, the objects are located. These macros are all
+% designed to be called in the conditional part of an |\if|; they start out
+% by expanding |TT| (which the |\if| recognizes as unconditional true), then
+% open a new |\if| that does the actual conditioning.
+%
+% \begin{macro}{\horo@isclockwise}
+% Conditional, true if \#1 is clockwise of \#2. Implementation finds the
+% difference in Pos, inside a group to prevent pollution, and checks its sign.
+% \begin{macrocode}
+\def\horo@isclockwise#1#2{%
+ TT\fi
+ \begingroup
+ \horo@findpdiff{#1}{#2}%
+ \edef\horo@data{\the\dimen@}%
+ \horo@fterdef\horo@data
+ \endgroup
+ \ifdim\horo@data>\z@\relax
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\horo@anghouse}
+% Conditional, true if \#1 is in an angular house; that is, I, IV, VII, or
+% X. Works by comparing the object's position against the two cusps
+% bounding the house, for each of the four angular houses.
+% \begin{macrocode}
+\def\horo@anghouse#1{%
+ TT\fi
+ \begingroup
+ \def\horo@angh@{F}%
+ \if\horo@isclockwise{CuspI}{#1}\if\horo@isclockwise{#1}{CuspII}%
+ \def\horo@angh@{T}%
+ \fi\fi
+ \if\horo@isclockwise{CuspIV}{#1}\if\horo@isclockwise{#1}{CuspV}%
+ \def\horo@angh@{T}%
+ \fi\fi
+ \if\horo@isclockwise{CuspVII}{#1}\if\horo@isclockwise{#1}{CuspVIII}%
+ \def\horo@angh@{T}%
+ \fi\fi
+ \if\horo@isclockwise{CuspX}{#1}\if\horo@isclockwise{#1}{CuspXI}%
+ \def\horo@angh@{T}%
+ \fi\fi
+ \horo@fterdef\horo@angh@
+ \endgroup
+ \if\horo@angh@ T\relax
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\horo@succhouse}
+% Conditional, true if \#1 is in a succedent house; that is, II, V, VIII, or
+% XI. Implementation basically the same as |\horo@anghouse|.
+% \begin{macrocode}
+\def\horo@succhouse#1{%
+ TT\fi
+ \begingroup
+ \def\horo@succh@{F}%
+ \if\horo@isclockwise{CuspII}{#1}\if\horo@isclockwise{#1}{CuspIII}%
+ \def\horo@succh@{T}%
+ \fi\fi
+ \if\horo@isclockwise{CuspV}{#1}\if\horo@isclockwise{#1}{CuspVI}%
+ \def\horo@succh@{T}%
+ \fi\fi
+ \if\horo@isclockwise{CuspVIII}{#1}\if\horo@isclockwise{#1}{CuspIX}%
+ \def\horo@succh@{T}%
+ \fi\fi
+ \if\horo@isclockwise{CuspXI}{#1}\if\horo@isclockwise{#1}{CuspXII}%
+ \def\horo@succh@{T}%
+ \fi\fi
+ \horo@fterdef\horo@succh@
+ \endgroup
+ \if\horo@succh@ T\relax
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \subsubsection{Support for Montreal template}
+% \begin{macro}{\horo@montrealcurve}
+% Draw one of the special curves that typify the Montreal chart template.
+% This goes from the midpoint of a succedent house, based on DPos of the
+% starting and ending cusps, to the Pos of an angular house's cusp. There
+% are a total of eight of them to be drawn. The inner and outer radii are
+% fixed at 15 and 45. The implementation just calls |\horo@midpoint| to
+% compute the inner end, and then |\horo@putcurve| to draw the curve. This
+% is not one of the nice special cases for |\horo@putcurve| (constant $r$ or
+% constant $\theta$) but the result looks good in context anyway.
+% \begin{macrocode}
+\def\horo@montrealcurve#1#2#3{%
+ \horo@midpoint{\csname horoCusp#2DPos\endcsname}%
+ {\csname horoCusp#3DPos\endcsname}%
+ \horoputcurve{45}{\csname horoCusp#1Pos\endcsname}{15}{\TG@rem@pt\dimen@}%
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\horo@putmontrealobj}
+% Typeset an object label for the Montreal template. Objects in succedent
+% houses get labels on a larger radius than those in angular or cadent
+% houses.
+% \begin{macrocode}
+\def\horo@putmontrealobj#1{%
+ \if\horo@succhouse{#1}%
+ \horoputobjsymbol{42}{#1}%
+ \horoputobjdeglabel{34}{4}{#1}%
+ \horoputrxlabel{30}{#1}%
+ \else
+ \horoputobjsymbol{29}{#1}%
+ \horoputobjdeglabel{21}{4}{#1}%
+ \horoputrxlabel{17}{#1}%
+ \fi
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \subsubsection{Support for Quebec City template}
+% \begin{macro}{\horo@putqcobj}
+% Typeset an object label for the Quebec City template. Objects in
+% angular houses get labels on a smaller radius than those
+% in succedent or cadent houses.
+% \begin{macrocode}
+\def\horo@putqcobj#1{%
+ \if\horo@anghouse{#1}%
+ \horoputobjsymbol{28}{#1}%
+ \horoputobjdeglabel{20}{4}{#1}%
+ \horoputrxlabel{16}{#1}%
+ \else
+ \horoputobjsymbol{42}{#1}%
+ \horoputobjdeglabel{34}{4}{#1}%
+ \horoputrxlabel{30}{#1}%
+ \fi
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\horo@qcline}
+% Draw a straight line as part of the Quebec City template. This goes from
+% radius \#1 and angle \#2 to radius \#3 and angle \#4. The angles are
+% specified as cusp number concatenated with variable, as in
+% ``IIMPos,'' because that's the most convenient form for the calling
+% macro.
+% \begin{macrocode}
+\def\horo@qcline#1#2#3#4{%
+ \begingroup
+ \dimen@=\csname horoCusp#2\endcsname\p@\horo@chartrotate
+ \dimen1=\dimen@\relax
+ \dimen@=\csname horoCusp#4\endcsname\p@\horo@chartrotate
+ \horoputline{#1}{\TG@rem@pt\dimen1}%
+ {#3}{\TG@rem@pt\dimen@}%
+ \endgroup
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \subsubsection{Support for dial templates}
+% The dial templates all follow much the same pattern, so most of the parts
+% that are the same regardless of the number of dials are factored into
+% these two macros.
+%
+% \begin{macro}{\horo@dialstart}
+% Start drawing a dial template. The first argument is the radius of the
+% innermost dial, and the second is the harmonic--specially supported
+% because people who use dial charts seem to also often want harmonics on
+% them, and the degree scale should expand according to the harmonic.
+%
+% Implementation starts by calculating the harmonic positions of the
+% objects:
+% \begin{macrocode}
+\def\horo@dialstart#1#2{%
+ \horocalcharmonic{#2}
+% \end{macrocode}
+%
+% To print a nice degree scale we want ticks of differing sizes every one,
+% five, and ten degrees - but with the spacing adjusted according to the
+% harmonic. So we open a group and compute \#2 times one, five, and ten,
+% and save the results in the macros |\horo@dtone|, |\horo@dtfive|, and
+% |\horo@dtten| respectively.
+% \begin{macrocode}
+ \begingroup
+ \count0=#2\relax
+ \edef\horo@dtone{\the\count0}%
+ \multiply\count0 by 5\relax
+ \edef\horo@dtfive{\the\count0}%
+ \multiply\count0 by 2\relax
+ \edef\horo@dtten{\the\count0}%
+ \horo@fterdef\horo@dtone
+ \horo@fterdef\horo@dtfive
+ \horo@fterdef\horo@dtten
+ \endgroup
+% \end{macrocode}
+%
+% Force the right coordinate to 270\horodegrees, which means that the
+% 0\horodegrees\ mark will be at the top of the chart; that seems to be what
+% dial-chart users want.
+% \begin{macrocode}
+ \def\hororightcoord{270}%
+% \end{macrocode}
+%
+% If there's to be an aspect web (which may not be standard usage for dial
+% charts, but costs little to support) then typeset it. Otherwise, just
+% make a little cross in the centre of the dial so that the Cosmobiologists
+% know where to place their angle-finding instruments.
+% \changes{v0.92}{2013/05/15}{Replace \cs{drawline} with \cs{Line}}
+% \begin{macrocode}
+ \ifhoroaspectweb
+ \horoautoaspects{#1}%
+ \else
+ \Line(-1,0)(1,0)%
+ \Line(0,-1)(0,1)%
+ \fi
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\horo@dialwheel}
+% Draw one wheel of a potentially multi-wheel dial chart. The argument
+% \#1 is the |\horooomindist| setting (because the outer wheels may be less
+% cramped) and \#2 the diameter (not radius) of the basic circle. Then
+% \#3 through \#6 are the radii of various things: start of object-Pos
+% ticks, start of connector curves between object Pos and object DPos, end
+% of connector curves, and object symbols. The last argument, \#7, is the
+% length of object-Pos ticks.
+%
+% Implementation starts by setting object-object minimum distance according
+% to the argument, and object-cusp minimum distance to -90\horodegrees,
+% which effectively means that object-cusp interference won't be meaningful
+% to the adjustment algorithm. Dial charts don't have cusps. Then we draw
+% a circle for the basic dial, and set the right coordinate to
+% 270\horodegrees.
+% \begin{macrocode}
+\def\horo@dialwheel#1#2#3#4#5#6#7{%
+ \def\horooomindist{#1}\def\horoocmindist{-90.0}%
+ \put(0,0){\circle{#2}}%
+ \def\hororightcoord{270}%
+% \end{macrocode}
+%
+% The rest is only meaningful if there is calculated data. We plot a set of
+% radials to show objects' Pos values.
+% \begin{macrocode}
+ \ifhorocalculated
+ \horoputradials{\horoobjects}{#3}{#7}%
+% \end{macrocode}
+%
+% Do |\horoadjust| to come up with reasonable DPos values.
+% \begin{macrocode}
+ \horoadjust
+% \end{macrocode}
+%
+% Then plot the connecting curves and the object symbols and end (closing
+% off the conditional).
+% \begin{macrocode}
+ \horoforeach{\horoobjects}{\horoconncurve{#4}{#5}}%
+ \horoforeach{\horoobjects}{\horoputobjsymbol{#6}}%
+ \fi
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \subsubsection{Choosing text size}
+%
+% \begin{macro}{\horotextsize}
+% Adjustment to automatically-determined label text size in charts like
+% Vancouver, where the text size depends on the length of the smart-label
+% format string. Positive numbers make the text bigger, negative make it
+% smaller.
+% \begin{macrocode}
+\def\horotextsize{0}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\horochoosetextsize}
+% This makes some attempt to choose a reasonable text size based on
+% |\horolbllen|, so that labels with more chunks will be set in smaller
+% type. We start out by setting |\count@| to the configuration setting
+% |\horotextsize| (actually its negative) and adding the detected value of
+% |\horolbllen|.
+% \begin{macrocode}
+\def\horochoosetextsize{%
+ \count@=\horotextsize\relax
+ \multiply\count@ by-1\relax
+ \advance\count@ by\horolbllen\relax
+% \end{macrocode}
+%
+% Based on the result, we choose a text size from |\Large| down to |\tiny|.
+% \begin{macrocode}
+ \ifcase\the\count@\or\Large\or\large\or\normalsize\or\small\or
+ \scriptsize\or\scriptsize\or\tiny\fi
+}
+% \end{macrocode}
+% \end{macro}
+%
+% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% \subsection{Ready-Made Wheel Templates}
+%
+% These are all designed to be used inside a |horoscope| environment.
+%
+% \subsubsection{Basic wheel}
+% This is a standard wheel of the sort typically produced by a lot of
+% astrological software; it probably resembles Astrolog's more than anything
+% else. It has a sign key and angle scale around the outside, and space for
+% a centre label or aspect web in the middle. Objects have ticks showing
+% their true locations against the angle scale and aspect web, and curves
+% connecting those to their displayed locations within the houses. House
+% cusps can jog out of their true positions in order to accomodate adjusted
+% labels.
+%
+% \begin{macro}{\horowheelVancouver}
+% The optional argument is the label format string, which will be passed
+% into the smart labels code. Default value shows degrees and minutes of
+% object position.
+% \begin{macrocode}
+\newcommand{\horowheelVancouver}[1][ydzmr/ymzdr]{%
+% \end{macrocode}
+%
+% The graphic elements that make up the wheel are arranged at the following
+% radii:
+%
+% \begin{tabular}{ll}
+% r & element \\ \hline
+% 0--21 & aspect web or centre label \\
+% 21 & circle bounding aspect web from houses \\ \hline
+% 21--22 & radials showing true cusp positions \\
+% 22 & arcs connecting cusp radials to displaced cusps \\
+% 21--23 & radials showing true object positions \\
+% 23--24 & curves connecting object labels to radials \\
+% 22--42 & possibly-displaced cusps \\
+% 25 & approximate innermost object label chunk \\
+% 32 & centres of internal house labels \\
+% 38 & centres of outermost label chunks \\
+% 40--41 & curves connecting object labels to radials \\
+% 41--43 & radials showing true object positions \\
+% 42 & arcs connecting cusp radials to displaced cusps \\
+% 42--43 & radials showing true cusp positions \\
+% 43 & circle on inside of angle scale \\ \hline
+% 43--44 & 1\horodegrees\ ticks in angle scale \\
+% 43--45 & 5\horodegrees\ ticks in angle scale \\
+% 45 & circle bounding angle scale from sign key \\ \hline
+% 45--50 & 30\horodegrees\ ticks between signs \\
+% 47.5 & centres of sign symbols in key \\
+% 50 & circle around entire chart \\ \hline
+% \end{tabular}
+%
+% The object label chunk radii are set by |\horosetsmartradii| to spacing that
+% depends on the number of chunks, but the rough guideline is that they occupy
+% radii 25--38. In fact, scanning the label string and setting the radii are
+% the first things |\horowheelVancouver| does.
+% \begin{macrocode}
+ \horoscanlabels{#1}%
+ \horosetsmartradii{38}{4.666}{0.333}%
+% \end{macrocode}
+%
+% Set the default rounding mode, which is round to minutes keep degrees,
+% if |\hororoundautotrue| is active.
+% \begin{macrocode}
+ \ifhororoundauto\hororoundtominkeepdeg\fi
+% \end{macrocode}
+%
+% Draw the bounding circles (given by their diameter, which are twice their
+% radii).
+% \begin{macrocode}
+ \put(0,0){\circle{100}}%
+ \put(0,0){\circle{90}}%
+ \put(0,0){\circle{86}}%
+ \put(0,0){\circle{42}}%
+% \end{macrocode}
+%
+% Draw the angle scale with its 1\horodegrees\ and 5\horodegrees\ ticks, and
+% the sign key.
+% \begin{macrocode}
+ \horoputticks{45}{5}{30}%
+ \horoputticks{43}{1}{1}%
+ \horoputticks{43}{2}{5}%
+ \horoputsignkey{47.5}%
+% \end{macrocode}
+%
+% At this point DPos=Pos. Draw all the radials that go in true positions:
+% two each for objects and cusps, and two more bold ones for the cusps.
+% \changes{v0.92}{2013/05/15}{Replace \cs{allinethickness} with \cs{thicklines}\cs{linethickness}}
+% \begin{macrocode}
+ \ifhorocalculated
+ \horoputradials{\horoobjects}{41}{2}%
+ \horoputradials{\horoobjects}{21}{2}%
+ \ifhorodrawcusps
+ \horoputradials{\horocusps}{21}{1}%
+ \horoputradials{\horocusps}{42}{1}%
+ \fi
+ \ifhoroboldangles
+ \begingroup
+ \thicklines\linethickness{\horoanglecuspwidth}%
+ \horoputradials{\horoangularcusps}{21}{1}%
+ \ifhoroanglearrows
+ \horoputradials{\horoangularcusps}{42}{0.5}%
+ \else
+ \horoputradials{\horoangularcusps}{42}{1}%
+ \fi
+ \endgroup
+ \fi
+ \ifhoroanglearrows
+ \horoputarrows{\horoangularcusps}{43}{0.7}%
+ \fi
+ \fi
+% \end{macrocode}
+%
+% Compute the adjusted DPos values.
+% \begin{macrocode}
+ \horoadjust
+% \end{macrocode}
+%
+% Now draw the linework that goes in, or uses, adjusted positions. That
+% includes connecting curves for objects and cusps, and the main chunks
+% of the cusps themselves.
+% \changes{v0.92}{2013/05/15}{Replace \cs{allinethickness} with \cs{thicklines}\cs{linethickness}}
+% \begin{macrocode}
+ \ifhorocalculated
+ \horoforeach{\horoobjects}{\horoconncurve{41}{40}}%
+ \horoforeach{\horoobjects}{\horoconncurve{23}{24}}%
+ \ifhorodrawcusps
+ \horoforeach{\horocusps}{\horoconncurve{42}{42}}%
+ \horoforeach{\horocusps}{\horoconncurve{22}{22}}%
+ \horoputradials{\horocusps}{22}{20}%
+ \fi
+ \ifhoroboldangles
+ \thicklines\linethickness{\horoanglecuspwidth}%
+ \horoforeach{\horoangularcusps}{\horoconncurve{42}{42}}%
+ \horoforeach{\horoangularcusps}{\horoconncurve{22}{22}}%
+ \horoputradials{\horoangularcusps}{22}{20}%
+ \thinlines
+ \fi
+% \end{macrocode}
+%
+% Finally, the smart labels for objects, the aspect web, and
+% the internal house labels.
+% \begin{macrocode}
+ {\horochoosetextsize
+ \horoforeach{\horoobjects}{\horoputsmartlabel}}%
+ \ifhoroaspectweb\horoautoaspects{21}\fi
+ \ifhorointhouselabels\horoputinthouselabels{32}\fi
+ \fi
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \subsubsection{Harmonic multi-dial charts}
+% These templates are intended to be similar to some of those used in
+% Cosmobiology; they're also handy for comparing multiple charts. One, two,
+% three, or four concentric dials are supported. There's also built-in
+% support for calculating harmonics to create a 90\horodegrees\ wheel, or a
+% 45\horodegrees\ wheel, or whatever. The dials have ticks on them
+% indicating multiples of 1\horodegrees\ and 5\horodegrees (also
+% 10\horodegrees\ for the single and double dials), and the ticks
+% expand with the harmonic to make it easy to measure angles visually.
+% Labels for objects consist of just the object sysbols, to save radial
+% space (especially in the many-wheels case).
+%
+% All these take an optional first argument which is the harmonic number;
+% use 4 for a 90\horodegrees\ dial. Their implementations are
+% straightforward, based on the helper macros already defined.
+%
+% \begin{macro}{\horowheelIqaluit}
+% Single dial with the main circle at radius 42.
+% \begin{macrocode}
+\newcommand{\horowheelIqaluit}[1][1]{{%
+ \horo@dialstart{42}{#1}%
+ \horoputticks{42}{1}{\horo@dtone}%
+ \horoputticks{42}{2}{\horo@dtfive}%
+ \horoputticks{42}{3}{\horo@dtten}%
+ \horo@dialwheel{5.0}{84}{42}{45}{46}{47.5}{3}%
+}}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\horowheelIgloolik}
+% Double dial, radii 34 and 42. The optional first argument is the harmonic; second
+% and third should be two sets of object positions saved with
+% |\horosaveobjects|, corresponding to the positions to display in the inner
+% and outer dials respectively.
+% \begin{macrocode}
+\newcommand{\horowheelIgloolik}[3][1]{{%
+ \horo@dialstart{34}{#1}%
+ #3\horocalcharmonic{#1}%
+ \horoputticks{42}{1}{\horo@dtone}%
+ \horoputticks{42}{2}{\horo@dtfive}%
+ \horoputticks{42}{3}{\horo@dtten}%
+ \horo@dialwheel{5.0}{84}{42}{45}{46}{47.5}{3}%
+ #2\horocalcharmonic{#1}%
+ \horoputticks{34}{1}{\horo@dtone}%
+ \horoputticks{34}{2}{\horo@dtfive}%
+ \horoputticks{34}{3}{\horo@dtten}%
+ \horo@dialwheel{6.0}{68}{34}{37}{38}{39.5}{3}%
+}}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\horowheelResolute}
+% Triple dial, radii 29, 36, and 43. Optional first argument is harmonic;
+% remaining arguments are sets of saved object positions for the dials
+% ordered from inner to outer.
+% \begin{macrocode}
+\newcommand{\horowheelResolute}[4][1]{{%
+ \horo@dialstart{29}{#1}%
+ #4\horocalcharmonic{#1}%
+ \horoputticks{43}{1}{\horo@dtone}%
+ \horoputticks{43}{2}{\horo@dtfive}%
+ \horo@dialwheel{5.0}{86}{43}{45}{46}{47.5}{2}%
+ #3\horocalcharmonic{#1}%
+ \horoputticks{36}{1}{\horo@dtone}%
+ \horoputticks{36}{2}{\horo@dtfive}%
+ \horo@dialwheel{6.0}{72}{36}{38}{39}{40.5}{2}%
+ #2\horocalcharmonic{#1}%
+ \horoputticks{29}{1}{\horo@dtone}%
+ \horoputticks{29}{2}{\horo@dtfive}%
+ \horo@dialwheel{7.0}{58}{29}{31}{32}{33.5}{2}%
+}}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\horowheelRankin}
+% Quadruple dial, radii 22, 29, 36, and 43. Optional first argument is harmonic;
+% remaining arguments are sets of saved object positions for the dials
+% ordered from inner to outer.
+% \begin{macrocode}
+\newcommand{\horowheelRankin}[5][1]{{%
+ \horo@dialstart{22}{#1}%
+ #5\horocalcharmonic{#1}%
+ \horoputticks{43}{1}{\horo@dtone}%
+ \horoputticks{43}{2}{\horo@dtfive}%
+ \horo@dialwheel{5.0}{86}{43}{45}{46}{47.5}{2}%
+ #4\horocalcharmonic{#1}%
+ \horoputticks{36}{1}{\horo@dtone}%
+ \horoputticks{36}{2}{\horo@dtfive}%
+ \horo@dialwheel{6.0}{72}{36}{38}{39}{40.5}{2}%
+ #3\horocalcharmonic{#1}%
+ \horoputticks{29}{1}{\horo@dtone}%
+ \horoputticks{29}{2}{\horo@dtfive}%
+ \horo@dialwheel{7.0}{58}{29}{31}{32}{33.5}{2}%
+ #2\horocalcharmonic{#1}%
+ \horoputticks{22}{1}{\horo@dtone}%
+ \horoputticks{22}{2}{\horo@dtfive}%
+ \horo@dialwheel{10.0}{44}{22}{24}{25}{26.5}{2}%
+}}
+% \end{macrocode}
+% \end{macro}
+%
+% \subsubsection{Decorative wheel charts}
+% These were created partly to demonstrate some of the possibilities of
+% putting the pieces together to create interesting variations on the basic
+% chart, and partly in an effort to imitate historical chart styles. The
+% Montreal design was an attempt to create something similar to
+% old-fashioned square charts with triangular houses that I've seen; but at
+% the time I wasn't remembering clearly how those charts were laid out, and
+% I misunderstood which direction the triangles should point. The result is
+% not much like historical charts at all, but was retained because it's
+% visually interesting anyway, and demonstrates creative abuse of spline
+% curves. The Quebec City design is a second attempt
+% at imitating historical charts; although circular instead of square, it
+% uses the triangular-house layout, in a design that puts emphasis on the
+% angles and house cusps. Both are designed to emphasize the houses things
+% are in and de-emphasize the precise longitude relationships that the
+% Vancouver chart focuses on. That may or may not accomodate a different
+% style of interpretation.
+%
+% \begin{macro}{\horowheelMontreal}
+% This chart style puts some labels at small radii, so the minimum distances
+% for label adjustment have to be relatively large angles to prevent
+% interference.
+% \begin{macrocode}
+\newcommand{\horowheelMontreal}{{%
+ \def\horooomindist{10.0}\def\horoocmindist{6.0}%
+% \end{macrocode}
+%
+% Set the default rounding mode, which is round to degrees keep sign,
+% if |\hororoundautotrue| is active.
+% \begin{macrocode}
+ \ifhororoundauto\hororoundtodegkeepsign\fi
+% \end{macrocode}
+%
+% Draw circles at radii 15 and 45.
+% \begin{macrocode}
+ \put(0,0){\circle{90}}%
+ \put(0,0){\circle{30}}%
+% \end{macrocode}
+%
+% Put circular-reading labels at radius 47.5 for the four angles.
+% \begin{macrocode}
+ \ifhorocalculated
+ \ifhorodrawcusps
+ \horoforeach{\horoangularcusps}{\horoputcusplabel{47.5}{5}}%
+ \fi
+ \fi
+% \end{macrocode}
+%
+% Do adjustment to find non-conflicting locations for everything else.
+% \begin{macrocode}
+ \horoadjust
+% \end{macrocode}
+%
+% Now draw cusps separating succedent houses from the others.
+% Note that each call of |\horo@montrealcurve| draws a
+% curve from the \emph{middle} of one house, on the inner circle, to the
+% \emph{cusp} of another, on the outer circle. For instance,
+% |\horo@montrealcurve{I}{II}{III}| connects the first house cusp (that is
+% the boundary between the twelfth and first houses; the ascendant) on the
+% outside, to the midpoint of the second and third house cusps, which is the
+% middle of the second house, on the inside. In general it's midpoints of
+% succedent houses and cusps of angular houses, for a total of eight
+% connecting curves around the circle. Also note that we use adjusted
+% positions (DPos) on the inside and true positions (Pos) on the outside.
+% \begin{macrocode}
+ \ifhorocalculated
+ \ifhorodrawcusps
+ \horo@montrealcurve{I}{II}{III}%
+ \horo@montrealcurve{IV}{II}{III}%
+ \horo@montrealcurve{IV}{V}{VI}%
+ \horo@montrealcurve{VII}{V}{VI}%
+ \horo@montrealcurve{VII}{VIII}{IX}%
+ \horo@montrealcurve{X}{VIII}{IX}%
+ \horo@montrealcurve{X}{XI}{XII}%
+ \horo@montrealcurve{I}{XI}{XII}%
+% \end{macrocode}
+%
+% Draw cusps separating cadent from angular houses. The end result looks
+% like a sort of four-petalled flower, with two houses inside each petal and
+% one more in each of the spaces between.
+% \begin{macrocode}
+ \horoforeach{\horoangularcusps}{\horoconncurve{45}{15}}%
+ \fi
+% \end{macrocode}
+%
+% Finally, draw object labels. The code inside |\horo@putmontrealobj|
+% places the labels at different radii depending on the house type. In
+% general, the cusp adjustments mean that labels should not interfere
+% with the cusp curves, but it's imaginable in the case of heavily
+% overfilled houses.
+% \begin{macrocode}
+ \horoforeach{\horoobjects}{\horo@putmontrealobj}%
+ \fi
+}}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\horowheelQuebecCity}
+% As with the Montreal template, this one requires a fair bit of angular
+% space between object labels.
+% \begin{macrocode}
+\newcommand{\horowheelQuebecCity}{{%
+ \def\horooomindist{10.0}\def\horoocmindist{6.0}%
+% \end{macrocode}
+%
+% Set the default rounding mode, which is round to degrees keep sign,
+% if |\hororoundautotrue| is active.
+% \begin{macrocode}
+ \ifhororoundauto\hororoundtodegkeepsign\fi
+% \end{macrocode}
+%
+% Draw two circles for the outside; the cusp labels will go between them.
+% \begin{macrocode}
+ \put(0,0){\circle{100}}%
+ \put(0,0){\circle{90}}%
+% \end{macrocode}
+%
+% Do adjustment to find nice spacing for everything.
+% \begin{macrocode}
+ \horoadjust
+% \end{macrocode}
+%
+% Find the midpoints of all the houses and rotate the chart so that the
+% triangle forming the seventh house will point exactly to the right, which
+% means the triangle forming the first house should be very close to
+% pointing exactly to the left.
+% \begin{macrocode}
+ \ifhorocalculated
+ \horo@findcuspmids
+ \let\hororightcoord=\horoCuspVIIMPos
+% \end{macrocode}
+%
+% The layout here is that there's a (approximate) square in the middle, with
+% triangles pointing out of its four sides. Those form the angular houses.
+% The spaces between them are each bisected by a radial, to form the
+% succedent and cadent houses. We draw those radials first; they are
+% exactly on the cusps, and go from radius 20 (which circumscribes the
+% near-square) to 45 (the inside of the two rim circles).
+% \begin{macrocode}
+ \ifhorodrawcusps
+ \horoputradials{CuspIII,CuspVI,CuspIX,CuspXII}{20}{25}%
+% \end{macrocode}
+%
+% Now the eight lines connecting the square corners to the rim to form the
+% triangles; these go between angular house midpoints on the outside, and
+% cadent house cusps (which are the square corners) on the inside.
+% \begin{macrocode}
+ \horo@qcline{45}{IMPos}{20}{IIIDPos}%
+ \horo@qcline{45}{IVMPos}{20}{IIIDPos}%
+ \horo@qcline{45}{IVMPos}{20}{VIDPos}%
+ \horo@qcline{45}{VIIMPos}{20}{VIDPos}%
+ \horo@qcline{45}{VIIMPos}{20}{IXDPos}%
+ \horo@qcline{45}{XMPos}{20}{IXDPos}%
+ \horo@qcline{45}{XMPos}{20}{XIIDPos}%
+ \horo@qcline{45}{IMPos}{20}{XIIDPos}%
+% \end{macrocode}
+%
+% Draw the square itself by connecting cusps of cadent houses.
+% \begin{macrocode}
+ \horo@qcline{20}{IIIDPos}{20}{VIDPos}%
+ \horo@qcline{20}{VIDPos}{20}{IXDPos}%
+ \horo@qcline{20}{IXDPos}{20}{XIIDPos}%
+ \horo@qcline{20}{XIIDPos}{20}{IIIDPos}%
+ \fi
+% \end{macrocode}
+%
+% Now label the cusps. These labels go at midpoints of the houses, so we
+% need to copy the MPos of the houses to their DPos.
+% \begin{macrocode}
+ \horocopyvar{\horocusps}{MPos}{DPos}%
+ \ifhorodrawcusps
+ \horoforeach{\horocusps}{\horoputcusplabel{47.5}{5}}%
+ \fi
+% \end{macrocode}
+%
+% Finally, add the labels for the objects.
+% \begin{macrocode}
+ \horoforeach{\horoobjects}{\horo@putqcobj}%
+ \fi
+}}
+% \end{macrocode}
+% \end{macro}
+%
+% To end the file: we close the conditional, and set default values for the
+% calculation data so users can start typesetting charts immediately and not
+% worry about whether they are \emph{defining} or \emph{redefining} macros.
+% The default chart data is the author's.
+% \begin{macrocode}
+\fi
+\horocalcparms{1976}{8}{1}{17:22:19}{W123:20:38}{N48:25:53}
+% \end{macrocode}
+% \Finale
+\endinput