% \iffalse meta-comment
%
% This work is hereby released into the Public Domain.   To view a
% copy of the public domain dedication, visit
%    https://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
% https://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,unicode,wasysym,marvosym,starfont]{horoscop}[2020/07/31]
\usepackage{mathpazo}
\usepackage{metalogo}
\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{4317}
%
% \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{July 31, 2020}
%
% \thispagestyle{empty}
% \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 1.01, July 31, 2020}
% \vspace{2.5pc}
% \par}
%
% \clearpage
% \changes{v1.0}{2020/07/20}{Make page after title page page 2 for clearer
% numbering in PDF}
% \phantomsection
% \mybookmark{section}{Contents}
% \tableofcontents
%
% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 
%
% \section{Introduction}
%
% \changes{v1.0}{2020/07/20}{General updates to intro after seven years}
% 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 and Unicode
% astrological symbol code points.
% \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.
%
% I presented this package at TUG~2016, with a one-page summary in the
% conference proceedings:  Skala, M.  2016.  Astrological
% charts with \textsf{horoscop} and \textsf{starfont}.
% \emph{TUGboat,} 37(2):p.\ 182.  Proceedings of the 37th Annual Meeting of
% the TeX Users Group (TUG 2016), Toronto, Ontario, July 25-27, 2016.  A PDF
% of the summary is at \url{https://tug.org/TUGboat/tb37-2/tb116skala.pdf};
% a PDF of the slides from my talk is at
% \url{https://tug.org/tug2016/slides/skala.pdf}; and there is video of most
% of the presentation at
% \url{http://zeeba.tv/astrological-charts-with-horoscop-and-starfont/}.
%
% Version 1.0 represents a mature version of the package.
% The last release, version 0.92, was called a beta test, but it has
% been in use seven years now without needing any significant bug fixing or
% updates.  The most serious issue in 0.92 was in the documentation of
% how to enter manually-calculated object positions; the underlying macros
% for it worked well.
%
% Version 1.0 was primarily an update to the documentation to fix that
% issue; unfortunately, it still wasn't correct, so 1.01 is meant to fix it for
% real this time.  Version 1.0 made other documentation updates to recognize
% the fact that the package is mature and fully usable.  I also took the
% opportunity to add the Unicode-symbols feature, to reduce
% \textsf{horoscop}'s ties to classical \TeX\ and its font systems as users
% increasingly move toward Unicode engines and Unicode-based font selection;
% and I have updated such things as Web links and development contacts to
% reflect the inevitable changes in human institutitons over the years.
%
% \changes{v1.0}{2020/07/20}{In memoriam Axel}
% I encourage readers to think of Axel Harvey, a close friend of mine and
% a professional astrologer who contributed greatly to the testing of this
% software and its associated Web service.  He died in 2016, and is missed.
%
% \changes{v1.0}{2020/07/20}{New links for my own Web sites}
% There is an online chart service demonstrating \textsf{horoscop} at
% \href{https://edifyingfellowship.org/astro/}{\nolinkurl https://edifying}
% \href{https://edifyingfellowship.org/astro/}{\nolinkurl fellowship.org/astro/}.
% I also maintain a page pointing to \LaTeX\ astrology resources, at
% \url{https://ansuz.sooke.bc.ca/entry/107}.
%
% I no longer encourage the use of GitHub and it is unlikely that the
% existing GitHub repository for \textsf{horoscop} will be updated further.
% Bug reports and other correspondence related to \textsf{horoscop} should
% be directed to \href{mailto:mskala@ansuz.sooke.bc.ca}%
%   {\nolinkurl{mskala@ansuz.sooke.bc.ca}}.
%
% As of 2016, I am no longer pursuing a career in academic computer science. 
% I have started a business selling modules of my own design for
% Eurorack modular synthesizers, and kits for building them, through a Web
% storefront at \url{https://northcoastsynthesis.com/}.  If you are
% interested in electronic music, please consider buying my products; if
% not, please pass on the link to others.  My ability to spend time
% making free resources to share, such as the \textsf{horoscop} package,
% depends on the success of my business.
%
% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 
%
% \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, which should work in any
% \LaTeX\ environment; or the |unicode| option may
% \changes{v1.0}{2020/07/20}{\texttt{unicode} option}
% be used with \XeLaTeX\ or \LuaLaTeX\@.  With |unicode|, \textsf{horoscop}
% will use Unicode code points for the astrological symbols and leave it up to
% the Unicode-supporting \TeX\ engine to typeset them in an appropriate font.
%
% Sources for astrological font packages:
% \changes{v0.92}{2013/05/16}{Update links for font packages}
% \changes{v1.0}{2020/07/20}{Upgrade links to HTTPS}
% \begin{itemize}
% \item \textsf{marvosym}: \url{https://ctan.org/pkg/marvosym}
% \item \textsf{starfont}: \url{https://ctan.org/pkg/starfont}
% \item \textsf{wasysym}: \url{https://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.
%
% \changes{v1.0}{2020/07/20}{Upgrade links to HTTPS}
% Sources for external calculation programs:
% \begin{itemize}
% \item Astrolog:
%    \url{https://www.astrolog.org/astrolog.htm}
% \item Swiss Ephemeris:
%    \url{https://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|, |unicode|, |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.
%
% \changes{v1.0}{2020/07/20}{\texttt{unicode} option}
% The |unicode| option is normally only useful in \XeLaTeX\ and \LuaLaTeX;
% it causes \textsf{horoscop} to use non-ASCII Unicode characters for
% astrological symbols.  It is up to the \TeX\ engine, or the user, to
% select a font or combination of fonts in which these characters can be
% typeset.  Both \XeLaTeX\ and \LuaLaTeX\ offer relevant font-selection
% features, and if \textsf{horoscop} detects (using the \textsf{iftex}
% package) some other engine, it will fall back to a text indication of
% the desired code points, which looks like $\langle$U+263D$\rangle$.
%
% \DescribeMacro{\horotextsym}
% \DescribeMacro{\horounicode}
% \DescribeMacro{\horowasysym}
% \DescribeMacro{\horomarvosym}
% \DescribeMacro{\horostarfont}
% The macros |\horotextsym|, |\horounicode|, |\horowasysym|,
% |\horomarvosym|, and |\horostarfont| 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 that |\horotextsym| 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.
%
% {\setlength{\tabcolsep}{0.2em}
% \begin{tabular}{lccccc}
% macro & |textsym| & |unicode| & |wasysym| & |marvosym| & |starfont| \\
% |\AriesSymbol| & \horotextsym\AriesSymbol
%   & \horounicode\AriesSymbol
%   & \horowasysym\AriesSymbol
%   & \horomarvosym\AriesSymbol
%   & \horostarfont\AriesSymbol \\
% |\TaurusSymbol| & \horotextsym\TaurusSymbol
%   & \horounicode\TaurusSymbol
%   & \horowasysym\TaurusSymbol
%   & \horomarvosym\TaurusSymbol
%   & \horostarfont\TaurusSymbol \\
% |\GeminiSymbol| & \horotextsym\GeminiSymbol
%   & \horounicode\GeminiSymbol
%   & \horowasysym\GeminiSymbol
%   & \horomarvosym\GeminiSymbol
%   & \horostarfont\GeminiSymbol \\
% |\CancerSymbol| & \horotextsym\CancerSymbol
%   & \horounicode\CancerSymbol
%   & \horowasysym\CancerSymbol
%   & \horomarvosym\CancerSymbol
%   & \horostarfont\CancerSymbol \\
% |\LeoSymbol| & \horotextsym\LeoSymbol
%   & \horounicode\LeoSymbol
%   & \horowasysym\LeoSymbol
%   & \horomarvosym\LeoSymbol
%   & \horostarfont\LeoSymbol \\
% |\VirgoSymbol| & \horotextsym\VirgoSymbol
%   & \horounicode\VirgoSymbol
%   & \horowasysym\VirgoSymbol
%   & \horomarvosym\VirgoSymbol
%   & \horostarfont\VirgoSymbol \\
% |\LibraSymbol| & \horotextsym\LibraSymbol
%   & \horounicode\LibraSymbol
%   & \horowasysym\LibraSymbol
%   & \horomarvosym\LibraSymbol
%   & \horostarfont\LibraSymbol \\
% |\ScorpioSymbol| & \horotextsym\ScorpioSymbol
%   & \horounicode\ScorpioSymbol
%   & \horowasysym\ScorpioSymbol
%   & \horomarvosym\ScorpioSymbol
%   & \horostarfont\ScorpioSymbol \\
% |\SagittariusSymbol| & \horotextsym\SagittariusSymbol
%   & \horounicode\SagittariusSymbol
%   & \horowasysym\SagittariusSymbol
%   & \horomarvosym\SagittariusSymbol
%   & \horostarfont\SagittariusSymbol \\
% |\CapricornSymbol| & \horotextsym\CapricornSymbol
%   & \horounicode\CapricornSymbol
%   & \horowasysym\CapricornSymbol
%   & \horomarvosym\CapricornSymbol
%   & \horostarfont\CapricornSymbol \\
% |\AquariusSymbol| & \horotextsym\AquariusSymbol
%   & \horounicode\AquariusSymbol
%   & \horowasysym\AquariusSymbol
%   & \horomarvosym\AquariusSymbol
%   & \horostarfont\AquariusSymbol \\
% |\PiscesSymbol| & \horotextsym\PiscesSymbol
%   & \horounicode\PiscesSymbol
%   & \horowasysym\PiscesSymbol
%   & \horomarvosym\PiscesSymbol
%   & \horostarfont\PiscesSymbol
% \end{tabular}}
%
% \subsubsection{Luminaries and traditional planets}
%
% These are well-supported by the various fonts.
%
% {\setlength{\tabcolsep}{0.2em}
% \begin{tabular}{lccccc}
% macro & |textsym| & |unicode| & |wasysym| & |marvosym| & |starfont| \\
% |\SunSymbol| & \horotextsym\SunSymbol
%   & \horounicode\SunSymbol
%   & \horowasysym\SunSymbol
%   & \horomarvosym\SunSymbol
%   & \horostarfont\SunSymbol \\
% |\MoonSymbol| & \horotextsym\MoonSymbol
%   & \horounicode\MoonSymbol
%   & \horowasysym\MoonSymbol
%   & \horomarvosym\MoonSymbol
%   & \horostarfont\MoonSymbol \\
% |\MercurySymbol| & \horotextsym\MercurySymbol
%   & \horounicode\MercurySymbol
%   & \horowasysym\MercurySymbol
%   & \horomarvosym\MercurySymbol
%   & \horostarfont\MercurySymbol \\
% |\VenusSymbol| & \horotextsym\VenusSymbol
%   & \horounicode\VenusSymbol
%   & \horowasysym\VenusSymbol
%   & \horomarvosym\VenusSymbol
%   & \horostarfont\VenusSymbol \\
% |\MarsSymbol| & \horotextsym\MarsSymbol
%   & \horounicode\MarsSymbol
%   & \horowasysym\MarsSymbol
%   & \horomarvosym\MarsSymbol
%   & \horostarfont\MarsSymbol \\
% |\JupiterSymbol| & \horotextsym\JupiterSymbol
%   & \horounicode\JupiterSymbol
%   & \horowasysym\JupiterSymbol
%   & \horomarvosym\JupiterSymbol
%   & \horostarfont\JupiterSymbol \\
% |\SaturnSymbol| & \horotextsym\SaturnSymbol
%   & \horounicode\SaturnSymbol
%   & \horowasysym\SaturnSymbol
%   & \horomarvosym\SaturnSymbol
%   & \horostarfont\SaturnSymbol \\
% |\UranusSymbol| & \horotextsym\UranusSymbol
%   & \horounicode\UranusSymbol
%   & \horowasysym\UranusSymbol
%   & \horomarvosym\UranusSymbol
%   & \horostarfont\UranusSymbol \\
% |\NeptuneSymbol| & \horotextsym\NeptuneSymbol
%   & \horounicode\NeptuneSymbol
%   & \horowasysym\NeptuneSymbol
%   & \horomarvosym\NeptuneSymbol
%   & \horostarfont\NeptuneSymbol \\
% |\PlutoSymbol| & \horotextsym\PlutoSymbol
%   & \horounicode\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.  The |unicode| option also has code points for
% these.  Cusp symbols are listed in this table, but they
% generally do not appear in the default templates and will seldom be used
% in actual practice.
%
% {\setlength{\tabcolsep}{0.2em}
% \begin{tabular}{lccc}
% macro & |textsym| & |unicode| &|starfont| \\
% |\ChironSymbol| & \horotextsym\ChironSymbol
%   & \horounicode\ChironSymbol
%   & \horostarfont\ChironSymbol \\
% |\CeresSymbol| & \horotextsym\CeresSymbol
%   & \horounicode\CeresSymbol
%   & \horostarfont\CeresSymbol \\
% |\PallasSymbol| & \horotextsym\PallasSymbol
%   & \horounicode\PallasSymbol
%   & \horostarfont\PallasSymbol \\
% |\JunoSymbol| & \horotextsym\JunoSymbol
%   & \horounicode\JunoSymbol
%   & \horostarfont\JunoSymbol \\
% |\VestaSymbol| & \horotextsym\VestaSymbol
%   & \horounicode\VestaSymbol
%   & \horostarfont\VestaSymbol \\
% |\NorthNodeSymbol| & \horotextsym\NorthNodeSymbol
%   & \horounicode\NorthNodeSymbol
%   & \horostarfont\NorthNodeSymbol \\
% |\SouthNodeSymbol| & \horotextsym\SouthNodeSymbol
%   & \horounicode\SouthNodeSymbol
%   & \horostarfont\SouthNodeSymbol \\
% |\LilithSymbol| & \horotextsym\LilithSymbol
%   & \horounicode\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}.
%
% \noindent{\setlength{\tabcolsep}{0.1em}
% \begin{tabular}{lccccc}
% macro & |textsym| & |unicode| & |wasysym| & |starfont| & angle\\
% |\horoConjunctionSymbol| & \horotextsym\horoConjunctionSymbol
%   & \horounicode\horoConjunctionSymbol
%   & \horowasysym\horoConjunctionSymbol
%   & \horostarfont\horoConjunctionSymbol & $0\horodegrees\pm6\horodegrees$ \\
% |\horoOppositionSymbol| & \horotextsym\horoOppositionSymbol
%   & \horounicode\horoOppositionSymbol
%   & \horowasysym\horoOppositionSymbol
%   & \horostarfont\horoOppositionSymbol & $180\horodegrees\pm6\horodegrees$ \\
% |\horoTrineSymbol| & \horotextsym\horoTrineSymbol
%   & \horounicode\horoTrineSymbol
%   & \horowasysym\horoTrineSymbol
%   & \horostarfont\horoTrineSymbol & $120\horodegrees\pm5\horodegrees$ \\
% |\horoSquareSymbol| & \horotextsym\horoSquareSymbol
%   & \horounicode\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
%   & \horounicode\horoSextileSymbol
%   & \horowasysym\horoSextileSymbol
%   & \horostarfont\horoSextileSymbol & $60\horodegrees\pm4\horodegrees$ \\
% |\horoQuincunxSymbol| & \horotextsym\horoQuincunxSymbol
%   & \horounicode\horoQuincunxSymbol
%   & & \horostarfont\horoQuincunxSymbol & $150\horodegrees\pm3\horodegrees$ \\
% |\horoSemisextileSymbol| & \horotextsym\horoSemisextileSymbol
%   & \horounicode\horoSemisextileSymbol
%   & & \horostarfont\horoSemisextileSymbol & $30\horodegrees\pm3\horodegrees$ \\
% |\horoSemisquareSymbol| & \horotextsym\horoSemisquareSymbol
%   & \horounicode\horoSemisquareSymbol
%   & & \horostarfont\horoSemisquareSymbol & $45\horodegrees\pm2\horodegrees$ \\
% |\horoSesquiquadrateSymbol| & \horotextsym\horoSesquiquadrateSymbol
%   & \horounicode\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
% \changes{v1.0}{2020/07/20}{Upgrade links to HTTPS}
% \url{https://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.
%
% \changes{v1.0}{2020/07/20}{Correct macro names for manual position example}
% \changes{v1.01}{2020/07/31}{Correct macro names for manual position example, again}
% \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\horoCuspIPos{207.9120843}
% \def\horoCuspIIPos{236.5553269}
% \def\horoCuspIIIPos{267.6976404}
% \def\horoCuspIVPos{300.5365877}
% \def\horoCuspVPos{332.9973490}
% \def\horoCuspVIPos{2.5292853}
% \def\horoCuspVIIPos{27.9120843}
% \def\horoCuspVIIIPos{56.5553269}
% \def\horoCuspIXPos{87.6976404}
% \def\horoCuspXPos{120.5365877}
% \def\horoCuspXIPos{152.9973490}
% \def\horoCuspXIIPos{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}.
%
% \changes{v1.0}{2020/07/21}{Emphasize that template names do not determine
% geographic locations of charts}
% Please note that the standard templates are named after Canadian cities,
% but these names are only \emph{thematic names for the visual styles of the
% charts}\footnote{I was inspired to use this naming theme by Ruskey and
% Weston's work on Venn diagrams; see
% \url{https://www.combinatorics.org/files/Surveys/ds5/ds5v3-2005/VennEJC.html}.}
% and the names of the templates have no connection with the geographic
% locations the charts refer to.  You can plot a chart for any location in
% Vancouver style, and you can plot a chart that does happen to be for
% Vancouver (any of the multiple places in the world with that name) using any
% template.  The geographic location for the chart must be specified by
% latitude and longitude, independently of the template name.
%
% \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,
% \changes{v1.0}{2020/07/20}{Upgrade links to HTTPS}
% \url{https://sites.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 decrease 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}%
   [2020/07/31 v1.01 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.
%
% \changes{v1.0}{2020/07/20}{\texttt{unicode} option}
%    \begin{macrocode}
\newif\ifhoro@textsym\horo@textsymfalse
\newif\ifhoro@unicode\horo@unicodefalse
\newif\ifhoro@wasysym\horo@wasysymfalse
\newif\ifhoro@marvosym\horo@marvosymfalse
\newif\ifhoro@starfont\horo@starfontfalse
\DeclareOption{textsym}{\horo@textsymtrue}
\DeclareOption{unicode}{\horo@unicodetrue}
\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@unicode\else
    \ifhoro@wasysym\else
      \ifhoro@marvosym\else
        \horo@starfonttrue
      \fi
    \fi
  \fi
\fi
%    \end{macrocode}
%
% Because \textsf{iftex} defines conditionals, we must load it
% unconditionally.  Otherwise the parse of our style file (when it skims
% over not-taken conditional bodies) fails.
%
% \changes{v1.0}{2020/07/02}{Require \textsf{iftex}}
%    \begin{macrocode}
\RequirePackage{iftex}%
%    \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{Unicode astrological symbols}
%
% \changes{v1.0}{2020/07/20}{\texttt{unicode} option}
% As with |textsym|, the actual setting of the symbol macros is all inside a
% |unicode|-specific macro so that we can switch back to it easily
% after using other symbol sets.  The macro |\horounicode@| contains the
% actual code points in caret notation, which traditional \TeX\ engines
% cannot process; this macro is called by |\horounicode| conditionally
% on its detecting a Unicode-compatible engine.
%
% \begin{macro}{\horounicode@}
%    \begin{macrocode}
\ifhoro@unicode\newcommand{\horounicode@}{%
%    \end{macrocode}
%
% Signs of the Zodiac:
%    \begin{macrocode}
\gdef\AriesSymbol{^^^^2648}%
\gdef\TaurusSymbol{^^^^2649}%
\gdef\GeminiSymbol{^^^^264a}%
\gdef\CancerSymbol{^^^^264b}%
\gdef\LeoSymbol{^^^^264c}%
\gdef\VirgoSymbol{^^^^264d}%
\gdef\LibraSymbol{^^^^264e}%
\gdef\ScorpioSymbol{^^^^264f}%
\gdef\SagittariusSymbol{^^^^2650}%
\gdef\CapricornSymbol{^^^^2651}%
\gdef\AquariusSymbol{^^^^2652}%
\gdef\PiscesSymbol{^^^^2653}%
%    \end{macrocode}
%
% Traditional planets and luminaries:
%    \begin{macrocode}
\gdef\SunSymbol{^^^^2609}%
\gdef\MoonSymbol{^^^^263d}%
\gdef\MercurySymbol{^^^^263f}%
\gdef\VenusSymbol{^^^^2640}%
\gdef\MarsSymbol{^^^^2642}%
\gdef\JupiterSymbol{^^^^2643}%
\gdef\SaturnSymbol{^^^^2644}%
\gdef\UranusSymbol{^^^^2645}%
\gdef\NeptuneSymbol{^^^^2646}%
\gdef\PlutoSymbol{^^^^2647}%
%    \end{macrocode}
%
% Minor planets:
%    \begin{macrocode}
\gdef\ChironSymbol{^^^^26b7}%
\gdef\CeresSymbol{^^^^26b3}%
\gdef\PallasSymbol{^^^^26b4}%
\gdef\JunoSymbol{^^^^26b5}%
\gdef\VestaSymbol{^^^^26b6}%
%    \end{macrocode}
%
% Derived points:
%    \begin{macrocode}
\gdef\NorthNodeSymbol{^^^^260a}%
\gdef\SouthNodeSymbol{^^^^260b}%
\gdef\LilithSymbol{^^^^26b8}%
%    \end{macrocode}
%
% Direction:
%    \begin{macrocode}
\gdef\horoRetrogradeSymbol{^^^^211e}%
%    \end{macrocode}
%
% Aspects:
%    \begin{macrocode}
\gdef\horoConjunctionSymbol{^^^^260c}%
\gdef\horoOppositionSymbol{^^^^260d}%
\gdef\horoTrineSymbol{^^^^25b3}%
\gdef\horoSquareSymbol{^^^^25a1}%
\gdef\horoSextileSymbol{^^^^26b9}%
\gdef\horoQuincunxSymbol{^^^^26bb}%
\gdef\horoSemisextileSymbol{^^^^26ba}%
\gdef\horoSemisquareSymbol{^^^^2220}%
\gdef\horoSesquiquadrateSymbol{^^^^26bc}%
}
%    \end{macrocode}
% \end{macro}
%
% This helper macro typesets a notation that describes a code point in text:
%
% \begin{macro}{\horounicode@point}
%    \begin{macrocode}
\newcommand{\horounicode@point}[1]{\ensuremath{\langle\mbox{U+#1}\rangle}}
%    \end{macrocode}
% \end{macro}
%
% The |\horounicode| driver can either call |\horounicode@| to really
% use Unicode, or display text-based descriptions of the Unicode code points
% it wants, depending on the engine.  Factoring |\horounicode@| into a
% separate macro reduces repetition, since |\horounicode| wants to call it in
% two different places.
%
% \begin{macro}{\horounicode}
% \changes{v1.0}{2020/07/20}{New macro}
%    \begin{macrocode}
\newcommand{\horounicode}{%
%    \end{macrocode}
%
% Call |\horounicode@| if it is safe to do so:
%    \begin{macrocode}
\ifxetex\horounicode@\else
\ifluatex\horounicode@\else
%    \end{macrocode}
%
% Now define all the code points, as above, but in text notation.
%
% Signs of the Zodiac:
%    \begin{macrocode}
\gdef\AriesSymbol{\horounicode@point{2648}}%
\gdef\TaurusSymbol{\horounicode@point{2649}}%
\gdef\GeminiSymbol{\horounicode@point{264A}}%
\gdef\CancerSymbol{\horounicode@point{264B}}%
\gdef\LeoSymbol{\horounicode@point{264C}}%
\gdef\VirgoSymbol{\horounicode@point{264D}}%
\gdef\LibraSymbol{\horounicode@point{264E}}%
\gdef\ScorpioSymbol{\horounicode@point{264F}}%
\gdef\SagittariusSymbol{\horounicode@point{2650}}%
\gdef\CapricornSymbol{\horounicode@point{2651}}%
\gdef\AquariusSymbol{\horounicode@point{2652}}%
\gdef\PiscesSymbol{\horounicode@point{2653}}%
%    \end{macrocode}
%
% Traditional planets and luminaries:
%    \begin{macrocode}
\gdef\SunSymbol{\horounicode@point{2609}}%
\gdef\MoonSymbol{\horounicode@point{263D}}%
\gdef\MercurySymbol{\horounicode@point{263F}}%
\gdef\VenusSymbol{\horounicode@point{2640}}%
\gdef\MarsSymbol{\horounicode@point{2642}}%
\gdef\JupiterSymbol{\horounicode@point{2643}}%
\gdef\SaturnSymbol{\horounicode@point{2644}}%
\gdef\UranusSymbol{\horounicode@point{2645}}%
\gdef\NeptuneSymbol{\horounicode@point{2646}}%
\gdef\PlutoSymbol{\horounicode@point{2647}}%
%    \end{macrocode}
%
% Minor planets:
%    \begin{macrocode}
\gdef\ChironSymbol{\horounicode@point{26B7}}%
\gdef\CeresSymbol{\horounicode@point{26B3}}%
\gdef\PallasSymbol{\horounicode@point{26B4}}%
\gdef\JunoSymbol{\horounicode@point{26B5}}%
\gdef\VestaSymbol{\horounicode@point{26B6}}%
%    \end{macrocode}
%
% Derived points:
%    \begin{macrocode}
\gdef\NorthNodeSymbol{\horounicode@point{260A}}%
\gdef\SouthNodeSymbol{\horounicode@point{260B}}%
\gdef\LilithSymbol{\horounicode@point{26B8}}%
%    \end{macrocode}
%
% Direction:
%    \begin{macrocode}
\gdef\horoRetrogradeSymbol{\horounicode@point{211E}}%
%    \end{macrocode}
%
% Aspects:
%    \begin{macrocode}
\gdef\horoConjunctionSymbol{\horounicode@point{260C}}%
\gdef\horoOppositionSymbol{\horounicode@point{260D}}%
\gdef\horoTrineSymbol{\horounicode@point{25B3}}%
\gdef\horoSquareSymbol{\horounicode@point{25A1}}%
\gdef\horoSextileSymbol{\horounicode@point{26B9}}%
\gdef\horoQuincunxSymbol{\horounicode@point{26BB}}%
\gdef\horoSemisextileSymbol{\horounicode@point{26BA}}%
\gdef\horoSemisquareSymbol{\horounicode@point{2220}}%
\gdef\horoSesquiquadrateSymbol{\horounicode@point{26BC}}%
\fi\fi
}
%    \end{macrocode}
% \end{macro}
%
% Now invoke |\horounicode| to make these symbols default at the start of
% the document, except for the few (house cusps, and quintiles) that
% don't exist in Unicode.
%    \begin{macrocode}
\horounicode
\fi
%    \end{macrocode}
%
% \subsubsection{Symbols from \textsf{wasysym}}
%
% \begin{macro}{\horowasysym}
% These, too, are inside a macro specific to the package so that we can
% switch among multiple symbol sets when more than one is loaded.
%    \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
