summaryrefslogtreecommitdiff
path: root/macros/latex/contrib/horoscop/horoscop.dtx
blob: cc7827e623a0ebc767096155a3c9ba43425f2ae3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315
2316
2317
2318
2319
2320
2321
2322
2323
2324
2325
2326
2327
2328
2329
2330
2331
2332
2333
2334
2335
2336
2337
2338
2339
2340
2341
2342
2343
2344
2345
2346
2347
2348
2349
2350
2351
2352
2353
2354
2355
2356
2357
2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369
2370
2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394
2395
2396
2397
2398
2399
2400
2401
2402
2403
2404
2405
2406
2407
2408
2409
2410
2411
2412
2413
2414
2415
2416
2417
2418
2419
2420
2421
2422
2423
2424
2425
2426
2427
2428
2429
2430
2431
2432
2433
2434
2435
2436
2437
2438
2439
2440
2441
2442
2443
2444
2445
2446
2447
2448
2449
2450
2451
2452
2453
2454
2455
2456
2457
2458
2459
2460
2461
2462
2463
2464
2465
2466
2467
2468
2469
2470
2471
2472
2473
2474
2475
2476
2477
2478
2479
2480
2481
2482
2483
2484
2485
2486
2487
2488
2489
2490
2491
2492
2493
2494
2495
2496
2497
2498
2499
2500
2501
2502
2503
2504
2505
2506
2507
2508
2509
2510
2511
2512
2513
2514
2515
2516
2517
2518
2519
2520
2521
2522
2523
2524
2525
2526
2527
2528
2529
2530
2531
2532
2533
2534
2535
2536
2537
2538
2539
2540
2541
2542
2543
2544
2545
2546
2547
2548
2549
2550
2551
2552
2553
2554
2555
2556
2557
2558
2559
2560
2561
2562
2563
2564
2565
2566
2567
2568
2569
2570
2571
2572
2573
2574
2575
2576
2577
2578
2579
2580
2581
2582
2583
2584
2585
2586
2587
2588
2589
2590
2591
2592
2593
2594
2595
2596
2597
2598
2599
2600
2601
2602
2603
2604
2605
2606
2607
2608
2609
2610
2611
2612
2613
2614
2615
2616
2617
2618
2619
2620
2621
2622
2623
2624
2625
2626
2627
2628
2629
2630
2631
2632
2633
2634
2635
2636
2637
2638
2639
2640
2641
2642
2643
2644
2645
2646
2647
2648
2649
2650
2651
2652
2653
2654
2655
2656
2657
2658
2659
2660
2661
2662
2663
2664
2665
2666
2667
2668
2669
2670
2671
2672
2673
2674
2675
2676
2677
2678
2679
2680
2681
2682
2683
2684
2685
2686
2687
2688
2689
2690
2691
2692
2693
2694
2695
2696
2697
2698
2699
2700
2701
2702
2703
2704
2705
2706
2707
2708
2709
2710
2711
2712
2713
2714
2715
2716
2717
2718
2719
2720
2721
2722
2723
2724
2725
2726
2727
2728
2729
2730
2731
2732
2733
2734
2735
2736
2737
2738
2739
2740
2741
2742
2743
2744
2745
2746
2747
2748
2749
2750
2751
2752
2753
2754
2755
2756
2757
2758
2759
2760
2761
2762
2763
2764
2765
2766
2767
2768
2769
2770
2771
2772
2773
2774
2775
2776
2777
2778
2779
2780
2781
2782
2783
2784
2785
2786
2787
2788
2789
2790
2791
2792
2793
2794
2795
2796
2797
2798
2799
2800
2801
2802
2803
2804
2805
2806
2807
2808
2809
2810
2811
2812
2813
2814
2815
2816
2817
2818
2819
2820
2821
2822
2823
2824
2825
2826
2827
2828
2829
2830
2831
2832
2833
2834
2835
2836
2837
2838
2839
2840
2841
2842
2843
2844
2845
2846
2847
2848
2849
2850
2851
2852
2853
2854
2855
2856
2857
2858
2859
2860
2861
2862
2863
2864
2865
2866
2867
2868
2869
2870
2871
2872
2873
2874
2875
2876
2877
2878
2879
2880
2881
2882
2883
2884
2885
2886
2887
2888
2889
2890
2891
2892
2893
2894
2895
2896
2897
2898
2899
2900
2901
2902
2903
2904
2905
2906
2907
2908
2909
2910
2911
2912
2913
2914
2915
2916
2917
2918
2919
2920
2921
2922
2923
2924
2925
2926
2927
2928
2929
2930
2931
2932
2933
2934
2935
2936
2937
2938
2939
2940
2941
2942
2943
2944
2945
2946
2947
2948
2949
2950
2951
2952
2953
2954
2955
2956
2957
2958
2959
2960
2961
2962
2963
2964
2965
2966
2967
2968
2969
2970
2971
2972
2973
2974
2975
2976
2977
2978
2979
2980
2981
2982
2983
2984
2985
2986
2987
2988
2989
2990
2991
2992
2993
2994
2995
2996
2997
2998
2999
3000
3001
3002
3003
3004
3005
3006
3007
3008
3009
3010
3011
3012
3013
3014
3015
3016
3017
3018
3019
3020
3021
3022
3023
3024
3025
3026
3027
3028
3029
3030
3031
3032
3033
3034
3035
3036
3037
3038
3039
3040
3041
3042
3043
3044
3045
3046
3047
3048
3049
3050
3051
3052
3053
3054
3055
3056
3057
3058
3059
3060
3061
3062
3063
3064
3065
3066
3067
3068
3069
3070
3071
3072
3073
3074
3075
3076
3077
3078
3079
3080
3081
3082
3083
3084
3085
3086
3087
3088
3089
3090
3091
3092
3093
3094
3095
3096
3097
3098
3099
3100
3101
3102
3103
3104
3105
3106
3107
3108
3109
3110
3111
3112
3113
3114
3115
3116
3117
3118
3119
3120
3121
3122
3123
3124
3125
3126
3127
3128
3129
3130
3131
3132
3133
3134
3135
3136
3137
3138
3139
3140
3141
3142
3143
3144
3145
3146
3147
3148
3149
3150
3151
3152
3153
3154
3155
3156
3157
3158
3159
3160
3161
3162
3163
3164
3165
3166
3167
3168
3169
3170
3171
3172
3173
3174
3175
3176
3177
3178
3179
3180
3181
3182
3183
3184
3185
3186
3187
3188
3189
3190
3191
3192
3193
3194
3195
3196
3197
3198
3199
3200
3201
3202
3203
3204
3205
3206
3207
3208
3209
3210
3211
3212
3213
3214
3215
3216
3217
3218
3219
3220
3221
3222
3223
3224
3225
3226
3227
3228
3229
3230
3231
3232
3233
3234
3235
3236
3237
3238
3239
3240
3241
3242
3243
3244
3245
3246
3247
3248
3249
3250
3251
3252
3253
3254
3255
3256
3257
3258
3259
3260
3261
3262
3263
3264
3265
3266
3267
3268
3269
3270
3271
3272
3273
3274
3275
3276
3277
3278
3279
3280
3281
3282
3283
3284
3285
3286
3287
3288
3289
3290
3291
3292
3293
3294
3295
3296
3297
3298
3299
3300
3301
3302
3303
3304
3305
3306
3307
3308
3309
3310
3311
3312
3313
3314
3315
3316
3317
3318
3319
3320
3321
3322
3323
3324
3325
3326
3327
3328
3329
3330
3331
3332
3333
3334
3335
3336
3337
3338
3339
3340
3341
3342
3343
3344
3345
3346
3347
3348
3349
3350
3351
3352
3353
3354
3355
3356
3357
3358
3359
3360
3361
3362
3363
3364
3365
3366
3367
3368
3369
3370
3371
3372
3373
3374
3375
3376
3377
3378
3379
3380
3381
3382
3383
3384
3385
3386
3387
3388
3389
3390
3391
3392
3393
3394
3395
3396
3397
3398
3399
3400
3401
3402
3403
3404
3405
3406
3407
3408
3409
3410
3411
3412
3413
3414
3415
3416
3417
3418
3419
3420
3421
3422
3423
3424
3425
3426
3427
3428
3429
3430
3431
3432
3433
3434
3435
3436
3437
3438
3439
3440
3441
3442
3443
3444
3445
3446
3447
3448
3449
3450
3451
3452
3453
3454
3455
3456
3457
3458
3459
3460
3461
3462
3463
3464
3465
3466
3467
3468
3469
3470
3471
3472
3473
3474
3475
3476
3477
3478
3479
3480
3481
3482
3483
3484
3485
3486
3487
3488
3489
3490
3491
3492
3493
3494
3495
3496
3497
3498
3499
3500
3501
3502
3503
3504
3505
3506
3507
3508
3509
3510
3511
3512
3513
3514
3515
3516
3517
3518
3519
3520
3521
3522
3523
3524
3525
3526
3527
3528
3529
3530
3531
3532
3533
3534
3535
3536
3537
3538
3539
3540
3541
3542
3543
3544
3545
3546
3547
3548
3549
3550
3551
3552
3553
3554
3555
3556
3557
3558
3559
3560
3561
3562
3563
3564
3565
3566
3567
3568
3569
3570
3571
3572
3573
3574
3575
3576
3577
3578
3579
3580
3581
3582
3583
3584
3585
3586
3587
3588
3589
3590
3591
3592
3593
3594
3595
3596
3597
3598
3599
3600
3601
3602
3603
3604
3605
3606
3607
3608
3609
3610
3611
3612
3613
3614
3615
3616
3617
3618
3619
3620
3621
3622
3623
3624
3625
3626
3627
3628
3629
3630
3631
3632
3633
3634
3635
3636
3637
3638
3639
3640
3641
3642
3643
3644
3645
3646
3647
3648
3649
3650
3651
3652
3653
3654
3655
3656
3657
3658
3659
3660
3661
3662
3663
3664
3665
3666
3667
3668
3669
3670
3671
3672
3673
3674
3675
3676
3677
3678
3679
3680
3681
3682
3683
3684
3685
3686
3687
3688
3689
3690
3691
3692
3693
3694
3695
3696
3697
3698
3699
3700
3701
3702
3703
3704
3705
3706
3707
3708
3709
3710
3711
3712
3713
3714
3715
3716
3717
3718
3719
3720
3721
3722
3723
3724
3725
3726
3727
3728
3729
3730
3731
3732
3733
3734
3735
3736
3737
3738
3739
3740
3741
3742
3743
3744
3745
3746
3747
3748
3749
3750
3751
3752
3753
3754
3755
3756
3757
3758
3759
3760
3761
3762
3763
3764
3765
3766
3767
3768
3769
3770
3771
3772
3773
3774
3775
3776
3777
3778
3779
3780
3781
3782
3783
3784
3785
3786
3787
3788
3789
3790
3791
3792
3793
3794
3795
3796
3797
3798
3799
3800
3801
3802
3803
3804
3805
3806
3807
3808
3809
3810
3811
3812
3813
3814
3815
3816
3817
3818
3819
3820
3821
3822
3823
3824
3825
3826
3827
3828
3829
3830
3831
3832
3833
3834
3835
3836
3837
3838
3839
3840
3841
3842
3843
3844
3845
3846
3847
3848
3849
3850
3851
3852
3853
3854
3855
3856
3857
3858
3859
3860
3861
3862
3863
3864
3865
3866
3867
3868
3869
3870
3871
3872
3873
3874
3875
3876
3877
3878
3879
3880
3881
3882
3883
3884
3885
3886
3887
3888
3889
3890
3891
3892
3893
3894
3895
3896
3897
3898
3899
3900
3901
3902
3903
3904
3905
3906
3907
3908
3909
3910
3911
3912
3913
3914
3915
3916
3917
3918
3919
3920
3921
3922
3923
3924
3925
3926
3927
3928
3929
3930
3931
3932
3933
3934
3935
3936
3937
3938
3939
3940
3941
3942
3943
3944
3945
3946
3947
3948
3949
3950
3951
3952
3953
3954
3955
3956
3957
3958
3959
3960
3961
3962
3963
3964
3965
3966
3967
3968
3969
3970
3971
3972
3973
3974
3975
3976
3977
3978
3979
3980
3981
3982
3983
3984
3985
3986
3987
3988
3989
3990
3991
3992
3993
3994
3995
3996
3997
3998
3999
4000
4001
4002
4003
4004
4005
4006
4007
4008
4009
4010
4011
4012
4013
4014
4015
4016
4017
4018
4019
4020
4021
4022
4023
4024
4025
4026
4027
4028
4029
4030
4031
4032
4033
4034
4035
4036
4037
4038
4039
4040
4041
4042
4043
4044
4045
4046
4047
4048
4049
4050
4051
4052
4053
4054
4055
4056
4057
4058
4059
4060
4061
4062
4063
4064
4065
4066
4067
4068
4069
4070
4071
4072
4073
4074
4075
4076
4077
4078
4079
4080
4081
4082
4083
4084
4085
4086
4087
4088
4089
4090
4091
4092
4093
4094
4095
4096
4097
4098
4099
4100
4101
4102
4103
4104
4105
4106
4107
4108
4109
4110
4111
4112
4113
4114
4115
4116
4117
4118
4119
4120
4121
4122
4123
4124
4125
4126
4127
4128
4129
4130
4131
4132
4133
4134
4135
4136
4137
4138
4139
4140
4141
4142
4143
4144
4145
4146
4147
4148
4149
4150
4151
4152
4153
4154
4155
4156
4157
4158
4159
4160
4161
4162
4163
4164
4165
4166
4167
4168
4169
4170
4171
4172
4173
4174
4175
4176
4177
4178
4179
4180
4181
4182
4183
4184
4185
4186
4187
4188
4189
4190
4191
4192
4193
4194
4195
4196
4197
4198
4199
4200
4201
4202
4203
4204
4205
4206
4207
4208
4209
4210
4211
4212
4213
4214
4215
4216
4217
4218
4219
4220
4221
4222
4223
4224
4225
4226
4227
4228
4229
4230
4231
4232
4233
4234
4235
4236
4237
4238
4239
4240
4241
4242
4243
4244
4245
4246
4247
4248
4249
4250
4251
4252
4253
4254
4255
4256
4257
4258
4259
4260
4261
4262
4263
4264
4265
4266
4267
4268
4269
4270
4271
4272
4273
4274
4275
4276
4277
4278
4279
4280
4281
4282
4283
4284
4285
4286
4287
4288
4289
4290
4291
4292
4293
4294
4295
4296
4297
4298
4299
4300
4301
4302
4303
4304
4305
4306
4307
4308
4309
4310
4311
4312
4313
4314
4315
4316
4317
4318
4319
4320
4321
4322
4323
4324
4325
4326
4327
4328
4329
4330
4331
4332
4333
4334
4335
4336
4337
4338
4339
4340
4341
4342
4343
4344
4345
4346
4347
4348
4349
4350
4351
4352
4353
4354
4355
4356
4357
4358
4359
4360
4361
4362
4363
4364
4365
4366
4367
4368
4369
4370
4371
4372
4373
4374
4375
4376
4377
4378
4379
4380
4381
4382
4383
4384
4385
4386
4387
4388
4389
4390
4391
4392
4393
4394
4395
4396
4397
4398
4399
4400
4401
4402
4403
4404
4405
4406
4407
4408
4409
4410
4411
4412
4413
4414
4415
4416
4417
4418
4419
4420
4421
4422
4423
4424
4425
4426
4427
4428
4429
4430
4431
4432
4433
4434
4435
4436
4437
4438
4439
4440
4441
4442
4443
4444
4445
4446
4447
4448
4449
4450
4451
4452
4453
4454
4455
4456
4457
4458
4459
4460
4461
4462
4463
4464
4465
4466
4467
4468
4469
4470
4471
4472
4473
4474
4475
4476
4477
4478
4479
4480
4481
4482
4483
4484
4485
4486
4487
4488
4489
4490
4491
4492
4493
4494
4495
4496
4497
4498
4499
4500
4501
4502
4503
4504
4505
4506
4507
4508
4509
4510
4511
4512
4513
4514
4515
4516
4517
4518
4519
4520
4521
4522
4523
4524
4525
4526
4527
4528
4529
4530
4531
4532
4533
4534
4535
4536
4537
4538
4539
4540
4541
4542
4543
4544
4545
4546
4547
4548
4549
4550
4551
4552
4553
4554
4555
4556
4557
4558
4559
4560
4561
4562
4563
4564
4565
4566
4567
4568
4569
4570
4571
4572
4573
4574
4575
4576
4577
4578
4579
4580
4581
4582
4583
4584
4585
4586
4587
4588
4589
4590
4591
4592
4593
4594
4595
4596
4597
4598
4599
4600
4601
4602
4603
4604
4605
4606
4607
4608
4609
4610
4611
4612
4613
4614
4615
4616
4617
4618
4619
4620
4621
4622
4623
4624
4625
4626
4627
4628
4629
4630
4631
4632
4633
4634
4635
4636
4637
4638
4639
4640
4641
4642
4643
4644
4645
4646
4647
4648
4649
4650
4651
4652
4653
4654
4655
4656
4657
4658
4659
4660
4661
4662
4663
4664
4665
4666
4667
4668
4669
4670
4671
4672
4673
4674
4675
4676
4677
4678
4679
4680
4681
4682
4683
4684
4685
4686
4687
4688
4689
4690
4691
4692
4693
4694
4695
4696
4697
4698
4699
4700
4701
4702
4703
4704
4705
4706
4707
4708
4709
4710
4711
4712
4713
4714
4715
4716
4717
4718
4719
4720
4721
4722
4723
4724
4725
4726
4727
4728
4729
4730
4731
4732
4733
4734
4735
4736
4737
4738
4739
4740
4741
4742
4743
4744
4745
4746
4747
4748
4749
4750
4751
4752
4753
4754
4755
4756
4757
4758
4759
4760
4761
4762
4763
4764
4765
4766
4767
4768
4769
4770
4771
4772
4773
4774
4775
4776
4777
4778
4779
4780
4781
4782
4783
4784
4785
4786
4787
4788
4789
4790
4791
4792
4793
4794
4795
4796
4797
4798
4799
4800
4801
4802
4803
4804
4805
4806
4807
4808
4809
4810
4811
4812
4813
4814
4815
4816
4817
4818
4819
4820
4821
4822
4823
4824
4825
4826
4827
4828
4829
4830
4831
4832
4833
4834
4835
4836
4837
4838
4839
4840
4841
4842
4843
4844
4845
4846
4847
4848
4849
4850
4851
4852
4853
4854
4855
4856
4857
4858
4859
4860
4861
4862
4863
4864
4865
4866
4867
4868
4869
4870
4871
4872
4873
4874
4875
4876
4877
4878
4879
4880
4881
4882
4883
4884
4885
4886
4887
4888
4889
4890
4891
4892
4893
4894
4895
4896
4897
4898
4899
4900
4901
4902
4903
4904
4905
4906
4907
4908
4909
4910
4911
4912
4913
4914
4915
4916
4917
4918
4919
4920
4921
4922
4923
4924
4925
4926
4927
4928
4929
4930
4931
4932
4933
4934
4935
4936
4937
4938
4939
4940
4941
4942
4943
4944
4945
4946
4947
4948
4949
4950
4951
4952
4953
4954
4955
4956
4957
4958
4959
4960
4961
4962
4963
4964
4965
4966
4967
4968
4969
4970
4971
4972
4973
4974
4975
4976
4977
4978
4979
4980
4981
4982
4983
4984
4985
4986
4987
4988
4989
4990
4991
4992
4993
4994
4995
4996
4997
4998
4999
5000
5001
5002
5003
5004
5005
5006
5007
5008
5009
5010
5011
5012
5013
5014
5015
5016
5017
5018
5019
5020
5021
5022
5023
5024
5025
5026
5027
5028
5029
5030
5031
5032
5033
5034
5035
5036
5037
5038
5039
5040
5041
5042
5043
5044
5045
5046
5047
5048
5049
5050
5051
5052
5053
5054
5055
5056
5057
5058
5059
5060
5061
5062
5063
5064
5065
5066
5067
5068
5069
5070
5071
5072
5073
5074
5075
5076
5077
5078
5079
5080
5081
5082
5083
5084
5085
5086
5087
5088
5089
5090
5091
5092
5093
5094
5095
5096
5097
5098
5099
5100
5101
5102
5103
5104
5105
5106
5107
5108
5109
5110
5111
5112
5113
5114
5115
5116
5117
5118
5119
5120
5121
5122
5123
5124
5125
5126
5127
5128
5129
5130
5131
5132
5133
5134
5135
5136
5137
5138
5139
5140
5141
5142
5143
5144
5145
5146
5147
5148
5149
5150
5151
5152
5153
5154
5155
5156
5157
5158
5159
5160
5161
5162
5163
5164
5165
5166
5167
5168
5169
5170
5171
5172
5173
5174
5175
5176
5177
5178
5179
5180
5181
5182
5183
5184
5185
5186
5187
5188
5189
5190
5191
5192
5193
5194
5195
5196
5197
5198
5199
5200
5201
5202
5203
5204
5205
5206
5207
5208
5209
5210
5211
5212
5213
5214
5215
5216
5217
5218
5219
5220
5221
5222
5223
5224
5225
5226
5227
5228
5229
5230
5231
5232
5233
5234
5235
5236
5237
5238
5239
5240
5241
5242
5243
5244
5245
5246
5247
5248
5249
5250
5251
5252
5253
5254
5255
5256
5257
5258
5259
5260
5261
5262
5263
5264
5265
5266
5267
5268
5269
5270
5271
5272
5273
5274
5275
5276
5277
5278
5279
5280
5281
5282
5283
5284
5285
5286
5287
5288
5289
5290
5291
5292
5293
5294
5295
5296
5297
5298
5299
5300
5301
5302
5303
5304
5305
5306
5307
5308
5309
5310
5311
5312
5313
5314
5315
5316
5317
5318
5319
5320
5321
5322
5323
5324
5325
5326
5327
5328
5329
5330
5331
5332
5333
5334
5335
5336
5337
5338
5339
5340
5341
5342
5343
5344
5345
5346
5347
5348
5349
5350
5351
5352
5353
5354
5355
5356
5357
5358
5359
5360
5361
5362
5363
5364
5365
5366
5367
5368
5369
5370
5371
5372
5373
5374
5375
5376
5377
5378
5379
5380
5381
5382
5383
5384
5385
5386
5387
5388
5389
5390
5391
5392
5393
5394
5395
5396
5397
5398
5399
5400
5401
5402
5403
5404
5405
5406
5407
5408
5409
5410
5411
5412
5413
5414
5415
5416
5417
5418
5419
5420
5421
5422
5423
5424
5425
5426
5427
5428
5429
5430
5431
5432
5433
5434
5435
5436
5437
5438
5439
5440
5441
5442
5443
5444
5445
5446
5447
5448
5449
5450
5451
5452
5453
5454
5455
5456
5457
5458
5459
5460
5461
5462
5463
5464
5465
5466
5467
5468
5469
5470
5471
5472
5473
5474
5475
5476
5477
5478
5479
5480
5481
5482
5483
5484
5485
5486
5487
5488
5489
5490
5491
5492
5493
5494
5495
5496
5497
5498
5499
5500
5501
5502
5503
5504
5505
5506
5507
5508
5509
5510
5511
5512
5513
5514
5515
5516
5517
5518
5519
5520
5521
5522
5523
5524
5525
5526
5527
5528
5529
5530
5531
5532
5533
5534
5535
5536
5537
5538
5539
5540
5541
5542
5543
5544
5545
5546
5547
5548
5549
5550
5551
5552
5553
5554
5555
5556
5557
5558
5559
5560
5561
5562
5563
5564
5565
5566
5567
5568
5569
5570
5571
5572
5573
5574
5575
5576
5577
5578
5579
5580
5581
5582
5583
5584
5585
5586
5587
5588
5589
5590
5591
5592
5593
5594
5595
5596
5597
5598
5599
5600
5601
5602
5603
5604
5605
5606
5607
5608
5609
5610
5611
5612
5613
5614
5615
5616
5617
5618
5619
5620
5621
5622
5623
5624
5625
5626
5627
5628
5629
5630
5631
5632
5633
5634
5635
5636
5637
5638
5639
5640
5641
5642
5643
5644
5645
5646
5647
5648
5649
5650
5651
5652
5653
5654
5655
5656
5657
5658
5659
5660
5661
5662
5663
5664
5665
5666
5667
5668
5669
5670
5671
5672
5673
5674
5675
5676
5677
5678
5679
5680
5681
5682
5683
5684
5685
5686
5687
5688
5689
5690
5691
5692
5693
5694
5695
5696
5697
5698
5699
5700
5701
5702
5703
5704
5705
5706
5707
5708
5709
5710
5711
5712
5713
5714
5715
5716
5717
5718
5719
5720
5721
5722
5723
5724
5725
5726
5727
5728
5729
5730
5731
5732
5733
5734
5735
5736
5737
5738
5739
5740
5741
5742
5743
5744
5745
5746
5747
5748
5749
5750
5751
5752
5753
5754
5755
5756
5757
5758
5759
5760
5761
5762
5763
5764
5765
5766
5767
5768
5769
5770
5771
5772
5773
5774
5775
5776
5777
5778
5779
5780
5781
5782
5783
5784
5785
5786
5787
5788
5789
5790
5791
5792
5793
5794
5795
5796
5797
5798
5799
5800
5801
5802
5803
5804
5805
5806
5807
5808
5809
5810
5811
5812
5813
5814
5815
5816
5817
5818
5819
5820
5821
5822
5823
5824
5825
5826
5827
5828
5829
5830
5831
5832
5833
5834
5835
5836
5837
5838
5839
5840
5841
5842
5843
5844
5845
5846
5847
5848
5849
5850
5851
5852
5853
5854
5855
5856
5857
5858
5859
5860
5861
5862
5863
5864
5865
5866
5867
5868
5869
5870
5871
5872
5873
5874
5875
5876
5877
5878
5879
5880
5881
5882
5883
5884
5885
5886
5887
5888
5889
5890
5891
5892
5893
5894
5895
5896
5897
5898
5899
5900
5901
5902
5903
5904
5905
5906
5907
5908
5909
5910
5911
5912
5913
5914
5915
5916
5917
5918
5919
5920
5921
5922
5923
5924
5925
5926
5927
5928
5929
5930
5931
5932
5933
5934
5935
5936
5937
5938
5939
5940
5941
5942
5943
5944
5945
5946
5947
5948
5949
5950
5951
5952
5953
5954
5955
5956
5957
5958
5959
5960
5961
5962
5963
5964
5965
5966
5967
5968
5969
5970
5971
5972
5973
5974
5975
5976
5977
5978
5979
5980
5981
5982
5983
5984
5985
5986
5987
5988
5989
5990
5991
5992
5993
5994
5995
5996
5997
5998
5999
6000
6001
6002
6003
6004
6005
6006
6007
6008
6009
6010
6011
6012
6013
6014
6015
6016
6017
6018
6019
6020
6021
6022
6023
6024
6025
6026
6027
6028
6029
6030
6031
6032
6033
6034
6035
6036
6037
6038
6039
6040
6041
6042
6043
6044
6045
6046
6047
6048
6049
6050
6051
6052
6053
6054
6055
6056
6057
6058
6059
6060
6061
6062
6063
6064
6065
6066
6067
6068
6069
6070
6071
6072
6073
6074
6075
6076
6077
6078
6079
6080
6081
6082
6083
6084
6085
6086
6087
6088
6089
6090
6091
6092
6093
6094
6095
6096
6097
6098
6099
6100
6101
6102
6103
6104
6105
6106
6107
6108
6109
6110
6111
6112
6113
6114
6115
6116
6117
6118
6119
6120
6121
6122
6123
6124
6125
6126
6127
6128
6129
6130
6131
6132
6133
6134
6135
6136
6137
6138
6139
6140
6141
6142
6143
6144
6145
6146
6147
6148
6149
6150
6151
6152
6153
6154
6155
6156
6157
6158
6159
6160
6161
6162
6163
6164
6165
6166
6167
6168
6169
6170
6171
6172
6173
6174
6175
6176
6177
6178
6179
6180
6181
6182
6183
6184
6185
6186
6187
6188
6189
6190
6191
6192
6193
6194
6195
6196
6197
6198
6199
6200
6201
6202
6203
6204
6205
6206
6207
6208
6209
6210
6211
6212
6213
6214
6215
6216
6217
6218
6219
6220
6221
6222
6223
6224
6225
6226
6227
6228
6229
6230
6231
6232
6233
6234
6235
6236
6237
6238
6239
6240
6241
6242
6243
6244
6245
6246
6247
6248
6249
6250
6251
6252
6253
6254
6255
6256
6257
6258
6259
6260
6261
6262
6263
6264
6265
6266
6267
6268
6269
6270
6271
6272
6273
6274
6275
6276
6277
6278
6279
6280
6281
6282
6283
6284
6285
6286
6287
6288
6289
6290
6291
6292
6293
6294
6295
6296
6297
6298
6299
6300
6301
6302
6303
6304
6305
6306
6307
6308
6309
6310
6311
6312
6313
6314
6315
6316
6317
6318
6319
6320
6321
6322
6323
6324
6325
6326
6327
6328
6329
6330
6331
6332
6333
6334
6335
6336
6337
6338
6339
6340
6341
6342
6343
6344
6345
6346
6347
6348
6349
6350
6351
6352
6353
6354
6355
6356
6357
6358
6359
6360
6361
6362
6363
6364
6365
6366
6367
6368
6369
6370
6371
6372
6373
6374
6375
6376
6377
6378
6379
6380
6381
6382
6383
6384
6385
6386
6387
6388
6389
6390
6391
6392
6393
6394
6395
6396
6397
6398
6399
6400
6401
6402
6403
6404
6405
6406
6407
6408
6409
6410
6411
6412
6413
6414
6415
6416
6417
6418
6419
6420
6421
6422
6423
6424
6425
6426
6427
6428
6429
6430
6431
6432
6433
6434
6435
6436
6437
6438
6439
6440
6441
6442
6443
6444
6445
6446
6447
6448
6449
6450
6451
6452
6453
6454
6455
6456
6457
6458
6459
6460
6461
6462
6463
6464
6465
6466
6467
6468
6469
6470
6471
6472
6473
6474
6475
6476
6477
6478
6479
6480
6481
6482
6483
6484
6485
6486
6487
6488
6489
6490
6491
6492
6493
6494
6495
6496
6497
6498
6499
6500
6501
6502
6503
6504
6505
6506
6507
6508
6509
6510
6511
6512
6513
6514
6515
6516
6517
6518
6519
6520
6521
6522
6523
6524
6525
6526
6527
6528
6529
6530
6531
6532
6533
6534
6535
6536
6537
6538
6539
6540
6541
6542
6543
6544
6545
6546
6547
6548
6549
6550
6551
6552
6553
6554
6555
6556
6557
6558
6559
6560
6561
6562
6563
6564
6565
6566
6567
6568
6569
6570
6571
6572
6573
6574
6575
6576
6577
6578
6579
6580
6581
6582
6583
6584
6585
6586
6587
6588
6589
6590
6591
6592
6593
6594
6595
6596
6597
6598
6599
6600
6601
6602
6603
6604
6605
6606
6607
6608
6609
6610
6611
6612
6613
6614
6615
6616
6617
6618
6619
6620
6621
6622
6623
6624
6625
6626
6627
6628
6629
6630
6631
6632
6633
6634
6635
6636
6637
6638
6639
6640
6641
6642
6643
6644
6645
6646
6647
6648
6649
6650
6651
6652
6653
6654
6655
6656
6657
6658
6659
6660
6661
6662
6663
6664
6665
6666
6667
6668
6669
6670
6671
6672
6673
6674
6675
6676
6677
6678
6679
6680
6681
6682
6683
6684
6685
6686
6687
6688
6689
6690
6691
6692
6693
6694
6695
6696
6697
6698
6699
6700
6701
6702
6703
6704
6705
6706
6707
6708
6709
6710
6711
6712
6713
6714
6715
6716
6717
6718
6719
6720
6721
6722
6723
6724
6725
6726
6727
6728
6729
6730
6731
6732
6733
6734
6735
6736
6737
6738
6739
6740
6741
6742
6743
6744
6745
6746
6747
6748
6749
6750
6751
6752
6753
6754
6755
6756
6757
6758
6759
6760
6761
6762
6763
6764
6765
6766
6767
6768
6769
6770
6771
6772
6773
6774
6775
6776
6777
6778
6779
6780
6781
6782
6783
6784
6785
6786
6787
6788
6789
6790
6791
6792
6793
6794
6795
6796
6797
6798
6799
6800
6801
6802
6803
6804
6805
6806
6807
6808
6809
6810
6811
6812
6813
6814
6815
6816
6817
6818
6819
6820
6821
6822
6823
6824
6825
6826
6827
6828
6829
6830
6831
6832
6833
6834
6835
6836
6837
6838
6839
6840
6841
6842
6843
6844
6845
6846
6847
6848
6849
6850
6851
6852
6853
6854
6855
6856
6857
6858
6859
6860
6861
6862
6863
6864
6865
6866
6867
6868
6869
6870
6871
6872
6873
6874
6875
6876
6877
6878
6879
6880
6881
6882
6883
6884
6885
6886
6887
6888
6889
6890
6891
6892
6893
6894
6895
6896
6897
6898
6899
6900
6901
6902
6903
6904
6905
6906
6907
6908
6909
6910
6911
6912
6913
6914
6915
6916
6917
6918
6919
6920
6921
6922
6923
6924
6925
6926
6927
6928
6929
6930
6931
6932
6933
6934
6935
6936
6937
6938
6939
6940
6941
6942
6943
6944
6945
6946
6947
6948
6949
6950
6951
6952
6953
6954
6955
6956
6957
6958
6959
6960
6961
6962
6963
6964
6965
6966
6967
6968
6969
6970
6971
6972
6973
6974
6975
6976
6977
6978
6979
6980
6981
6982
6983
6984
6985
6986
6987
6988
6989
6990
6991
6992
6993
6994
6995
6996
6997
6998
6999
7000
7001
7002
7003
7004
7005
7006
7007
7008
7009
7010
7011
7012
7013
7014
7015
7016
7017
7018
7019
7020
7021
7022
7023
7024
7025
7026
7027
7028
7029
7030
7031
7032
7033
7034
7035
7036
7037
7038
7039
7040
7041
7042
7043
7044
7045
7046
7047
7048
7049
7050
7051
7052
7053
7054
7055
7056
7057
7058
7059
7060
7061
7062
7063
7064
7065
7066
7067
7068
7069
7070
7071
7072
7073
7074
7075
7076
7077
7078
7079
7080
7081
7082
7083
7084
7085
7086
7087
7088
7089
7090
7091
7092
7093
7094
7095
7096
7097
7098
7099
7100
7101
7102
7103
7104
7105
7106
7107
7108
7109
7110
7111
7112
7113
7114
7115
7116
7117
7118
7119
7120
7121
7122
7123
7124
7125
7126
7127
7128
7129
7130
7131
7132
7133
7134
7135
7136
7137
7138
7139
7140
7141
7142
7143
7144
7145
7146
7147
7148
7149
7150
7151
7152
7153
7154
7155
7156
7157
7158
7159
7160
7161
7162
7163
7164
7165
7166
7167
7168
7169
7170
7171
7172
7173
7174
7175
7176
7177
7178
7179
7180
7181
7182
7183
7184
7185
7186
7187
7188
7189
7190
7191
7192
7193
7194
7195
7196
7197
7198
7199
7200
7201
7202
7203
7204
7205
7206
7207
7208
7209
7210
7211
7212
7213
7214
7215
7216
7217
7218
7219
7220
7221
7222
7223
7224
7225
7226
7227
7228
7229
7230
7231
7232
7233
7234
7235
7236
7237
7238
7239
7240
7241
7242
7243
7244
7245
7246
7247
7248
7249
7250
7251
7252
7253
7254
7255
7256
7257
7258
7259
7260
7261
7262
7263
7264
7265
7266
7267
7268
7269
7270
7271
7272
7273
7274
7275
7276
7277
7278
7279
7280
7281
7282
7283
7284
7285
7286
7287
7288
7289
7290
7291
7292
7293
7294
7295
7296
7297
7298
7299
7300
7301
7302
7303
7304
7305
7306
7307
7308
7309
7310
7311
7312
7313
7314
7315
7316
7317
7318
7319
7320
7321
7322
7323
7324
7325
7326
7327
7328
7329
7330
7331
7332
7333
7334
7335
7336
7337
7338
7339
7340
7341
7342
7343
7344
7345
7346
7347
7348
7349
7350
7351
7352
7353
7354
7355
7356
7357
7358
7359
7360
7361
7362
7363
7364
7365
7366
7367
7368
7369
7370
7371
7372
7373
7374
7375
7376
7377
7378
7379
7380
7381
7382
7383
7384
7385
7386
7387
7388
7389
7390
7391
7392
7393
7394
7395
7396
7397
7398
7399
7400
7401
7402
7403
7404
7405
7406
7407
7408
7409
7410
7411
7412
7413
7414
7415
7416
7417
7418
7419
7420
7421
7422
7423
7424
7425
7426
7427
7428
7429
7430
7431
7432
7433
7434
7435
7436
7437
7438
7439
7440
7441
7442
7443
7444
7445
7446
7447
7448
7449
7450
7451
7452
7453
7454
7455
7456
7457
7458
7459
7460
7461
7462
7463
7464
7465
7466
7467
7468
7469
7470
7471
7472
7473
7474
7475
7476
7477
7478
7479
7480
7481
7482
7483
7484
7485
7486
7487
7488
7489
7490
7491
7492
7493
7494
7495
7496
7497
7498
7499
7500
7501
7502
7503
7504
7505
7506
7507
7508
7509
7510
7511
7512
7513
7514
7515
7516
7517
7518
7519
7520
7521
7522
7523
7524
7525
7526
7527
7528
7529
7530
7531
7532
7533
7534
7535
7536
7537
7538
7539
7540
7541
7542
7543
7544
7545
7546
7547
7548
7549
7550
7551
7552
7553
7554
7555
7556
7557
7558
7559
7560
7561
7562
7563
7564
7565
7566
7567
7568
7569
7570
7571
7572
7573
7574
7575
7576
7577
7578
7579
7580
7581
7582
7583
7584
7585
7586
7587
7588
7589
7590
7591
7592
7593
7594
7595
7596
7597
7598
7599
7600
7601
7602
7603
7604
7605
7606
7607
7608
7609
7610
7611
7612
7613
7614
7615
7616
7617
7618
7619
7620
7621
7622
7623
7624
7625
7626
7627
7628
7629
7630
7631
7632
7633
7634
7635
7636
7637
7638
7639
7640
7641
7642
7643
7644
7645
7646
7647
7648
7649
7650
7651
7652
7653
7654
7655
7656
7657
7658
7659
7660
7661
7662
7663
7664
7665
7666
7667
7668
7669
7670
7671
7672
7673
7674
7675
7676
7677
7678
7679
7680
7681
7682
7683
7684
7685
7686
7687
7688
7689
7690
7691
7692
7693
7694
7695
7696
7697
7698
7699
7700
7701
7702
7703
7704
7705
7706
7707
7708
7709
7710
7711
7712
7713
7714
7715
7716
7717
7718
7719
7720
7721
7722
7723
7724
7725
7726
7727
7728
7729
7730
7731
7732
7733
7734
7735
% \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