@typescriptify/sweph 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (211) hide show
  1. package/README.md +422 -0
  2. package/ephe/semo_18.se1 +0 -0
  3. package/ephe/sepl_18.se1 +0 -0
  4. package/originalCode/.eslintrc.json +124 -0
  5. package/originalCode/.gitattributes +2 -0
  6. package/originalCode/.github/FUNDING.yml +5 -0
  7. package/originalCode/.github/workflows/test.yml +35 -0
  8. package/originalCode/LICENSE +840 -0
  9. package/originalCode/README.md +91 -0
  10. package/originalCode/binding.gyp +41 -0
  11. package/originalCode/constants.js +366 -0
  12. package/originalCode/docs.gif +0 -0
  13. package/originalCode/index.d.ts +5115 -0
  14. package/originalCode/index.js +7 -0
  15. package/originalCode/index.mjs +109 -0
  16. package/originalCode/package.json +55 -0
  17. package/originalCode/src/functions/azalt.cpp +39 -0
  18. package/originalCode/src/functions/azalt_rev.cpp +35 -0
  19. package/originalCode/src/functions/calc.cpp +29 -0
  20. package/originalCode/src/functions/calc_pctr.cpp +31 -0
  21. package/originalCode/src/functions/calc_ut.cpp +29 -0
  22. package/originalCode/src/functions/close.cpp +6 -0
  23. package/originalCode/src/functions/cotrans.cpp +26 -0
  24. package/originalCode/src/functions/cotrans_sp.cpp +26 -0
  25. package/originalCode/src/functions/cs2degstr.cpp +19 -0
  26. package/originalCode/src/functions/cs2lonlatstr.cpp +23 -0
  27. package/originalCode/src/functions/cs2timestr.cpp +23 -0
  28. package/originalCode/src/functions/csnorm.cpp +15 -0
  29. package/originalCode/src/functions/csroundsec.cpp +15 -0
  30. package/originalCode/src/functions/d2l.cpp +15 -0
  31. package/originalCode/src/functions/date_conversion.cpp +30 -0
  32. package/originalCode/src/functions/day_of_week.cpp +15 -0
  33. package/originalCode/src/functions/degnorm.cpp +15 -0
  34. package/originalCode/src/functions/deltat.cpp +15 -0
  35. package/originalCode/src/functions/deltat_ex.cpp +24 -0
  36. package/originalCode/src/functions/difcs2n.cpp +19 -0
  37. package/originalCode/src/functions/difcsn.cpp +19 -0
  38. package/originalCode/src/functions/difdeg2n.cpp +19 -0
  39. package/originalCode/src/functions/difdegn.cpp +19 -0
  40. package/originalCode/src/functions/fixstar.cpp +32 -0
  41. package/originalCode/src/functions/fixstar2.cpp +32 -0
  42. package/originalCode/src/functions/fixstar2_mag.cpp +28 -0
  43. package/originalCode/src/functions/fixstar2_ut.cpp +32 -0
  44. package/originalCode/src/functions/fixstar_mag.cpp +28 -0
  45. package/originalCode/src/functions/fixstar_ut.cpp +32 -0
  46. package/originalCode/src/functions/gauquelin_sector.cpp +44 -0
  47. package/originalCode/src/functions/get_ayanamsa.cpp +15 -0
  48. package/originalCode/src/functions/get_ayanamsa_ex.cpp +27 -0
  49. package/originalCode/src/functions/get_ayanamsa_ex_ut.cpp +27 -0
  50. package/originalCode/src/functions/get_ayanamsa_name.cpp +19 -0
  51. package/originalCode/src/functions/get_ayanamsa_ut.cpp +15 -0
  52. package/originalCode/src/functions/get_current_file_data.cpp +28 -0
  53. package/originalCode/src/functions/get_library_path.cpp +8 -0
  54. package/originalCode/src/functions/get_orbital_elements.cpp +29 -0
  55. package/originalCode/src/functions/get_planet_name.cpp +19 -0
  56. package/originalCode/src/functions/get_tid_acc.cpp +7 -0
  57. package/originalCode/src/functions/heliacal_pheno_ut.cpp +52 -0
  58. package/originalCode/src/functions/heliacal_ut.cpp +52 -0
  59. package/originalCode/src/functions/helio_cross.cpp +33 -0
  60. package/originalCode/src/functions/helio_cross_ut.cpp +33 -0
  61. package/originalCode/src/functions/house_name.cpp +20 -0
  62. package/originalCode/src/functions/house_pos.cpp +36 -0
  63. package/originalCode/src/functions/houses.cpp +35 -0
  64. package/originalCode/src/functions/houses_armc.cpp +38 -0
  65. package/originalCode/src/functions/houses_armc_ex2.cpp +47 -0
  66. package/originalCode/src/functions/houses_ex.cpp +37 -0
  67. package/originalCode/src/functions/houses_ex2.cpp +46 -0
  68. package/originalCode/src/functions/jdet_to_utc.cpp +38 -0
  69. package/originalCode/src/functions/jdut1_to_utc.cpp +38 -0
  70. package/originalCode/src/functions/julday.cpp +25 -0
  71. package/originalCode/src/functions/lat_to_lmt.cpp +27 -0
  72. package/originalCode/src/functions/lmt_to_lat.cpp +27 -0
  73. package/originalCode/src/functions/lun_eclipse_how.cpp +34 -0
  74. package/originalCode/src/functions/lun_eclipse_when.cpp +31 -0
  75. package/originalCode/src/functions/lun_eclipse_when_loc.cpp +39 -0
  76. package/originalCode/src/functions/lun_occult_when_glob.cpp +35 -0
  77. package/originalCode/src/functions/lun_occult_when_loc.cpp +43 -0
  78. package/originalCode/src/functions/lun_occult_where.cpp +34 -0
  79. package/originalCode/src/functions/mooncross.cpp +26 -0
  80. package/originalCode/src/functions/mooncross_node.cpp +30 -0
  81. package/originalCode/src/functions/mooncross_node_ut.cpp +30 -0
  82. package/originalCode/src/functions/mooncross_ut.cpp +26 -0
  83. package/originalCode/src/functions/nod_aps.cpp +42 -0
  84. package/originalCode/src/functions/nod_aps_ut.cpp +42 -0
  85. package/originalCode/src/functions/orbit_max_min_true_distance.cpp +37 -0
  86. package/originalCode/src/functions/pheno.cpp +29 -0
  87. package/originalCode/src/functions/pheno_ut.cpp +29 -0
  88. package/originalCode/src/functions/radnorm.cpp +15 -0
  89. package/originalCode/src/functions/refrac.cpp +23 -0
  90. package/originalCode/src/functions/refrac_extended.cpp +32 -0
  91. package/originalCode/src/functions/revjul.cpp +33 -0
  92. package/originalCode/src/functions/rise_trans.cpp +44 -0
  93. package/originalCode/src/functions/rise_trans_true_hor.cpp +46 -0
  94. package/originalCode/src/functions/set_delta_t_userdef.cpp +14 -0
  95. package/originalCode/src/functions/set_ephe_path.cpp +14 -0
  96. package/originalCode/src/functions/set_jpl_file.cpp +14 -0
  97. package/originalCode/src/functions/set_sid_mode.cpp +20 -0
  98. package/originalCode/src/functions/set_tid_acc.cpp +14 -0
  99. package/originalCode/src/functions/set_topo.cpp +20 -0
  100. package/originalCode/src/functions/sidtime.cpp +15 -0
  101. package/originalCode/src/functions/sidtime0.cpp +21 -0
  102. package/originalCode/src/functions/sol_eclipse_how.cpp +34 -0
  103. package/originalCode/src/functions/sol_eclipse_when_glob.cpp +31 -0
  104. package/originalCode/src/functions/sol_eclipse_when_loc.cpp +39 -0
  105. package/originalCode/src/functions/sol_eclipse_where.cpp +30 -0
  106. package/originalCode/src/functions/solcross.cpp +26 -0
  107. package/originalCode/src/functions/solcross_ut.cpp +26 -0
  108. package/originalCode/src/functions/split_deg.cpp +35 -0
  109. package/originalCode/src/functions/time_equ.cpp +25 -0
  110. package/originalCode/src/functions/utc_time_zone.cpp +48 -0
  111. package/originalCode/src/functions/utc_to_jd.cpp +37 -0
  112. package/originalCode/src/functions/version.cpp +8 -0
  113. package/originalCode/src/functions/vis_limit_mag.cpp +50 -0
  114. package/originalCode/src/sweph.cpp +150 -0
  115. package/originalCode/src/sweph.h +119 -0
  116. package/originalCode/swisseph/swecl.c +6428 -0
  117. package/originalCode/swisseph/swedate.c +588 -0
  118. package/originalCode/swisseph/swedate.h +81 -0
  119. package/originalCode/swisseph/swehel.c +3511 -0
  120. package/originalCode/swisseph/swehouse.c +3143 -0
  121. package/originalCode/swisseph/swehouse.h +98 -0
  122. package/originalCode/swisseph/swejpl.c +958 -0
  123. package/originalCode/swisseph/swejpl.h +103 -0
  124. package/originalCode/swisseph/swemmoon.c +1930 -0
  125. package/originalCode/swisseph/swemplan.c +967 -0
  126. package/originalCode/swisseph/swemptab.h +10640 -0
  127. package/originalCode/swisseph/swenut2000a.h +2819 -0
  128. package/originalCode/swisseph/sweodef.h +326 -0
  129. package/originalCode/swisseph/sweph.c +8614 -0
  130. package/originalCode/swisseph/sweph.h +849 -0
  131. package/originalCode/swisseph/swephexp.h +1020 -0
  132. package/originalCode/swisseph/swephlib.c +4634 -0
  133. package/originalCode/swisseph/swephlib.h +189 -0
  134. package/package.json +28 -0
  135. package/scripts/gen-swemptab.js +177 -0
  136. package/scripts/gen-swenut2000a.js +106 -0
  137. package/src/SwissEph/README.md +268 -0
  138. package/src/SwissEph/UseCases/Ayanamsa.md +363 -0
  139. package/src/SwissEph/UseCases/AzimuthAltitude.md +408 -0
  140. package/src/SwissEph/UseCases/CoordinateSystems.md +337 -0
  141. package/src/SwissEph/UseCases/DateAndTime.md +368 -0
  142. package/src/SwissEph/UseCases/DeltaT.md +258 -0
  143. package/src/SwissEph/UseCases/EphemerisFiles.md +338 -0
  144. package/src/SwissEph/UseCases/FixedStars.md +300 -0
  145. package/src/SwissEph/UseCases/GauquelinSectors.md +304 -0
  146. package/src/SwissEph/UseCases/HeliacalEvents.md +396 -0
  147. package/src/SwissEph/UseCases/HelioCrossings.md +325 -0
  148. package/src/SwissEph/UseCases/HousePosition.md +254 -0
  149. package/src/SwissEph/UseCases/HouseSystems.md +279 -0
  150. package/src/SwissEph/UseCases/LunarEclipse.md +326 -0
  151. package/src/SwissEph/UseCases/MeridianTransit.md +279 -0
  152. package/src/SwissEph/UseCases/MoonCrossings.md +373 -0
  153. package/src/SwissEph/UseCases/NodesAndApsides.md +307 -0
  154. package/src/SwissEph/UseCases/Occultation.md +352 -0
  155. package/src/SwissEph/UseCases/OrbitalElements.md +469 -0
  156. package/src/SwissEph/UseCases/Phenomena.md +328 -0
  157. package/src/SwissEph/UseCases/PlanetPositions.md +366 -0
  158. package/src/SwissEph/UseCases/Planetocentric.md +278 -0
  159. package/src/SwissEph/UseCases/Refraction.md +314 -0
  160. package/src/SwissEph/UseCases/RiseAndSet.md +433 -0
  161. package/src/SwissEph/UseCases/SiderealTime.md +302 -0
  162. package/src/SwissEph/UseCases/SolarEclipse.md +379 -0
  163. package/src/SwissEph/UseCases/SunCrossings.md +275 -0
  164. package/src/SwissEph/UseCases/TopocentricCorrection.md +335 -0
  165. package/src/SwissEph/errors.ts +10 -0
  166. package/src/SwissEph/index.ts +823 -0
  167. package/src/SwissEph/types.ts +291 -0
  168. package/src/constants.ts +762 -0
  169. package/src/file-reader.ts +147 -0
  170. package/src/index.ts +10 -0
  171. package/src/swecl.ts +4526 -0
  172. package/src/swedate.ts +376 -0
  173. package/src/swehel.ts +1939 -0
  174. package/src/swehouse.ts +2167 -0
  175. package/src/swejpl.ts +470 -0
  176. package/src/swemmoon.ts +1318 -0
  177. package/src/swemplan.ts +585 -0
  178. package/src/swemptab.ts +4448 -0
  179. package/src/swenut2000a.ts +2763 -0
  180. package/src/sweph.ts +3993 -0
  181. package/src/swephlib.ts +2720 -0
  182. package/src/types.ts +490 -0
  183. package/tests/c-style/ayanamsa.test.ts +63 -0
  184. package/tests/c-style/config.test.ts +96 -0
  185. package/tests/c-style/crossings.test.ts +81 -0
  186. package/tests/c-style/date-time.test.ts +114 -0
  187. package/tests/c-style/eclipses.test.ts +84 -0
  188. package/tests/c-style/fixed-stars.test.ts +66 -0
  189. package/tests/c-style/heliacal.test.ts +34 -0
  190. package/tests/c-style/houses.test.ts +135 -0
  191. package/tests/c-style/math-utils.test.ts +160 -0
  192. package/tests/c-style/orbital.test.ts +78 -0
  193. package/tests/c-style/phenomena.test.ts +42 -0
  194. package/tests/c-style/planetocentric.test.ts +26 -0
  195. package/tests/c-style/planets.test.ts +117 -0
  196. package/tests/c-style/rise-set.test.ts +71 -0
  197. package/tests/helpers.ts +21 -0
  198. package/tests/modern/ayanamsa.test.ts +47 -0
  199. package/tests/modern/calc.test.ts +113 -0
  200. package/tests/modern/config.test.ts +46 -0
  201. package/tests/modern/crossings.test.ts +45 -0
  202. package/tests/modern/eclipses.test.ts +81 -0
  203. package/tests/modern/errors.test.ts +71 -0
  204. package/tests/modern/heliacal.test.ts +30 -0
  205. package/tests/modern/houses.test.ts +87 -0
  206. package/tests/modern/orbital.test.ts +79 -0
  207. package/tests/modern/phenomena.test.ts +41 -0
  208. package/tests/modern/rise-set.test.ts +60 -0
  209. package/tests/modern/statics.test.ts +99 -0
  210. package/tests/modern/utilities.test.ts +70 -0
  211. package/tsconfig.json +20 -0
@@ -0,0 +1,2167 @@
1
+ /*************************************************************
2
+ * Swiss Ephemeris house calculations
3
+ * Translated from swehouse.c
4
+ *
5
+ * Copyright (C) 1997 - 2021 Astrodienst AG, Switzerland.
6
+ * All rights reserved. (AGPL)
7
+ *************************************************************/
8
+
9
+ import {
10
+ DEGTORAD, RADTODEG, OK, ERR,
11
+ SE_ASC, SE_MC, SE_ARMC, SE_NASCMC,
12
+ SEFLG_SIDEREAL, SEFLG_SPEED, SEFLG_EQUATORIAL, SEFLG_NONUT, SEFLG_RADIANS,
13
+ SE_SUN, SE_SIDM_FAGAN_BRADLEY,
14
+ SE_SIDBIT_ECL_T0, SE_SIDBIT_SSY_PLANE,
15
+ SSY_PLANE_NODE_E2000, SSY_PLANE_NODE, SSY_PLANE_INCL,
16
+ J2000, J_TO_J2000, J2000_TO_J,
17
+ } from './constants';
18
+
19
+ import type { SweData, Houses } from './types';
20
+ import { createHouses } from './types';
21
+
22
+ import {
23
+ sweDegnorm, sweDifdeg2n, sweRadnorm,
24
+ sweCotrans,
25
+ swiCoortrf, swiCartpol, swiPolcart, swiCartpolSp, swiPolcartSp,
26
+ swiCrossProd, swiDotProdUnit,
27
+ swiPrecess, swiEpsiln, swiNutation,
28
+ sweDeltatEx, sweSidtime0,
29
+ } from './swephlib';
30
+
31
+ import {
32
+ sweCalcUt, sweSetSidMode,
33
+ sweGetAyanamsaEx, swiGetAyanamsaWithSpeed,
34
+ swiInitSwedIfStart,
35
+ } from './sweph';
36
+
37
+ /* ---- Constants ---- */
38
+ const VERY_SMALL = 1e-10;
39
+ const MILLIARCSEC = 1.0 / 3600000.0;
40
+ const SOLAR_YEAR = 365.24219893;
41
+ const ARMCS = (SOLAR_YEAR + 1) / SOLAR_YEAR * 360;
42
+ const VERY_SMALL_PLAC_ITER = 1.0 / 360000.0;
43
+ const SUNSHINE_KEEP_MC_SOUTH = 0;
44
+
45
+ /* ---- Degree-based trig helpers ---- */
46
+ function sind(x: number): number { return Math.sin(x * DEGTORAD); }
47
+ function cosd(x: number): number { return Math.cos(x * DEGTORAD); }
48
+ function tand(x: number): number { return Math.tan(x * DEGTORAD); }
49
+ function asind(x: number): number { return Math.asin(x) * RADTODEG; }
50
+ function acosd(x: number): number { return Math.acos(x) * RADTODEG; }
51
+ function atand(x: number): number { return Math.atan(x) * RADTODEG; }
52
+
53
+ /* ==================================================================
54
+ * Part 1: Core trig helpers
55
+ * ================================================================== */
56
+
57
+ /**
58
+ * Asc2 - oblique triangle solver
59
+ * x in range 0..90, f in range -90..+90
60
+ */
61
+ function asc2(x: number, f: number, sine: number, cose: number): number {
62
+ let ass = -tand(f) * sine + cose * cosd(x);
63
+ if (Math.abs(ass) < VERY_SMALL) ass = 0;
64
+ let sinx = sind(x);
65
+ if (Math.abs(sinx) < VERY_SMALL) sinx = 0;
66
+ if (sinx === 0) {
67
+ ass = ass < 0 ? -VERY_SMALL : VERY_SMALL;
68
+ } else if (ass === 0) {
69
+ ass = sinx < 0 ? -90 : 90;
70
+ } else {
71
+ ass = atand(sinx / ass);
72
+ }
73
+ if (ass < 0) ass = 180 + ass;
74
+ return ass;
75
+ }
76
+
77
+ /**
78
+ * Asc1 - ecliptic/great circle intersection
79
+ * Prepare quadrants before doing the work in Asc2.
80
+ */
81
+ function asc1(x1: number, f: number, sine: number, cose: number): number {
82
+ x1 = sweDegnorm(x1);
83
+ const n = Math.floor(x1 / 90) + 1;
84
+ if (Math.abs(90 - f) < VERY_SMALL) return 180;
85
+ if (Math.abs(90 + f) < VERY_SMALL) return 0;
86
+ let ass: number;
87
+ if (n === 1)
88
+ ass = asc2(x1, f, sine, cose);
89
+ else if (n === 2)
90
+ ass = 180 - asc2(180 - x1, -f, sine, cose);
91
+ else if (n === 3)
92
+ ass = 180 + asc2(x1 - 180, -f, sine, cose);
93
+ else
94
+ ass = 360 - asc2(360 - x1, f, sine, cose);
95
+ ass = sweDegnorm(ass);
96
+ if (Math.abs(ass - 90) < VERY_SMALL) ass = 90;
97
+ if (Math.abs(ass - 180) < VERY_SMALL) ass = 180;
98
+ if (Math.abs(ass - 270) < VERY_SMALL) ass = 270;
99
+ if (Math.abs(ass - 360) < VERY_SMALL) ass = 0;
100
+ return ass;
101
+ }
102
+
103
+ /**
104
+ * AscDash - derivative of Asc1 for speed computation
105
+ */
106
+ function ascDash(x: number, f: number, sine: number, cose: number): number {
107
+ const cosx = cosd(x);
108
+ const sinx = sind(x);
109
+ const sinx2 = sinx * sinx;
110
+ const c = cose * cosx - tand(f) * sine;
111
+ const d = sinx2 + c * c;
112
+ let dudt: number;
113
+ if (d > VERY_SMALL) {
114
+ dudt = (cosx * c + cose * sinx2) / d;
115
+ } else {
116
+ dudt = 0;
117
+ }
118
+ return dudt * ARMCS;
119
+ }
120
+
121
+ /** ARMC → MC (private to this module) */
122
+ function armcToMc(armc: number, eps: number): number {
123
+ const cose = cosd(eps);
124
+ if (Math.abs(armc - 90) > VERY_SMALL && Math.abs(armc - 270) > VERY_SMALL) {
125
+ const tant = tand(armc);
126
+ let mc = sweDegnorm(atand(tant / cose));
127
+ if (armc > 90 && armc <= 270)
128
+ mc = sweDegnorm(mc + 180);
129
+ return mc;
130
+ } else {
131
+ return Math.abs(armc - 90) <= VERY_SMALL ? 90 : 270;
132
+ }
133
+ }
134
+
135
+ /** If ascendant is on western half of horizon, add 180° */
136
+ function fixAscPolar(asc: number, armc: number, eps: number, geolat: number): number {
137
+ const demc = atand(sind(armc) * tand(eps));
138
+ if (geolat >= 0 && 90 - geolat + demc < 0)
139
+ asc = sweDegnorm(asc + 180);
140
+ if (geolat < 0 && -90 - geolat + demc > 0)
141
+ asc = sweDegnorm(asc + 180);
142
+ return asc;
143
+ }
144
+
145
+ /** APC sector helper */
146
+ function apcSector(n: number, ph: number, e: number, az: number): number {
147
+ let kv: number, dasc: number;
148
+ let isBelow = 0;
149
+ if (Math.abs(ph * RADTODEG) > 90 - VERY_SMALL) {
150
+ kv = 0;
151
+ dasc = 0;
152
+ } else {
153
+ kv = Math.atan(Math.tan(ph) * Math.tan(e) * Math.cos(az) / (1 + Math.tan(ph) * Math.tan(e) * Math.sin(az)));
154
+ if (Math.abs(ph * RADTODEG) < VERY_SMALL) {
155
+ dasc = (90 - VERY_SMALL) * DEGTORAD;
156
+ if (ph < 0) dasc = -dasc;
157
+ } else {
158
+ dasc = Math.atan(Math.sin(kv) / Math.tan(ph));
159
+ }
160
+ }
161
+ let k: number;
162
+ if (n < 8) {
163
+ isBelow = 1;
164
+ k = n - 1;
165
+ } else {
166
+ k = n - 13;
167
+ }
168
+ let a: number;
169
+ if (isBelow) {
170
+ a = kv + az + Math.PI / 2 + k * (Math.PI / 2 - kv) / 3;
171
+ } else {
172
+ a = kv + az + Math.PI / 2 + k * (Math.PI / 2 + kv) / 3;
173
+ }
174
+ a = sweRadnorm(a);
175
+ let dret = Math.atan2(
176
+ Math.tan(dasc) * Math.tan(ph) * Math.sin(az) + Math.sin(a),
177
+ Math.cos(e) * (Math.tan(dasc) * Math.tan(ph) * Math.cos(az) + Math.cos(a)) + Math.sin(e) * Math.tan(ph) * Math.sin(az - a)
178
+ );
179
+ dret = sweDegnorm(dret * RADTODEG);
180
+ return dret;
181
+ }
182
+
183
+ /** Sunshine init - compute offsets on diurnal/nocturnal arcs */
184
+ function sunshineInit(lat: number, dec: number, xh: number[]): number {
185
+ let ad: number;
186
+ const arg = tand(dec) * tand(lat);
187
+ if (arg >= 1) {
188
+ ad = 90 - VERY_SMALL;
189
+ } else if (arg <= -1) {
190
+ ad = -90 + VERY_SMALL;
191
+ } else {
192
+ ad = asind(arg);
193
+ }
194
+ const nsa = 90 - ad;
195
+ const dsa = 90 + ad;
196
+ xh[2] = -2 * nsa / 3;
197
+ xh[3] = -1 * nsa / 3;
198
+ xh[5] = 1 * nsa / 3;
199
+ xh[6] = 2 * nsa / 3;
200
+ xh[8] = -2 * dsa / 3;
201
+ xh[9] = -1 * dsa / 3;
202
+ xh[11] = 1 * dsa / 3;
203
+ xh[12] = 2 * dsa / 3;
204
+ if (Math.abs(arg) >= 1) return ERR;
205
+ return OK;
206
+ }
207
+
208
+ /** Sunshine solution - Makransky */
209
+ function sunshineSolutionMakransky(ramc: number, lat: number, ecl: number, hsp: Houses): number {
210
+ const xh = new Array<number>(13).fill(0);
211
+ const dec = hsp.sundec;
212
+ const sinlat = sind(lat);
213
+ const coslat = cosd(lat);
214
+ const tanlat = tand(lat);
215
+ const tandec = tand(dec);
216
+ const sinecl = sind(ecl);
217
+ if (sunshineInit(lat, dec, xh) === ERR) return ERR;
218
+ for (let ih = 1; ih <= 12; ih++) {
219
+ let z = 0;
220
+ if ((ih - 1) % 3 === 0) continue;
221
+ const md = Math.abs(xh[ih]);
222
+ let rah: number;
223
+ if (ih <= 6)
224
+ rah = sweDegnorm(ramc + 180 + xh[ih]);
225
+ else
226
+ rah = sweDegnorm(ramc + xh[ih]);
227
+ if (lat < 0) rah = sweDegnorm(180 + rah);
228
+ let zd: number;
229
+ if (md === 90) {
230
+ zd = 90.0 - atand(sinlat * tandec);
231
+ } else {
232
+ let a: number;
233
+ if (md < 90) {
234
+ a = atand(coslat * tand(md));
235
+ } else {
236
+ a = atand(tand(md - 90) / coslat);
237
+ }
238
+ const b = atand(tanlat * cosd(md));
239
+ let c: number;
240
+ if (ih <= 6) c = b + dec;
241
+ else c = b - dec;
242
+ const f = atand(sinlat * sind(md) * tand(c));
243
+ zd = a + f;
244
+ }
245
+ const pole = asind(sind(zd) * sinlat);
246
+ const q = asind(tandec * tand(pole));
247
+ let w: number;
248
+ if (ih <= 3 || ih >= 11)
249
+ w = sweDegnorm(rah - q);
250
+ else
251
+ w = sweDegnorm(rah + q);
252
+ let cu: number;
253
+ let r = 0;
254
+ if (w === 90) {
255
+ r = atand(sinecl * tand(pole));
256
+ cu = (ih <= 3 || ih >= 11) ? 90 + r : 90 - r;
257
+ } else if (w === 270) {
258
+ r = atand(sinecl * tand(pole));
259
+ cu = (ih <= 3 || ih >= 11) ? 270 - r : 270 + r;
260
+ } else {
261
+ const m = atand(Math.abs(tand(pole) / cosd(w)));
262
+ if (ih <= 3 || ih >= 11) {
263
+ z = (w > 90 && w < 270) ? m - ecl : m + ecl;
264
+ } else {
265
+ z = (w > 90 && w < 270) ? m + ecl : m - ecl;
266
+ }
267
+ if (z === 90) {
268
+ cu = w < 180 ? 90 : 270;
269
+ } else {
270
+ r = atand(Math.abs(cosd(m) * tand(w) / cosd(z)));
271
+ if (w < 90) cu = r;
272
+ else if (w > 90 && w < 180) cu = 180 - r;
273
+ else if (w > 180 && w < 270) cu = 180 + r;
274
+ else cu = 360 - r;
275
+ }
276
+ if (z > 90) {
277
+ if (w < 90) cu = 180 - r;
278
+ else if (w > 90 && w < 180) cu = r;
279
+ else if (w > 180 && w < 270) cu = 360 - r;
280
+ else cu = 180 + r;
281
+ }
282
+ if (lat < 0) cu = sweDegnorm(cu + 180);
283
+ }
284
+ hsp.cusp[ih] = cu;
285
+ }
286
+ return OK;
287
+ }
288
+
289
+ /** Sunshine solution - Treindl */
290
+ function sunshineSolutionTreindl(ramc: number, lat: number, ecl: number, hsp: Houses): number {
291
+ const xh = new Array<number>(13).fill(0);
292
+ const dec = hsp.sundec;
293
+ const sinlat = sind(lat);
294
+ const coslat = cosd(lat);
295
+ const cosdec = cosd(dec);
296
+ const tandec = tand(dec);
297
+ const sinecl = sind(ecl);
298
+ const cosecl = cosd(ecl);
299
+ let retval = OK;
300
+ sunshineInit(lat, dec, xh);
301
+ const mcdec = atand(sind(ramc) * tand(ecl));
302
+ const mcUnderHorizon = Math.abs(lat - mcdec) > 90;
303
+ if (mcUnderHorizon && SUNSHINE_KEEP_MC_SOUTH) {
304
+ for (let ih = 2; ih <= 12; ih++) xh[ih] = -xh[ih];
305
+ }
306
+ for (let ih = 1; ih <= 12; ih++) {
307
+ if ((ih - 1) % 3 === 0) continue;
308
+ const xhs = 2 * asind(cosdec * sind(xh[ih] / 2));
309
+ const cosa = tandec * tand(xhs / 2);
310
+ const alph = acosd(cosa);
311
+ let alpha2: number, b: number;
312
+ if (ih > 7) {
313
+ alpha2 = 180 - alph;
314
+ b = 90 - lat + dec;
315
+ } else {
316
+ alpha2 = alph;
317
+ b = 90 - lat - dec;
318
+ }
319
+ const cosc = cosd(xhs) * cosd(b) + sind(xhs) * sind(b) * cosd(alpha2);
320
+ const c = acosd(cosc);
321
+ if (c < 1e-6) {
322
+ hsp.serr = `Sunshine house ${ih} c=${c} very small`;
323
+ retval = ERR;
324
+ }
325
+ const sinzd = sind(xhs) * sind(alpha2) / sind(c);
326
+ const zd = asind(sinzd);
327
+ const rax = atand(coslat * tand(zd));
328
+ let pole = asind(sinzd * sinlat);
329
+ let a: number;
330
+ if (ih <= 6) {
331
+ pole = -pole;
332
+ a = sweDegnorm(rax + ramc + 180);
333
+ } else {
334
+ a = sweDegnorm(ramc + rax);
335
+ }
336
+ const hc = asc1(a, pole, sinecl, cosecl);
337
+ hsp.cusp[ih] = hc;
338
+ }
339
+ if (mcUnderHorizon && !SUNSHINE_KEEP_MC_SOUTH) {
340
+ for (let ih = 2; ih <= 12; ih++) {
341
+ if ((ih - 1) % 3 === 0) continue;
342
+ hsp.cusp[ih] = sweDegnorm(hsp.cusp[ih] + 180);
343
+ }
344
+ }
345
+ return retval;
346
+ }
347
+
348
+ /* ==================================================================
349
+ * CalcH - main house calculation engine
350
+ * ================================================================== */
351
+ function calcH(th: number, fi: number, ekl: number, hsy: string, hsp: Houses): number {
352
+ let tanfi: number, cosfi: number, sinfi: number;
353
+ let a: number, c: number, f: number, fh1: number, fh2: number;
354
+ let xh1: number, xh2: number, rectasc: number, ad3: number, acmc: number, vemc: number;
355
+ let i: number, retc = OK;
356
+ const cose = cosd(ekl);
357
+ const sine = sind(ekl);
358
+ const tane = tand(ekl);
359
+ const niterMax = 100;
360
+ let cuspsv: number;
361
+ let tant: number;
362
+ hsp.serr = '';
363
+ hsp.doInterpol = false;
364
+ /* north and south poles */
365
+ if (Math.abs(Math.abs(fi) - 90) < VERY_SMALL) {
366
+ fi = fi < 0 ? -90 + VERY_SMALL : 90 - VERY_SMALL;
367
+ }
368
+ tanfi = tand(fi);
369
+ /* mc */
370
+ if (Math.abs(th - 90) > VERY_SMALL && Math.abs(th - 270) > VERY_SMALL) {
371
+ tant = tand(th);
372
+ hsp.mc = atand(tant / cose);
373
+ if (th > 90 && th <= 270)
374
+ hsp.mc = sweDegnorm(hsp.mc + 180);
375
+ } else {
376
+ hsp.mc = Math.abs(th - 90) <= VERY_SMALL ? 90 : 270;
377
+ }
378
+ hsp.mc = sweDegnorm(hsp.mc);
379
+ if (hsp.doSpeed) hsp.mcSpeed = ascDash(th, 0, sine, cose);
380
+ /* ascendant */
381
+ hsp.ac = asc1(th + 90, fi, sine, cose);
382
+ if (hsp.doSpeed) hsp.acSpeed = ascDash(th + 90, fi, sine, cose);
383
+ if (hsp.doHspeed) {
384
+ for (i = 0; i <= 12; i++) hsp.cuspSpeed[i] = 0;
385
+ }
386
+ hsp.armcSpeed = ARMCS;
387
+ hsp.cusp[1] = hsp.ac;
388
+ hsp.cusp[10] = hsp.mc;
389
+ if (hsp.doHspeed) {
390
+ hsp.cuspSpeed[1] = hsp.acSpeed;
391
+ hsp.cuspSpeed[10] = hsp.mcSpeed;
392
+ }
393
+ /* lowercase letters (except 'i') are deprecated */
394
+ if (hsy.charCodeAt(0) > 95 && hsy !== 'i') {
395
+ hsp.serr = `use of lower case letters like ${hsy} for house systems is deprecated`;
396
+ hsy = String.fromCharCode(hsy.charCodeAt(0) - 32);
397
+ }
398
+
399
+ // Label for porphyry fallback (replaces C goto)
400
+ let doPorphyry = false;
401
+
402
+ switch (hsy) {
403
+ case 'A':
404
+ case 'E': { /* equal houses */
405
+ acmc = sweDifdeg2n(hsp.ac, hsp.mc);
406
+ if (acmc < 0) {
407
+ hsp.ac = sweDegnorm(hsp.ac + 180);
408
+ hsp.cusp[1] = hsp.ac;
409
+ }
410
+ for (i = 2; i <= 12; i++)
411
+ hsp.cusp[i] = sweDegnorm(hsp.cusp[1] + (i - 1) * 30);
412
+ if (hsp.doHspeed) {
413
+ for (i = 1; i <= 12; i++) hsp.cuspSpeed[i] = hsp.acSpeed;
414
+ }
415
+ break;
416
+ }
417
+ case 'D': { /* equal, begin at MC */
418
+ acmc = sweDifdeg2n(hsp.ac, hsp.mc);
419
+ if (acmc < 0) hsp.ac = sweDegnorm(hsp.ac + 180);
420
+ hsp.cusp[10] = hsp.mc;
421
+ for (i = 11; i <= 12; i++)
422
+ hsp.cusp[i] = sweDegnorm(hsp.cusp[10] + (i - 10) * 30);
423
+ for (i = 1; i <= 9; i++)
424
+ hsp.cusp[i] = sweDegnorm(hsp.cusp[10] + (i + 2) * 30);
425
+ if (hsp.doHspeed) {
426
+ for (i = 1; i <= 12; i++) hsp.cuspSpeed[i] = hsp.mcSpeed;
427
+ }
428
+ break;
429
+ }
430
+ case 'C': { /* Campanus */
431
+ fh1 = asind(sind(fi) / 2);
432
+ fh2 = asind(Math.sqrt(3) / 2 * sind(fi));
433
+ cosfi = cosd(fi);
434
+ if (Math.abs(cosfi) === 0) {
435
+ if (fi > 0) xh1 = xh2 = 90;
436
+ else xh1 = xh2 = 270;
437
+ } else {
438
+ xh1 = atand(Math.sqrt(3) / cosfi);
439
+ xh2 = atand(1 / Math.sqrt(3) / cosfi);
440
+ }
441
+ hsp.cusp[11] = asc1(th + 90 - xh1, fh1, sine, cose);
442
+ hsp.cusp[12] = asc1(th + 90 - xh2, fh2, sine, cose);
443
+ hsp.cusp[2] = asc1(th + 90 + xh2, fh2, sine, cose);
444
+ hsp.cusp[3] = asc1(th + 90 + xh1, fh1, sine, cose);
445
+ if (hsp.doHspeed) {
446
+ hsp.cuspSpeed[11] = ascDash(th + 90 - xh1, fh1, sine, cose);
447
+ hsp.cuspSpeed[12] = ascDash(th + 90 - xh2, fh2, sine, cose);
448
+ hsp.cuspSpeed[2] = ascDash(th + 90 + xh2, fh2, sine, cose);
449
+ hsp.cuspSpeed[3] = ascDash(th + 90 + xh1, fh1, sine, cose);
450
+ }
451
+ if (Math.abs(fi) >= 90 - ekl) {
452
+ acmc = sweDifdeg2n(hsp.ac, hsp.mc);
453
+ if (acmc < 0) {
454
+ hsp.ac = sweDegnorm(hsp.ac + 180);
455
+ hsp.mc = sweDegnorm(hsp.mc + 180);
456
+ for (i = 1; i <= 12; i++) {
457
+ if (i >= 4 && i < 10) continue;
458
+ hsp.cusp[i] = sweDegnorm(hsp.cusp[i] + 180);
459
+ }
460
+ }
461
+ }
462
+ break;
463
+ }
464
+ case 'H': { /* Horizon / Azimut */
465
+ if (fi > 0) fi = 90 - fi;
466
+ else fi = -90 - fi;
467
+ if (Math.abs(Math.abs(fi) - 90) < VERY_SMALL) {
468
+ fi = fi < 0 ? -90 + VERY_SMALL : 90 - VERY_SMALL;
469
+ }
470
+ th = sweDegnorm(th + 180);
471
+ fh1 = asind(sind(fi) / 2);
472
+ fh2 = asind(Math.sqrt(3) / 2 * sind(fi));
473
+ cosfi = cosd(fi);
474
+ if (Math.abs(cosfi) === 0) {
475
+ if (fi > 0) xh1 = xh2 = 90;
476
+ else xh1 = xh2 = 270;
477
+ } else {
478
+ xh1 = atand(Math.sqrt(3) / cosfi);
479
+ xh2 = atand(1 / Math.sqrt(3) / cosfi);
480
+ }
481
+ hsp.cusp[11] = asc1(th + 90 - xh1, fh1, sine, cose);
482
+ hsp.cusp[12] = asc1(th + 90 - xh2, fh2, sine, cose);
483
+ hsp.cusp[1] = asc1(th + 90, fi, sine, cose);
484
+ hsp.cusp[2] = asc1(th + 90 + xh2, fh2, sine, cose);
485
+ hsp.cusp[3] = asc1(th + 90 + xh1, fh1, sine, cose);
486
+ if (hsp.doHspeed) {
487
+ hsp.cuspSpeed[11] = ascDash(th + 90 - xh1, fh1, sine, cose);
488
+ hsp.cuspSpeed[12] = ascDash(th + 90 - xh2, fh2, sine, cose);
489
+ hsp.cuspSpeed[1] = ascDash(th + 90, fi, sine, cose);
490
+ hsp.cuspSpeed[2] = ascDash(th + 90 + xh2, fh2, sine, cose);
491
+ hsp.cuspSpeed[3] = ascDash(th + 90 + xh1, fh1, sine, cose);
492
+ }
493
+ if (Math.abs(fi) >= 90 - ekl) {
494
+ acmc = sweDifdeg2n(hsp.ac, hsp.mc);
495
+ if (acmc < 0) {
496
+ hsp.ac = sweDegnorm(hsp.ac + 180);
497
+ hsp.mc = sweDegnorm(hsp.mc + 180);
498
+ for (i = 1; i <= 12; i++) {
499
+ if (i >= 4 && i < 10) continue;
500
+ hsp.cusp[i] = sweDegnorm(hsp.cusp[i] + 180);
501
+ }
502
+ }
503
+ }
504
+ for (i = 1; i <= 3; i++) hsp.cusp[i] = sweDegnorm(hsp.cusp[i] + 180);
505
+ for (i = 11; i <= 12; i++) hsp.cusp[i] = sweDegnorm(hsp.cusp[i] + 180);
506
+ /* restore fi and th */
507
+ if (fi > 0) fi = 90 - fi;
508
+ else fi = -90 - fi;
509
+ th = sweDegnorm(th + 180);
510
+ acmc = sweDifdeg2n(hsp.ac, hsp.mc);
511
+ if (acmc < 0) hsp.ac = sweDegnorm(hsp.ac + 180);
512
+ break;
513
+ }
514
+ case 'I':
515
+ case 'i': { /* Sunshine houses */
516
+ acmc = sweDifdeg2n(hsp.ac, hsp.mc);
517
+ if (acmc < 0) {
518
+ hsp.ac = sweDegnorm(hsp.ac + 180);
519
+ hsp.cusp[1] = hsp.ac;
520
+ if (!SUNSHINE_KEEP_MC_SOUTH && hsy === 'I') {
521
+ hsp.mc = sweDegnorm(hsp.mc + 180);
522
+ hsp.cusp[10] = hsp.mc;
523
+ }
524
+ }
525
+ hsp.cusp[4] = sweDegnorm(hsp.cusp[10] + 180);
526
+ hsp.cusp[7] = sweDegnorm(hsp.cusp[1] + 180);
527
+ if (hsy === 'I') {
528
+ retc = sunshineSolutionTreindl(th, fi, ekl, hsp);
529
+ } else {
530
+ retc = sunshineSolutionMakransky(th, fi, ekl, hsp);
531
+ }
532
+ if (retc === ERR) {
533
+ hsp.serr = 'within polar circle, switched to Porphyry';
534
+ doPorphyry = true;
535
+ } else {
536
+ hsp.doInterpol = hsp.doHspeed;
537
+ }
538
+ break;
539
+ }
540
+ case 'J': { /* Savard-A */
541
+ sinfi = sind(fi);
542
+ cosfi = cosd(fi);
543
+ let xs1: number, xs2: number;
544
+ if (Math.abs(fi) < VERY_SMALL) {
545
+ xs2 = 1 / 3.0;
546
+ xs1 = 2 / 3.0;
547
+ } else {
548
+ xs2 = sind(fi / 3) / sinfi;
549
+ xs1 = sind(2 * fi / 3) / sinfi;
550
+ }
551
+ xs2 = asind(xs2);
552
+ xs1 = asind(xs1);
553
+ if (cosfi === 0) {
554
+ if (fi > 0) xh1 = xh2 = 90;
555
+ else xh1 = xh2 = 270;
556
+ } else {
557
+ xh1 = atand(tand(xs1) / cosfi);
558
+ xh2 = atand(tand(xs2) / cosfi);
559
+ }
560
+ fh1 = asind(sind(fi) * sind(90 - xs1));
561
+ fh2 = asind(sind(fi) * sind(90 - xs2));
562
+ hsp.cusp[12] = asc1(th + 90 - xh2, fh2, sine, cose);
563
+ hsp.cusp[11] = asc1(th + 90 - xh1, fh1, sine, cose);
564
+ hsp.cusp[2] = asc1(th + 90 + xh2, fh2, sine, cose);
565
+ hsp.cusp[3] = asc1(th + 90 + xh1, fh1, sine, cose);
566
+ if (hsp.doHspeed) {
567
+ hsp.cuspSpeed[11] = ascDash(th + 90 - xh1, fh1, sine, cose);
568
+ hsp.cuspSpeed[12] = ascDash(th + 90 - xh2, fh2, sine, cose);
569
+ hsp.cuspSpeed[3] = ascDash(th + 90 + xh1, fh1, sine, cose);
570
+ hsp.cuspSpeed[2] = ascDash(th + 90 + xh2, fh2, sine, cose);
571
+ }
572
+ if (Math.abs(fi) >= 90 - ekl) {
573
+ acmc = sweDifdeg2n(hsp.ac, hsp.mc);
574
+ if (acmc < 0) {
575
+ hsp.ac = sweDegnorm(hsp.ac + 180);
576
+ hsp.mc = sweDegnorm(hsp.mc + 180);
577
+ for (i = 1; i <= 12; i++) {
578
+ if (i >= 4 && i < 10) continue;
579
+ hsp.cusp[i] = sweDegnorm(hsp.cusp[i] + 180);
580
+ }
581
+ }
582
+ }
583
+ break;
584
+ }
585
+ case 'K': { /* Koch */
586
+ if (Math.abs(fi) >= 90 - ekl) {
587
+ retc = ERR;
588
+ hsp.serr = 'within polar circle, switched to Porphyry';
589
+ doPorphyry = true;
590
+ break;
591
+ }
592
+ let sina = sind(hsp.mc) * sine / cosd(fi);
593
+ if (sina > 1) sina = 1;
594
+ if (sina < -1) sina = -1;
595
+ const cosa = Math.sqrt(1 - sina * sina);
596
+ c = atand(tanfi / cosa);
597
+ ad3 = asind(sind(c) * sina) / 3.0;
598
+ hsp.cusp[11] = asc1(th + 30 - 2 * ad3, fi, sine, cose);
599
+ hsp.cusp[12] = asc1(th + 60 - ad3, fi, sine, cose);
600
+ hsp.cusp[2] = asc1(th + 120 + ad3, fi, sine, cose);
601
+ hsp.cusp[3] = asc1(th + 150 + 2 * ad3, fi, sine, cose);
602
+ if (hsp.doHspeed) {
603
+ hsp.cuspSpeed[11] = ascDash(th + 30 - 2 * ad3, fi, sine, cose);
604
+ hsp.cuspSpeed[12] = ascDash(th + 60 - ad3, fi, sine, cose);
605
+ hsp.cuspSpeed[2] = ascDash(th + 120 + ad3, fi, sine, cose);
606
+ hsp.cuspSpeed[3] = ascDash(th + 150 + 2 * ad3, fi, sine, cose);
607
+ }
608
+ break;
609
+ }
610
+ case 'L': { /* Pullen SD sinusoidal delta */
611
+ let d: number, q1: number;
612
+ acmc = sweDifdeg2n(hsp.ac, hsp.mc);
613
+ if (acmc < 0) {
614
+ hsp.ac = sweDegnorm(hsp.ac + 180);
615
+ hsp.cusp[1] = hsp.ac;
616
+ acmc = sweDifdeg2n(hsp.ac, hsp.mc);
617
+ }
618
+ q1 = 180 - acmc;
619
+ d = (acmc - 90) / 4.0;
620
+ if (acmc <= 30) {
621
+ hsp.cusp[11] = hsp.cusp[12] = sweDegnorm(hsp.mc + acmc / 2);
622
+ } else {
623
+ hsp.cusp[11] = sweDegnorm(hsp.mc + 30 + d);
624
+ hsp.cusp[12] = sweDegnorm(hsp.mc + 60 + 3 * d);
625
+ }
626
+ d = (q1 - 90) / 4.0;
627
+ if (q1 <= 30) {
628
+ hsp.cusp[2] = hsp.cusp[3] = sweDegnorm(hsp.ac + q1 / 2);
629
+ } else {
630
+ hsp.cusp[2] = sweDegnorm(hsp.ac + 30 + d);
631
+ hsp.cusp[3] = sweDegnorm(hsp.ac + 60 + 3 * d);
632
+ }
633
+ hsp.doInterpol = hsp.doHspeed;
634
+ break;
635
+ }
636
+ case 'N': { /* equal/1=Aries */
637
+ acmc = sweDifdeg2n(hsp.ac, hsp.mc);
638
+ if (acmc < 0) hsp.ac = sweDegnorm(hsp.ac + 180);
639
+ for (i = 1; i <= 12; i++) hsp.cusp[i] = (i - 1) * 30.0;
640
+ break;
641
+ }
642
+ case 'O': { /* Porphyry */
643
+ doPorphyry = true;
644
+ break;
645
+ }
646
+ case 'Q': { /* Pullen sinusoidal ratio */
647
+ const third = 1.0 / 3.0;
648
+ const two23 = Math.pow(2.0 * 2.0, third);
649
+ acmc = sweDifdeg2n(hsp.ac, hsp.mc);
650
+ if (acmc < 0) {
651
+ hsp.ac = sweDegnorm(hsp.ac + 180);
652
+ hsp.cusp[1] = hsp.ac;
653
+ acmc = sweDifdeg2n(hsp.ac, hsp.mc);
654
+ }
655
+ let q = acmc;
656
+ if (q > 90) q = 180 - q;
657
+ let x: number, xr: number, xr3: number, xr4: number;
658
+ if (q < 1e-30) {
659
+ x = xr = xr3 = 0;
660
+ xr4 = 180;
661
+ } else {
662
+ const cc = (180 - q) / q;
663
+ const csq = cc * cc;
664
+ const ccr = Math.pow(csq - cc, third);
665
+ const cqx = Math.sqrt(two23 * ccr + 1.0);
666
+ const r1 = 0.5 * cqx;
667
+ const r2 = 0.5 * Math.sqrt(-2 * (1 - 2 * cc) / cqx - two23 * ccr + 2);
668
+ const r = r1 + r2 - 0.5;
669
+ x = q / (2 * r + 1);
670
+ xr = r * x;
671
+ xr3 = xr * r * r;
672
+ xr4 = xr3 * r;
673
+ }
674
+ if (acmc > 90) {
675
+ hsp.cusp[11] = sweDegnorm(hsp.mc + xr3);
676
+ hsp.cusp[12] = sweDegnorm(hsp.cusp[11] + xr4);
677
+ hsp.cusp[2] = sweDegnorm(hsp.ac + xr);
678
+ hsp.cusp[3] = sweDegnorm(hsp.cusp[2] + x);
679
+ } else {
680
+ hsp.cusp[11] = sweDegnorm(hsp.mc + xr);
681
+ hsp.cusp[12] = sweDegnorm(hsp.cusp[11] + x);
682
+ hsp.cusp[2] = sweDegnorm(hsp.ac + xr3);
683
+ hsp.cusp[3] = sweDegnorm(hsp.cusp[2] + xr4);
684
+ }
685
+ hsp.doInterpol = hsp.doHspeed;
686
+ break;
687
+ }
688
+ case 'R': { /* Regiomontanus */
689
+ fh1 = atand(tanfi * 0.5);
690
+ fh2 = atand(tanfi * cosd(30));
691
+ hsp.cusp[11] = asc1(30 + th, fh1, sine, cose);
692
+ hsp.cusp[12] = asc1(60 + th, fh2, sine, cose);
693
+ hsp.cusp[2] = asc1(120 + th, fh2, sine, cose);
694
+ hsp.cusp[3] = asc1(150 + th, fh1, sine, cose);
695
+ if (hsp.doHspeed) {
696
+ hsp.cuspSpeed[11] = ascDash(30 + th, fh1, sine, cose);
697
+ hsp.cuspSpeed[12] = ascDash(60 + th, fh2, sine, cose);
698
+ hsp.cuspSpeed[2] = ascDash(120 + th, fh2, sine, cose);
699
+ hsp.cuspSpeed[3] = ascDash(150 + th, fh1, sine, cose);
700
+ }
701
+ if (Math.abs(fi) >= 90 - ekl) {
702
+ acmc = sweDifdeg2n(hsp.ac, hsp.mc);
703
+ if (acmc < 0) {
704
+ hsp.ac = sweDegnorm(hsp.ac + 180);
705
+ hsp.mc = sweDegnorm(hsp.mc + 180);
706
+ for (i = 1; i <= 12; i++) {
707
+ if (i >= 4 && i < 10) continue;
708
+ hsp.cusp[i] = sweDegnorm(hsp.cusp[i] + 180);
709
+ }
710
+ }
711
+ }
712
+ break;
713
+ }
714
+ case 'S': { /* Sripati */
715
+ acmc = sweDifdeg2n(hsp.ac, hsp.mc);
716
+ if (acmc < 0) {
717
+ hsp.ac = sweDegnorm(hsp.ac + 180);
718
+ acmc = sweDifdeg2n(hsp.ac, hsp.mc);
719
+ }
720
+ const q1 = 180 - acmc;
721
+ const s1 = q1 / 3.0;
722
+ const s4 = acmc / 3.0;
723
+ hsp.cusp[1] = sweDegnorm(hsp.ac - s4 * 0.5);
724
+ hsp.cusp[2] = sweDegnorm(hsp.ac + s1 * 0.5);
725
+ hsp.cusp[3] = sweDegnorm(hsp.ac + s1 * 1.5);
726
+ hsp.cusp[10] = sweDegnorm(hsp.mc - s1 * 0.5);
727
+ hsp.cusp[11] = sweDegnorm(hsp.mc + s4 * 0.5);
728
+ hsp.cusp[12] = sweDegnorm(hsp.mc + s4 * 1.5);
729
+ hsp.doInterpol = hsp.doHspeed;
730
+ break;
731
+ }
732
+ case 'T': { /* Topocentric (Polich/Page) */
733
+ fh1 = atand(tanfi / 3.0);
734
+ fh2 = atand(tanfi * 2.0 / 3.0);
735
+ hsp.cusp[11] = asc1(30 + th, fh1, sine, cose);
736
+ hsp.cusp[12] = asc1(60 + th, fh2, sine, cose);
737
+ hsp.cusp[2] = asc1(120 + th, fh2, sine, cose);
738
+ hsp.cusp[3] = asc1(150 + th, fh1, sine, cose);
739
+ if (hsp.doHspeed) {
740
+ hsp.cuspSpeed[11] = ascDash(30 + th, fh1, sine, cose);
741
+ hsp.cuspSpeed[12] = ascDash(60 + th, fh2, sine, cose);
742
+ hsp.cuspSpeed[2] = ascDash(120 + th, fh2, sine, cose);
743
+ hsp.cuspSpeed[3] = ascDash(150 + th, fh1, sine, cose);
744
+ }
745
+ if (Math.abs(fi) >= 90 - ekl) {
746
+ acmc = sweDifdeg2n(hsp.ac, hsp.mc);
747
+ if (acmc < 0) {
748
+ hsp.ac = sweDegnorm(hsp.ac + 180);
749
+ hsp.mc = sweDegnorm(hsp.mc + 180);
750
+ for (i = 1; i <= 12; i++)
751
+ hsp.cusp[i] = sweDegnorm(hsp.cusp[i] + 180);
752
+ }
753
+ }
754
+ break;
755
+ }
756
+ case 'V': { /* Vehlow */
757
+ acmc = sweDifdeg2n(hsp.ac, hsp.mc);
758
+ if (acmc < 0) hsp.ac = sweDegnorm(hsp.ac + 180);
759
+ hsp.cusp[1] = sweDegnorm(hsp.ac - 15);
760
+ for (i = 2; i <= 12; i++)
761
+ hsp.cusp[i] = sweDegnorm(hsp.cusp[1] + (i - 1) * 30);
762
+ if (hsp.doHspeed) {
763
+ for (i = 1; i <= 12; i++) hsp.cuspSpeed[i] = hsp.acSpeed;
764
+ }
765
+ break;
766
+ }
767
+ case 'W': { /* Whole sign */
768
+ acmc = sweDifdeg2n(hsp.ac, hsp.mc);
769
+ if (acmc < 0) {
770
+ hsp.ac = sweDegnorm(hsp.ac + 180);
771
+ hsp.cusp[1] = hsp.ac;
772
+ }
773
+ hsp.cusp[1] = hsp.ac - (hsp.ac % 30);
774
+ for (i = 2; i <= 12; i++)
775
+ hsp.cusp[i] = sweDegnorm(hsp.cusp[1] + (i - 1) * 30);
776
+ break;
777
+ }
778
+ case 'X': { /* Meridian/axial rotation */
779
+ a = th;
780
+ for (i = 1; i <= 12; i++) {
781
+ let j = i + 10;
782
+ if (j > 12) j -= 12;
783
+ a = sweDegnorm(a + 30);
784
+ if (Math.abs(a - 90) > VERY_SMALL && Math.abs(a - 270) > VERY_SMALL) {
785
+ tant = tand(a);
786
+ hsp.cusp[j] = atand(tant / cose);
787
+ if (a > 90 && a <= 270)
788
+ hsp.cusp[j] = sweDegnorm(hsp.cusp[j] + 180);
789
+ } else {
790
+ hsp.cusp[j] = Math.abs(a - 90) <= VERY_SMALL ? 90 : 270;
791
+ }
792
+ hsp.cusp[j] = sweDegnorm(hsp.cusp[j]);
793
+ }
794
+ acmc = sweDifdeg2n(hsp.ac, hsp.mc);
795
+ if (acmc < 0) hsp.ac = sweDegnorm(hsp.ac + 180);
796
+ hsp.doInterpol = hsp.doHspeed;
797
+ break;
798
+ }
799
+ case 'M': { /* Morinus */
800
+ a = th;
801
+ const x3 = [0, 0, 0];
802
+ for (i = 1; i <= 12; i++) {
803
+ let j = i + 10;
804
+ if (j > 12) j -= 12;
805
+ a = sweDegnorm(a + 30);
806
+ x3[0] = a;
807
+ x3[1] = 0;
808
+ sweCotrans(x3, x3, ekl);
809
+ hsp.cusp[j] = x3[0];
810
+ }
811
+ acmc = sweDifdeg2n(hsp.ac, hsp.mc);
812
+ if (acmc < 0) hsp.ac = sweDegnorm(hsp.ac + 180);
813
+ hsp.doInterpol = hsp.doHspeed;
814
+ break;
815
+ }
816
+ case 'F': { /* Carter poli-equatorial */
817
+ acmc = sweDifdeg2n(hsp.ac, hsp.mc);
818
+ if (acmc < 0) {
819
+ hsp.ac = sweDegnorm(hsp.ac + 180);
820
+ hsp.cusp[1] = hsp.ac;
821
+ }
822
+ const x3 = [hsp.ac, 0, 0];
823
+ sweCotrans(x3, x3, -ekl);
824
+ a = x3[0];
825
+ for (i = 2; i <= 12; i++) {
826
+ if (i <= 3 || i >= 10) {
827
+ const ra = sweDegnorm(a + (i - 1) * 30);
828
+ if (Math.abs(ra - 90) > VERY_SMALL && Math.abs(ra - 270) > VERY_SMALL) {
829
+ tant = tand(ra);
830
+ hsp.cusp[i] = atand(tant / cose);
831
+ if (ra > 90 && ra <= 270)
832
+ hsp.cusp[i] = sweDegnorm(hsp.cusp[i] + 180);
833
+ } else {
834
+ hsp.cusp[i] = Math.abs(ra - 90) <= VERY_SMALL ? 90 : 270;
835
+ }
836
+ hsp.cusp[i] = sweDegnorm(hsp.cusp[i]);
837
+ }
838
+ }
839
+ hsp.doInterpol = hsp.doHspeed;
840
+ break;
841
+ }
842
+ case 'B': { /* Alcabitius */
843
+ acmc = sweDifdeg2n(hsp.ac, hsp.mc);
844
+ if (acmc < 0) {
845
+ hsp.ac = sweDegnorm(hsp.ac + 180);
846
+ hsp.cusp[1] = hsp.ac;
847
+ acmc = sweDifdeg2n(hsp.ac, hsp.mc);
848
+ }
849
+ const dek = asind(sind(hsp.ac) * sine);
850
+ let r = -tanfi * tand(dek);
851
+ if (r > 1) r = 1;
852
+ if (r < -1) r = -1;
853
+ const sda = acosd(r);
854
+ const sna = 180 - sda;
855
+ const sd3 = sda / 3;
856
+ const sn3 = sna / 3;
857
+ rectasc = sweDegnorm(th + sd3);
858
+ hsp.cusp[11] = asc1(rectasc, 0, sine, cose);
859
+ rectasc = sweDegnorm(th + 2 * sd3);
860
+ hsp.cusp[12] = asc1(rectasc, 0, sine, cose);
861
+ rectasc = sweDegnorm(th + 180 - 2 * sn3);
862
+ hsp.cusp[2] = asc1(rectasc, 0, sine, cose);
863
+ rectasc = sweDegnorm(th + 180 - sn3);
864
+ hsp.cusp[3] = asc1(rectasc, 0, sine, cose);
865
+ hsp.doInterpol = hsp.doHspeed;
866
+ break;
867
+ }
868
+ case 'G': { /* 36 Gauquelin sectors */
869
+ for (i = 1; i <= 36; i++) {
870
+ hsp.cusp[i] = 0;
871
+ hsp.cuspSpeed[i] = 0;
872
+ }
873
+ if (Math.abs(fi) >= 90 - ekl) {
874
+ retc = ERR;
875
+ hsp.serr = 'within polar circle, switched to Porphyry';
876
+ doPorphyry = true;
877
+ break;
878
+ }
879
+ a = asind(tand(fi) * tane);
880
+ /* forth/second quarter */
881
+ for (let ih = 2; ih <= 9; ih++) {
882
+ const ih2 = 10 - ih;
883
+ fh1 = atand(sind(a * ih2 / 9) / tane);
884
+ rectasc = sweDegnorm((90 / 9) * ih2 + th);
885
+ tant = tand(asind(sine * sind(asc1(rectasc, fh1, sine, cose))));
886
+ if (Math.abs(tant) < VERY_SMALL) {
887
+ hsp.cusp[ih] = rectasc;
888
+ if (hsp.doHspeed) hsp.cuspSpeed[ih] = hsp.armcSpeed;
889
+ } else {
890
+ f = atand(sind(asind(tanfi * tant) * ih2 / 9) / tant);
891
+ hsp.cusp[ih] = asc1(rectasc, f, sine, cose);
892
+ cuspsv = 0;
893
+ let ii: number;
894
+ for (ii = 1; ii <= niterMax; ii++) {
895
+ tant = tand(asind(sine * sind(hsp.cusp[ih])));
896
+ if (Math.abs(tant) < VERY_SMALL) {
897
+ hsp.cusp[ih] = rectasc;
898
+ if (hsp.doHspeed) hsp.cuspSpeed[ih] = hsp.armcSpeed;
899
+ break;
900
+ }
901
+ f = atand(sind(asind(tanfi * tant) * ih2 / 9) / tant);
902
+ hsp.cusp[ih] = asc1(rectasc, f, sine, cose);
903
+ if (ii > 1 && Math.abs(sweDifdeg2n(hsp.cusp[ih], cuspsv)) < VERY_SMALL_PLAC_ITER)
904
+ break;
905
+ cuspsv = hsp.cusp[ih];
906
+ }
907
+ if (ii >= niterMax) {
908
+ retc = ERR;
909
+ hsp.serr = 'very close to polar circle, switched to Porphyry';
910
+ doPorphyry = true;
911
+ break;
912
+ }
913
+ if (hsp.doHspeed) hsp.cuspSpeed[ih] = ascDash(rectasc, f, sine, cose);
914
+ }
915
+ if (doPorphyry) break;
916
+ hsp.cusp[ih + 18] = sweDegnorm(hsp.cusp[ih] + 180);
917
+ if (hsp.doHspeed) hsp.cuspSpeed[ih + 18] = hsp.cuspSpeed[ih];
918
+ }
919
+ if (!doPorphyry) {
920
+ /* first/third quarter */
921
+ for (let ih = 29; ih <= 36; ih++) {
922
+ const ih2 = ih - 28;
923
+ fh1 = atand(sind(a * ih2 / 9) / tane);
924
+ rectasc = sweDegnorm(180 - ih2 * 90 / 9 + th);
925
+ tant = tand(asind(sine * sind(asc1(rectasc, fh1, sine, cose))));
926
+ if (Math.abs(tant) < VERY_SMALL) {
927
+ hsp.cusp[ih] = rectasc;
928
+ if (hsp.doHspeed) hsp.cuspSpeed[ih] = hsp.armcSpeed;
929
+ } else {
930
+ f = atand(sind(asind(tanfi * tant) * ih2 / 9) / tant);
931
+ hsp.cusp[ih] = asc1(rectasc, f, sine, cose);
932
+ cuspsv = 0;
933
+ let ii: number;
934
+ for (ii = 1; ii <= niterMax; ii++) {
935
+ tant = tand(asind(sine * sind(hsp.cusp[ih])));
936
+ if (Math.abs(tant) < VERY_SMALL) {
937
+ hsp.cusp[ih] = rectasc;
938
+ if (hsp.doHspeed) hsp.cuspSpeed[ih] = hsp.armcSpeed;
939
+ break;
940
+ }
941
+ f = atand(sind(asind(tanfi * tant) * ih2 / 9) / tant);
942
+ hsp.cusp[ih] = asc1(rectasc, f, sine, cose);
943
+ if (ii > 1 && Math.abs(sweDifdeg2n(hsp.cusp[ih], cuspsv)) < VERY_SMALL_PLAC_ITER)
944
+ break;
945
+ cuspsv = hsp.cusp[ih];
946
+ }
947
+ if (ii >= niterMax) {
948
+ retc = ERR;
949
+ hsp.serr = 'very close to polar circle, switched to Porphyry';
950
+ doPorphyry = true;
951
+ break;
952
+ }
953
+ if (hsp.doHspeed) hsp.cuspSpeed[ih] = ascDash(rectasc, f, sine, cose);
954
+ }
955
+ if (doPorphyry) break;
956
+ hsp.cusp[ih - 18] = sweDegnorm(hsp.cusp[ih] + 180);
957
+ if (hsp.doHspeed) hsp.cuspSpeed[ih - 18] = hsp.cuspSpeed[ih];
958
+ }
959
+ }
960
+ if (!doPorphyry) {
961
+ hsp.cusp[1] = hsp.ac;
962
+ hsp.cusp[10] = hsp.mc;
963
+ hsp.cusp[19] = sweDegnorm(hsp.ac + 180);
964
+ hsp.cusp[28] = sweDegnorm(hsp.mc + 180);
965
+ if (hsp.doHspeed) {
966
+ hsp.cuspSpeed[1] = hsp.acSpeed;
967
+ hsp.cuspSpeed[10] = hsp.mcSpeed;
968
+ hsp.cuspSpeed[19] = hsp.acSpeed;
969
+ hsp.cuspSpeed[28] = hsp.mcSpeed;
970
+ }
971
+ }
972
+ break;
973
+ }
974
+ case 'U': { /* Krusinski-Pisa */
975
+ acmc = sweDifdeg2n(hsp.ac, hsp.mc);
976
+ if (acmc < 0) hsp.ac = sweDegnorm(hsp.ac + 180);
977
+ const xk = [hsp.ac, 0, 1];
978
+ sweCotrans(xk, xk, -ekl);
979
+ xk[0] = xk[0] - (th - 90);
980
+ sweCotrans(xk, xk, -(90 - fi));
981
+ const krHorizonLon = xk[0];
982
+ xk[0] = 0;
983
+ sweCotrans(xk, xk, -90);
984
+ for (i = 0; i < 6; i++) {
985
+ xk[0] = 30.0 * i;
986
+ xk[1] = 0;
987
+ sweCotrans(xk, xk, 90);
988
+ xk[0] = xk[0] + krHorizonLon;
989
+ sweCotrans(xk, xk, 90 - fi);
990
+ xk[0] = sweDegnorm(xk[0] + (th - 90));
991
+ hsp.cusp[i + 1] = atand(tand(xk[0]) / cosd(ekl));
992
+ if (xk[0] > 90 && xk[0] <= 270)
993
+ hsp.cusp[i + 1] = sweDegnorm(hsp.cusp[i + 1] + 180);
994
+ hsp.cusp[i + 1] = sweDegnorm(hsp.cusp[i + 1]);
995
+ hsp.cusp[i + 7] = sweDegnorm(hsp.cusp[i + 1] + 180);
996
+ }
997
+ break;
998
+ }
999
+ case 'Y': { /* APC houses */
1000
+ for (i = 1; i <= 12; i++) {
1001
+ hsp.cusp[i] = apcSector(i, fi * DEGTORAD, ekl * DEGTORAD, th * DEGTORAD);
1002
+ }
1003
+ hsp.cusp[10] = hsp.mc;
1004
+ hsp.cusp[4] = sweDegnorm(hsp.mc + 180);
1005
+ if (Math.abs(fi) >= 90 - ekl) {
1006
+ acmc = sweDifdeg2n(hsp.ac, hsp.mc);
1007
+ if (acmc < 0) {
1008
+ hsp.ac = sweDegnorm(hsp.ac + 180);
1009
+ hsp.mc = sweDegnorm(hsp.mc + 180);
1010
+ for (i = 1; i <= 12; i++)
1011
+ hsp.cusp[i] = sweDegnorm(hsp.cusp[i] + 180);
1012
+ }
1013
+ }
1014
+ hsp.doInterpol = hsp.doHspeed;
1015
+ break;
1016
+ }
1017
+ default: { /* Placidus (default) */
1018
+ if (Math.abs(fi) >= 90 - ekl) {
1019
+ retc = ERR;
1020
+ hsp.serr = 'within polar circle, switched to Porphyry';
1021
+ doPorphyry = true;
1022
+ break;
1023
+ }
1024
+ a = asind(tand(fi) * tane);
1025
+ fh1 = atand(sind(a / 3) / tane);
1026
+ fh2 = atand(sind(a * 2 / 3) / tane);
1027
+ /* house 11 */
1028
+ rectasc = sweDegnorm(30 + th);
1029
+ tant = tand(asind(sine * sind(asc1(rectasc, fh1, sine, cose))));
1030
+ let ih = 11;
1031
+ if (Math.abs(tant) < VERY_SMALL) {
1032
+ hsp.cusp[ih] = rectasc;
1033
+ if (hsp.doHspeed) hsp.cuspSpeed[ih] = hsp.armcSpeed;
1034
+ } else {
1035
+ f = atand(sind(asind(tanfi * tant) / 3) / tant);
1036
+ hsp.cusp[ih] = asc1(rectasc, f, sine, cose);
1037
+ cuspsv = 0;
1038
+ let ii: number;
1039
+ for (ii = 1; ii <= niterMax; ii++) {
1040
+ tant = tand(asind(sine * sind(hsp.cusp[ih])));
1041
+ if (Math.abs(tant) < VERY_SMALL) {
1042
+ hsp.cusp[ih] = rectasc;
1043
+ if (hsp.doHspeed) hsp.cuspSpeed[ih] = hsp.armcSpeed;
1044
+ break;
1045
+ }
1046
+ f = atand(sind(asind(tanfi * tant) / 3) / tant);
1047
+ hsp.cusp[ih] = asc1(rectasc, f, sine, cose);
1048
+ if (ii > 1 && Math.abs(sweDifdeg2n(hsp.cusp[ih], cuspsv)) < VERY_SMALL_PLAC_ITER)
1049
+ break;
1050
+ cuspsv = hsp.cusp[ih];
1051
+ }
1052
+ if (ii >= niterMax) {
1053
+ retc = ERR;
1054
+ hsp.serr = 'very close to polar circle, switched to Porphyry';
1055
+ doPorphyry = true;
1056
+ break;
1057
+ }
1058
+ if (hsp.doHspeed) hsp.cuspSpeed[ih] = ascDash(rectasc, f, sine, cose);
1059
+ }
1060
+ if (doPorphyry) break;
1061
+ /* house 12 */
1062
+ rectasc = sweDegnorm(60 + th);
1063
+ tant = tand(asind(sine * sind(asc1(rectasc, fh2, sine, cose))));
1064
+ ih = 12;
1065
+ if (Math.abs(tant) < VERY_SMALL) {
1066
+ hsp.cusp[ih] = rectasc;
1067
+ if (hsp.doHspeed) hsp.cuspSpeed[ih] = hsp.armcSpeed;
1068
+ } else {
1069
+ f = atand(sind(asind(tanfi * tant) / 1.5) / tant);
1070
+ hsp.cusp[ih] = asc1(rectasc, f, sine, cose);
1071
+ cuspsv = 0;
1072
+ let ii: number;
1073
+ for (ii = 1; ii <= niterMax; ii++) {
1074
+ tant = tand(asind(sine * sind(hsp.cusp[ih])));
1075
+ if (Math.abs(tant) < VERY_SMALL) {
1076
+ hsp.cusp[ih] = rectasc;
1077
+ if (hsp.doHspeed) hsp.cuspSpeed[ih] = hsp.armcSpeed;
1078
+ break;
1079
+ }
1080
+ f = atand(sind(asind(tanfi * tant) / 1.5) / tant);
1081
+ hsp.cusp[ih] = asc1(rectasc, f, sine, cose);
1082
+ if (ii > 1 && Math.abs(sweDifdeg2n(hsp.cusp[ih], cuspsv)) < VERY_SMALL_PLAC_ITER)
1083
+ break;
1084
+ cuspsv = hsp.cusp[ih];
1085
+ }
1086
+ if (ii >= niterMax) {
1087
+ retc = ERR;
1088
+ hsp.serr = 'very close to polar circle, switched to Porphyry';
1089
+ doPorphyry = true;
1090
+ break;
1091
+ }
1092
+ if (hsp.doHspeed) hsp.cuspSpeed[ih] = ascDash(rectasc, f, sine, cose);
1093
+ }
1094
+ if (doPorphyry) break;
1095
+ /* house 2 */
1096
+ rectasc = sweDegnorm(120 + th);
1097
+ tant = tand(asind(sine * sind(asc1(rectasc, fh2, sine, cose))));
1098
+ ih = 2;
1099
+ if (Math.abs(tant) < VERY_SMALL) {
1100
+ hsp.cusp[ih] = rectasc;
1101
+ if (hsp.doHspeed) hsp.cuspSpeed[ih] = hsp.armcSpeed;
1102
+ } else {
1103
+ f = atand(sind(asind(tanfi * tant) / 1.5) / tant);
1104
+ hsp.cusp[ih] = asc1(rectasc, f, sine, cose);
1105
+ cuspsv = 0;
1106
+ let ii: number;
1107
+ for (ii = 1; ii <= niterMax; ii++) {
1108
+ tant = tand(asind(sine * sind(hsp.cusp[ih])));
1109
+ if (Math.abs(tant) < VERY_SMALL) {
1110
+ hsp.cusp[ih] = rectasc;
1111
+ if (hsp.doHspeed) hsp.cuspSpeed[ih] = hsp.armcSpeed;
1112
+ break;
1113
+ }
1114
+ f = atand(sind(asind(tanfi * tant) / 1.5) / tant);
1115
+ hsp.cusp[ih] = asc1(rectasc, f, sine, cose);
1116
+ if (ii > 1 && Math.abs(sweDifdeg2n(hsp.cusp[ih], cuspsv)) < VERY_SMALL_PLAC_ITER)
1117
+ break;
1118
+ cuspsv = hsp.cusp[ih];
1119
+ }
1120
+ if (ii >= niterMax) {
1121
+ retc = ERR;
1122
+ hsp.serr = 'very close to polar circle, switched to Porphyry';
1123
+ doPorphyry = true;
1124
+ break;
1125
+ }
1126
+ if (hsp.doHspeed) hsp.cuspSpeed[ih] = ascDash(rectasc, f, sine, cose);
1127
+ }
1128
+ if (doPorphyry) break;
1129
+ /* house 3 */
1130
+ rectasc = sweDegnorm(150 + th);
1131
+ tant = tand(asind(sine * sind(asc1(rectasc, fh1, sine, cose))));
1132
+ ih = 3;
1133
+ if (Math.abs(tant) < VERY_SMALL) {
1134
+ hsp.cusp[ih] = rectasc;
1135
+ if (hsp.doHspeed) hsp.cuspSpeed[ih] = hsp.armcSpeed;
1136
+ } else {
1137
+ f = atand(sind(asind(tanfi * tant) / 3) / tant);
1138
+ hsp.cusp[ih] = asc1(rectasc, f, sine, cose);
1139
+ cuspsv = 0;
1140
+ let ii: number;
1141
+ for (ii = 1; ii <= niterMax; ii++) {
1142
+ tant = tand(asind(sine * sind(hsp.cusp[ih])));
1143
+ if (Math.abs(tant) < VERY_SMALL) {
1144
+ hsp.cusp[ih] = rectasc;
1145
+ if (hsp.doHspeed) hsp.cuspSpeed[ih] = hsp.armcSpeed;
1146
+ break;
1147
+ }
1148
+ f = atand(sind(asind(tanfi * tant) / 3) / tant);
1149
+ hsp.cusp[ih] = asc1(rectasc, f, sine, cose);
1150
+ if (ii > 1 && Math.abs(sweDifdeg2n(hsp.cusp[ih], cuspsv)) < VERY_SMALL_PLAC_ITER)
1151
+ break;
1152
+ cuspsv = hsp.cusp[ih];
1153
+ }
1154
+ if (ii >= niterMax) {
1155
+ retc = ERR;
1156
+ hsp.serr = 'very close to polar circle, switched to Porphyry';
1157
+ doPorphyry = true;
1158
+ break;
1159
+ }
1160
+ if (hsp.doHspeed) hsp.cuspSpeed[ih] = ascDash(rectasc, f, sine, cose);
1161
+ }
1162
+ break;
1163
+ }
1164
+ } /* end switch */
1165
+
1166
+ /* Porphyry fallback (replaces C goto porphyry) */
1167
+ if (doPorphyry) {
1168
+ acmc = sweDifdeg2n(hsp.ac, hsp.mc);
1169
+ if (acmc < 0) {
1170
+ hsp.ac = sweDegnorm(hsp.ac + 180);
1171
+ hsp.cusp[1] = hsp.ac;
1172
+ acmc = sweDifdeg2n(hsp.ac, hsp.mc);
1173
+ }
1174
+ hsp.cusp[1] = hsp.ac;
1175
+ hsp.cusp[10] = hsp.mc;
1176
+ hsp.cusp[2] = sweDegnorm(hsp.ac + (180 - acmc) / 3);
1177
+ hsp.cusp[3] = sweDegnorm(hsp.ac + (180 - acmc) / 3 * 2);
1178
+ hsp.cusp[11] = sweDegnorm(hsp.mc + acmc / 3);
1179
+ hsp.cusp[12] = sweDegnorm(hsp.mc + acmc / 3 * 2);
1180
+ if (hsp.doHspeed) {
1181
+ const q1Speed = hsp.acSpeed - hsp.mcSpeed;
1182
+ hsp.cuspSpeed[1] = hsp.acSpeed;
1183
+ hsp.cuspSpeed[10] = hsp.mcSpeed;
1184
+ hsp.cuspSpeed[2] = hsp.acSpeed - q1Speed / 3;
1185
+ hsp.cuspSpeed[3] = hsp.acSpeed - q1Speed / 3 * 2;
1186
+ hsp.cuspSpeed[11] = hsp.acSpeed + q1Speed / 3;
1187
+ hsp.cuspSpeed[12] = hsp.acSpeed + q1Speed / 3 * 2;
1188
+ }
1189
+ }
1190
+
1191
+ /* Also handle 'O' case that fell through to doPorphyry with retc=OK */
1192
+ if (hsy === 'O' && !doPorphyry) {
1193
+ acmc = sweDifdeg2n(hsp.ac, hsp.mc);
1194
+ if (acmc < 0) {
1195
+ hsp.ac = sweDegnorm(hsp.ac + 180);
1196
+ hsp.cusp[1] = hsp.ac;
1197
+ acmc = sweDifdeg2n(hsp.ac, hsp.mc);
1198
+ }
1199
+ hsp.cusp[1] = hsp.ac;
1200
+ hsp.cusp[10] = hsp.mc;
1201
+ hsp.cusp[2] = sweDegnorm(hsp.ac + (180 - acmc) / 3);
1202
+ hsp.cusp[3] = sweDegnorm(hsp.ac + (180 - acmc) / 3 * 2);
1203
+ hsp.cusp[11] = sweDegnorm(hsp.mc + acmc / 3);
1204
+ hsp.cusp[12] = sweDegnorm(hsp.mc + acmc / 3 * 2);
1205
+ if (hsp.doHspeed) {
1206
+ const q1Speed = hsp.acSpeed - hsp.mcSpeed;
1207
+ hsp.cuspSpeed[1] = hsp.acSpeed;
1208
+ hsp.cuspSpeed[10] = hsp.mcSpeed;
1209
+ hsp.cuspSpeed[2] = hsp.acSpeed - q1Speed / 3;
1210
+ hsp.cuspSpeed[3] = hsp.acSpeed - q1Speed / 3 * 2;
1211
+ hsp.cuspSpeed[11] = hsp.acSpeed + q1Speed / 3;
1212
+ hsp.cuspSpeed[12] = hsp.acSpeed + q1Speed / 3 * 2;
1213
+ }
1214
+ }
1215
+
1216
+ /* cusps 4-9 from 10-3 (opposite) */
1217
+ if (hsy !== 'G' && hsy !== 'Y' && hsy.toUpperCase() !== 'I') {
1218
+ hsp.cusp[4] = sweDegnorm(hsp.cusp[10] + 180);
1219
+ hsp.cusp[5] = sweDegnorm(hsp.cusp[11] + 180);
1220
+ hsp.cusp[6] = sweDegnorm(hsp.cusp[12] + 180);
1221
+ hsp.cusp[7] = sweDegnorm(hsp.cusp[1] + 180);
1222
+ hsp.cusp[8] = sweDegnorm(hsp.cusp[2] + 180);
1223
+ hsp.cusp[9] = sweDegnorm(hsp.cusp[3] + 180);
1224
+ if (hsp.doHspeed && !hsp.doInterpol) {
1225
+ hsp.cuspSpeed[4] = hsp.cuspSpeed[10];
1226
+ hsp.cuspSpeed[5] = hsp.cuspSpeed[11];
1227
+ hsp.cuspSpeed[6] = hsp.cuspSpeed[12];
1228
+ hsp.cuspSpeed[7] = hsp.cuspSpeed[1];
1229
+ hsp.cuspSpeed[8] = hsp.cuspSpeed[2];
1230
+ hsp.cuspSpeed[9] = hsp.cuspSpeed[3];
1231
+ }
1232
+ }
1233
+
1234
+ /* vertex */
1235
+ if (fi >= 0) f = 90 - fi;
1236
+ else f = -90 - fi;
1237
+ hsp.vertex = asc1(th - 90, f, sine, cose);
1238
+ if (hsp.doSpeed) hsp.vertexSpeed = ascDash(th - 90, f, sine, cose);
1239
+ if (Math.abs(fi) <= ekl) {
1240
+ vemc = sweDifdeg2n(hsp.vertex, hsp.mc);
1241
+ if (vemc > 0) hsp.vertex = sweDegnorm(hsp.vertex + 180);
1242
+ }
1243
+
1244
+ /* equatorial ascendant */
1245
+ const th2 = sweDegnorm(th + 90);
1246
+ if (Math.abs(th2 - 90) > VERY_SMALL && Math.abs(th2 - 270) > VERY_SMALL) {
1247
+ tant = tand(th2);
1248
+ hsp.equasc = atand(tant / cose);
1249
+ if (th2 > 90 && th2 <= 270)
1250
+ hsp.equasc = sweDegnorm(hsp.equasc + 180);
1251
+ } else {
1252
+ hsp.equasc = Math.abs(th2 - 90) <= VERY_SMALL ? 90 : 270;
1253
+ }
1254
+ hsp.equasc = sweDegnorm(hsp.equasc);
1255
+ if (hsp.doSpeed) hsp.equascSpeed = ascDash(th + 90, 0, sine, cose);
1256
+
1257
+ /* co-ascendant W. Koch */
1258
+ hsp.coasc1 = sweDegnorm(asc1(th - 90, fi, sine, cose) + 180);
1259
+ if (hsp.doSpeed) hsp.coasc1Speed = ascDash(th - 90, fi, sine, cose);
1260
+
1261
+ /* co-ascendant M. Munkasey */
1262
+ if (fi >= 0) {
1263
+ hsp.coasc2 = asc1(th + 90, 90 - fi, sine, cose);
1264
+ if (hsp.doSpeed) hsp.coasc2Speed = ascDash(th + 90, 90 - fi, sine, cose);
1265
+ } else {
1266
+ hsp.coasc2 = asc1(th + 90, -90 - fi, sine, cose);
1267
+ if (hsp.doSpeed) hsp.coasc2Speed = ascDash(th + 90, -90 - fi, sine, cose);
1268
+ }
1269
+
1270
+ /* polar ascendant M. Munkasey */
1271
+ hsp.polasc = asc1(th - 90, fi, sine, cose);
1272
+ if (hsp.doSpeed) hsp.polascSpeed = ascDash(th - 90, fi, sine, cose);
1273
+
1274
+ return retc;
1275
+ }
1276
+
1277
+ /* ==================================================================
1278
+ * sweHousesArmcEx2 - core entry point
1279
+ * ================================================================== */
1280
+
1281
+ export function sweHousesArmcEx2(
1282
+ armc: number, geolat: number, eps: number, hsys: string,
1283
+ cusp: number[], ascmc: number[],
1284
+ cuspSpeed: number[] | null, ascmcSpeed: number[] | null,
1285
+ serr: { value: string } | null,
1286
+ ): number {
1287
+ const h = createHouses();
1288
+ let retc = 0;
1289
+ let ito = hsys.toUpperCase() === 'G' ? 36 : 12;
1290
+ armc = sweDegnorm(armc);
1291
+ h.doSpeed = false;
1292
+ h.doHspeed = false;
1293
+ if (ascmcSpeed !== null || cuspSpeed !== null)
1294
+ h.doSpeed = true;
1295
+ if (cuspSpeed !== null)
1296
+ h.doHspeed = true;
1297
+ if (hsys.toUpperCase() === 'I') {
1298
+ if (ascmc[9] === 99) {
1299
+ h.sundec = 0;
1300
+ } else {
1301
+ h.sundec = ascmc[9];
1302
+ }
1303
+ if (h.sundec < -24 || h.sundec > 24) {
1304
+ if (serr) serr.value = 'House system I (Sunshine) needs valid Sun declination in ascmc[9]';
1305
+ return ERR;
1306
+ }
1307
+ }
1308
+ retc = calcH(armc, geolat, eps, hsys, h);
1309
+ cusp[0] = 0;
1310
+ if (h.doHspeed && cuspSpeed) cuspSpeed[0] = 0;
1311
+ if (retc < 0) {
1312
+ ito = 12;
1313
+ if (serr) serr.value = h.serr;
1314
+ }
1315
+ for (let i = 1; i <= ito; i++) {
1316
+ cusp[i] = h.cusp[i];
1317
+ if (h.doHspeed && cuspSpeed) cuspSpeed[i] = h.cuspSpeed[i];
1318
+ }
1319
+ ascmc[0] = h.ac;
1320
+ ascmc[1] = h.mc;
1321
+ ascmc[2] = armc;
1322
+ ascmc[3] = h.vertex;
1323
+ ascmc[4] = h.equasc;
1324
+ ascmc[5] = h.coasc1;
1325
+ ascmc[6] = h.coasc2;
1326
+ ascmc[7] = h.polasc;
1327
+ for (let i = SE_NASCMC; i < 10; i++) ascmc[i] = 0;
1328
+ if (hsys.toUpperCase() === 'I') ascmc[9] = h.sundec;
1329
+ if (h.doSpeed && ascmcSpeed !== null) {
1330
+ ascmcSpeed[0] = h.acSpeed;
1331
+ ascmcSpeed[1] = h.mcSpeed;
1332
+ ascmcSpeed[2] = h.armcSpeed;
1333
+ ascmcSpeed[3] = h.vertexSpeed;
1334
+ ascmcSpeed[4] = h.equascSpeed;
1335
+ ascmcSpeed[5] = h.coasc1Speed;
1336
+ ascmcSpeed[6] = h.coasc2Speed;
1337
+ ascmcSpeed[7] = h.polascSpeed;
1338
+ for (let i = SE_NASCMC; i < 10; i++) ascmcSpeed[i] = 0;
1339
+ }
1340
+ if (h.doInterpol && cuspSpeed) {
1341
+ const dt = 1.0 / 86400;
1342
+ const darmc = dt * ARMCS;
1343
+ const hm1 = createHouses();
1344
+ const hp1 = createHouses();
1345
+ hm1.doSpeed = false; hm1.doHspeed = false;
1346
+ hp1.doSpeed = false; hp1.doHspeed = false;
1347
+ if (hsys.toUpperCase() === 'I') {
1348
+ hm1.sundec = h.sundec;
1349
+ hp1.sundec = h.sundec;
1350
+ }
1351
+ const rm1 = calcH(armc - darmc, geolat, eps, hsys, hm1);
1352
+ const rp1 = calcH(armc + darmc, geolat, eps, hsys, hp1);
1353
+ if (rp1 >= 0 && rm1 >= 0) {
1354
+ let dtUsed = dt;
1355
+ if (Math.abs(sweDifdeg2n(hp1.ac, h.ac)) > 90) {
1356
+ // use only lower interval
1357
+ for (let i = 1; i <= 12; i++) hp1.cusp[i] = h.cusp[i];
1358
+ dtUsed = dt / 2;
1359
+ } else if (Math.abs(sweDifdeg2n(hm1.ac, h.ac)) > 90) {
1360
+ for (let i = 1; i <= 12; i++) hm1.cusp[i] = h.cusp[i];
1361
+ dtUsed = dt / 2;
1362
+ }
1363
+ for (let i = 1; i <= 12; i++) {
1364
+ const dx = sweDifdeg2n(hp1.cusp[i], hm1.cusp[i]);
1365
+ cuspSpeed[i] = dx / 2 / dtUsed;
1366
+ }
1367
+ }
1368
+ }
1369
+ return retc;
1370
+ }
1371
+
1372
+ /** Simple wrapper */
1373
+ export function sweHousesArmc(
1374
+ armc: number, geolat: number, eps: number, hsys: string,
1375
+ cusp: number[], ascmc: number[],
1376
+ ): number {
1377
+ return sweHousesArmcEx2(armc, geolat, eps, hsys, cusp, ascmc, null, null, null);
1378
+ }
1379
+
1380
+ /* ==================================================================
1381
+ * Public API: sweHouses, sweHousesEx, sweHousesEx2
1382
+ * ================================================================== */
1383
+
1384
+ export function sweHouses(
1385
+ swed: SweData, tjdUt: number, geolat: number, geolon: number, hsys: string,
1386
+ cusp: number[], ascmc: number[],
1387
+ ): number {
1388
+ swiInitSwedIfStart(swed);
1389
+ const tjde = tjdUt + sweDeltatEx(tjdUt, -1, swed);
1390
+ const epsRad = swiEpsiln(tjde, 0, swed);
1391
+ const epsDeg = epsRad * RADTODEG;
1392
+ const nutlo = [0, 0];
1393
+ swiNutation(tjde, 0, nutlo, swed);
1394
+ nutlo[0] *= RADTODEG;
1395
+ nutlo[1] *= RADTODEG;
1396
+ const armc = sweDegnorm(sweSidtime0(swed, tjdUt, epsDeg + nutlo[1], nutlo[0]) * 15 + geolon);
1397
+ if (hsys.toUpperCase() === 'I') {
1398
+ const flags = SEFLG_SPEED | SEFLG_EQUATORIAL;
1399
+ const result = sweCalcUt(swed, tjdUt, SE_SUN, flags);
1400
+ if (result.flags < 0) {
1401
+ sweHousesArmcEx2(armc, geolat, epsDeg + nutlo[1], 'O', cusp, ascmc, null, null, null);
1402
+ return ERR;
1403
+ }
1404
+ ascmc[9] = result.xx[1]; // declination (equatorial latitude)
1405
+ }
1406
+ return sweHousesArmcEx2(armc, geolat, epsDeg + nutlo[1], hsys, cusp, ascmc, null, null, null);
1407
+ }
1408
+
1409
+ export function sweHousesEx(
1410
+ swed: SweData, tjdUt: number, iflag: number,
1411
+ geolat: number, geolon: number, hsys: string,
1412
+ cusp: number[], ascmc: number[],
1413
+ ): number {
1414
+ return sweHousesEx2(swed, tjdUt, iflag, geolat, geolon, hsys, cusp, ascmc, null, null, null);
1415
+ }
1416
+
1417
+ export function sweHousesEx2(
1418
+ swed: SweData, tjdUt: number, iflag: number,
1419
+ geolat: number, geolon: number, hsys: string,
1420
+ cusp: number[], ascmc: number[],
1421
+ cuspSpeed: number[] | null, ascmcSpeed: number[] | null,
1422
+ serr: { value: string } | null,
1423
+ ): number {
1424
+ swiInitSwedIfStart(swed);
1425
+ let retc = 0;
1426
+ const tjde = tjdUt + sweDeltatEx(tjdUt, iflag, swed);
1427
+ const sip = swed.sidd;
1428
+ const xp = [0, 0, 0, 0, 0, 0];
1429
+ let retcMakr = 0;
1430
+ let ito = hsys.toUpperCase() === 'G' ? 36 : 12;
1431
+ if ((iflag & SEFLG_SIDEREAL) && !swed.ayanaIsSet)
1432
+ sweSetSidMode(swed, SE_SIDM_FAGAN_BRADLEY, 0, 0);
1433
+ const epsMean = swiEpsiln(tjde, 0, swed) * RADTODEG;
1434
+ const nutlo = [0, 0];
1435
+ swiNutation(tjde, 0, nutlo, swed);
1436
+ nutlo[0] *= RADTODEG;
1437
+ nutlo[1] *= RADTODEG;
1438
+ if (iflag & SEFLG_NONUT) {
1439
+ nutlo[0] = 0;
1440
+ nutlo[1] = 0;
1441
+ }
1442
+ let armc = sweDegnorm(sweSidtime0(swed, tjdUt, epsMean + nutlo[1], nutlo[0]) * 15 + geolon);
1443
+ let hsysUsed = hsys;
1444
+ if (hsys.toUpperCase() === 'I') {
1445
+ const flags = SEFLG_SPEED | SEFLG_EQUATORIAL;
1446
+ const result = sweCalcUt(swed, tjdUt, SE_SUN, flags);
1447
+ if (result.flags < 0) {
1448
+ hsysUsed = 'O';
1449
+ retcMakr = ERR;
1450
+ }
1451
+ xp[1] = result.xx[1]; // declination
1452
+ ascmc[9] = xp[1];
1453
+ }
1454
+ if (iflag & SEFLG_SIDEREAL) {
1455
+ if (sip.sidMode & SE_SIDBIT_ECL_T0)
1456
+ retc = siderealHousesEclT0(swed, tjde, armc, epsMean + nutlo[1], nutlo, geolat, hsysUsed, cusp, ascmc, cuspSpeed, ascmcSpeed, serr);
1457
+ else if (sip.sidMode & SE_SIDBIT_SSY_PLANE)
1458
+ retc = siderealHousesSsypl(swed, tjde, armc, epsMean + nutlo[1], nutlo, geolat, hsysUsed, cusp, ascmc, cuspSpeed, ascmcSpeed, serr);
1459
+ else
1460
+ retc = siderealHousesTrad(swed, tjde, iflag, armc, epsMean + nutlo[1], nutlo[0], geolat, hsysUsed, cusp, ascmc, cuspSpeed, ascmcSpeed, serr);
1461
+ } else {
1462
+ retc = sweHousesArmcEx2(armc, geolat, epsMean + nutlo[1], hsysUsed, cusp, ascmc, cuspSpeed, ascmcSpeed, serr);
1463
+ if (hsys.toUpperCase() === 'I') ascmc[9] = xp[1];
1464
+ }
1465
+ if (iflag & SEFLG_RADIANS) {
1466
+ for (let i = 1; i <= ito; i++) cusp[i] *= DEGTORAD;
1467
+ for (let i = 0; i < SE_NASCMC; i++) ascmc[i] *= DEGTORAD;
1468
+ }
1469
+ if (retcMakr < 0) return retcMakr;
1470
+ return retc;
1471
+ }
1472
+
1473
+ /* ==================================================================
1474
+ * Sidereal house methods
1475
+ * ================================================================== */
1476
+
1477
+ function siderealHousesTrad(
1478
+ swed: SweData, tjde: number, iflag: number,
1479
+ armc: number, eps: number, nutl: number, lat: number,
1480
+ hsys: string, cusp: number[], ascmc: number[],
1481
+ cuspSpeed: number[] | null, ascmcSpeed: number[] | null,
1482
+ serr: { value: string } | null,
1483
+ ): number {
1484
+ let retc = OK;
1485
+ const ihs = hsys.toUpperCase();
1486
+ let ihs2 = ihs;
1487
+ const ayRes = sweGetAyanamsaEx(swed, tjde, iflag);
1488
+ const ay = ayRes.daya;
1489
+ const ito = ihs === 'G' ? 36 : 12;
1490
+ if (ihs === 'W') ihs2 = 'E';
1491
+ retc = sweHousesArmcEx2(armc, lat, eps, ihs2, cusp, ascmc, cuspSpeed, ascmcSpeed, serr);
1492
+ for (let i = 1; i <= ito; i++) {
1493
+ cusp[i] = sweDegnorm(cusp[i] - ay);
1494
+ if (ihs === 'W') cusp[i] -= cusp[i] % 30;
1495
+ }
1496
+ if (ihs === 'N') {
1497
+ for (let i = 1; i <= ito; i++) cusp[i] = (i - 1) * 30;
1498
+ }
1499
+ for (let i = 0; i < SE_NASCMC; i++) {
1500
+ if (i === 2) continue; /* armc */
1501
+ ascmc[i] = sweDegnorm(ascmc[i] - ay);
1502
+ }
1503
+ return retc;
1504
+ }
1505
+
1506
+ function siderealHousesEclT0(
1507
+ swed: SweData, tjde: number,
1508
+ armc: number, eps: number, nutlo: number[], lat: number,
1509
+ hsys: string, cusp: number[], ascmc: number[],
1510
+ cuspSpeed: number[] | null, ascmcSpeed: number[] | null,
1511
+ serr: { value: string } | null,
1512
+ ): number {
1513
+ let retc = OK;
1514
+ const sip = swed.sidd;
1515
+ const ito = hsys.toUpperCase() === 'G' ? 36 : 12;
1516
+ const epst0 = swiEpsiln(sip.t0, 0, swed);
1517
+ const x = new Float64Array(6);
1518
+ x[0] = 1; x[4] = 1;
1519
+ swiCoortrf(x, x, -epst0, 0, 0);
1520
+ swiCoortrf(x, x, -epst0, 3, 3);
1521
+ swiPrecess(x, sip.t0, 0, J_TO_J2000, swed);
1522
+ swiPrecess(x, tjde, 0, J2000_TO_J, swed);
1523
+ const xh = new Float64Array(6);
1524
+ for (let i = 0; i < 6; i++) xh[i] = x[i];
1525
+ swiPrecess(xh, sip.t0, 0, J_TO_J2000, swed);
1526
+ swiPrecess(xh, tjde, 0, J2000_TO_J, swed);
1527
+ // x already has the values we need, just overwrite with proper flow
1528
+ x[0] = 1; x[1] = 0; x[2] = 0; x[3] = 0; x[4] = 1; x[5] = 0;
1529
+ swiCoortrf(x, x, -epst0, 0, 0);
1530
+ swiCoortrf(x, x, -epst0, 3, 3);
1531
+ swiPrecess(x, sip.t0, 0, J_TO_J2000, swed);
1532
+ swiPrecess(x, tjde, 0, J2000_TO_J, swed);
1533
+ swiCoortrf(x, x, (eps - nutlo[1]) * DEGTORAD, 0, 0);
1534
+ swiCoortrf(x, x, (eps - nutlo[1]) * DEGTORAD, 3, 3);
1535
+ const xl = new Array(6);
1536
+ for (let i = 0; i < 6; i++) xl[i] = x[i];
1537
+ swiCartpolSp(xl, xl);
1538
+ xl[0] += nutlo[0] * DEGTORAD;
1539
+ swiPolcartSp(xl, xl);
1540
+ for (let i = 0; i < 6; i++) x[i] = xl[i];
1541
+ swiCoortrf(x, x, -eps * DEGTORAD, 0, 0);
1542
+ swiCoortrf(x, x, -eps * DEGTORAD, 3, 3);
1543
+ const xnorm = new Float64Array(3);
1544
+ swiCrossProd(x, new Float64Array([x[3], x[4], x[5]]), xnorm);
1545
+ let rxy = xnorm[0] * xnorm[0] + xnorm[1] * xnorm[1];
1546
+ const c2 = rxy + xnorm[2] * xnorm[2];
1547
+ const rxyz = Math.sqrt(c2);
1548
+ rxy = Math.sqrt(rxy);
1549
+ const epsx = Math.asin(rxy / rxyz) * RADTODEG;
1550
+ if (Math.abs(x[5]) < 1e-15) x[5] = 1e-15;
1551
+ const fac = x[2] / x[5];
1552
+ const sgn = x[5] / Math.abs(x[5]);
1553
+ const xvpx = new Float64Array(3);
1554
+ for (let j = 0; j <= 2; j++)
1555
+ xvpx[j] = (x[j] - fac * x[j + 3]) * sgn;
1556
+ const x2 = new Array(3).fill(0);
1557
+ swiCartpol(xvpx, x2);
1558
+ const dvpx = x2[0] * RADTODEG;
1559
+ const armcx = sweDegnorm(armc - dvpx);
1560
+ retc = sweHousesArmcEx2(armcx, lat, epsx, hsys, cusp, ascmc, cuspSpeed, ascmcSpeed, serr);
1561
+ let dvpxe = Math.acos(swiDotProdUnit(x, xvpx)) * RADTODEG;
1562
+ if (tjde < sip.t0) dvpxe = -dvpxe;
1563
+ for (let i = 1; i <= ito; i++)
1564
+ cusp[i] = sweDegnorm(cusp[i] - dvpxe - sip.ayanT0);
1565
+ for (let i = 0; i <= SE_NASCMC; i++) {
1566
+ if (i === 2) continue;
1567
+ ascmc[i] = sweDegnorm(ascmc[i] - dvpxe - sip.ayanT0);
1568
+ }
1569
+ if (hsys === 'N') {
1570
+ for (let i = 1; i <= ito; i++) cusp[i] = (i - 1) * 30;
1571
+ }
1572
+ return retc;
1573
+ }
1574
+
1575
+ function siderealHousesSsypl(
1576
+ swed: SweData, tjde: number,
1577
+ armc: number, eps: number, nutlo: number[], lat: number,
1578
+ hsys: string, cusp: number[], ascmc: number[],
1579
+ cuspSpeed: number[] | null, ascmcSpeed: number[] | null,
1580
+ serr: { value: string } | null,
1581
+ ): number {
1582
+ let retc = OK;
1583
+ const sip = swed.sidd;
1584
+ const ito = hsys.toUpperCase() === 'G' ? 36 : 12;
1585
+ const eps2000 = swiEpsiln(J2000, 0, swed);
1586
+ const x = new Float64Array(6);
1587
+ x[0] = 1; x[4] = 1;
1588
+ swiCoortrf(x, x, -SSY_PLANE_INCL, 0, 0);
1589
+ swiCoortrf(x, x, -SSY_PLANE_INCL, 3, 3);
1590
+ const xl = new Array(6);
1591
+ for (let i = 0; i < 6; i++) xl[i] = x[i];
1592
+ swiCartpolSp(xl, xl);
1593
+ xl[0] += SSY_PLANE_NODE_E2000;
1594
+ swiPolcartSp(xl, xl);
1595
+ for (let i = 0; i < 6; i++) x[i] = xl[i];
1596
+ swiCoortrf(x, x, -eps2000, 0, 0);
1597
+ swiCoortrf(x, x, -eps2000, 3, 3);
1598
+ swiPrecess(x, tjde, 0, J2000_TO_J, swed);
1599
+ const xp3 = new Float64Array(3);
1600
+ xp3[0] = x[3]; xp3[1] = x[4]; xp3[2] = x[5];
1601
+ swiPrecess(xp3, tjde, 0, J2000_TO_J, swed);
1602
+ x[3] = xp3[0]; x[4] = xp3[1]; x[5] = xp3[2];
1603
+ swiCoortrf(x, x, (eps - nutlo[1]) * DEGTORAD, 0, 0);
1604
+ swiCoortrf(x, x, (eps - nutlo[1]) * DEGTORAD, 3, 3);
1605
+ for (let i = 0; i < 6; i++) xl[i] = x[i];
1606
+ swiCartpolSp(xl, xl);
1607
+ xl[0] += nutlo[0] * DEGTORAD;
1608
+ swiPolcartSp(xl, xl);
1609
+ for (let i = 0; i < 6; i++) x[i] = xl[i];
1610
+ swiCoortrf(x, x, -eps * DEGTORAD, 0, 0);
1611
+ swiCoortrf(x, x, -eps * DEGTORAD, 3, 3);
1612
+ const xnorm = new Float64Array(3);
1613
+ swiCrossProd(x, new Float64Array([x[3], x[4], x[5]]), xnorm);
1614
+ let rxy = xnorm[0] * xnorm[0] + xnorm[1] * xnorm[1];
1615
+ const c2 = rxy + xnorm[2] * xnorm[2];
1616
+ const rxyz = Math.sqrt(c2);
1617
+ rxy = Math.sqrt(rxy);
1618
+ const epsx = Math.asin(rxy / rxyz) * RADTODEG;
1619
+ if (Math.abs(x[5]) < 1e-15) x[5] = 1e-15;
1620
+ const fac = x[2] / x[5];
1621
+ const sgn = x[5] / Math.abs(x[5]);
1622
+ const xvpx = new Float64Array(3);
1623
+ for (let j = 0; j <= 2; j++)
1624
+ xvpx[j] = (x[j] - fac * x[j + 3]) * sgn;
1625
+ const x2arr = new Array(3).fill(0);
1626
+ swiCartpol(xvpx, x2arr);
1627
+ const dvpx = x2arr[0] * RADTODEG;
1628
+ const armcx = sweDegnorm(armc - dvpx);
1629
+ retc = sweHousesArmcEx2(armcx, lat, epsx, hsys, cusp, ascmc, cuspSpeed, ascmcSpeed, serr);
1630
+ let dvpxe = Math.acos(swiDotProdUnit(x, xvpx)) * RADTODEG;
1631
+ dvpxe -= SSY_PLANE_NODE * RADTODEG;
1632
+ /* ayanamsa between t0 and J2000 on solar system plane */
1633
+ const x0 = new Array(3);
1634
+ x0[0] = 1; x0[1] = 0; x0[2] = 0;
1635
+ if (sip.t0 !== J2000) {
1636
+ const x0f = new Float64Array(3);
1637
+ x0f[0] = x0[0]; x0f[1] = x0[1]; x0f[2] = x0[2];
1638
+ swiPrecess(x0f, sip.t0, 0, J_TO_J2000, swed);
1639
+ x0[0] = x0f[0]; x0[1] = x0f[1]; x0[2] = x0f[2];
1640
+ }
1641
+ swiCoortrf(new Float64Array(x0), new Float64Array(x0), eps2000, 0, 0);
1642
+ // The above line modifies x0 in-place since we pass same array
1643
+ // Need to handle differently for number arrays:
1644
+ {
1645
+ const tmp = new Float64Array(3);
1646
+ tmp[0] = x0[0]; tmp[1] = x0[1]; tmp[2] = x0[2];
1647
+ swiCoortrf(tmp, tmp, eps2000);
1648
+ x0[0] = tmp[0]; x0[1] = tmp[1]; x0[2] = tmp[2];
1649
+ }
1650
+ swiCartpol(x0, x0);
1651
+ x0[0] -= SSY_PLANE_NODE_E2000;
1652
+ swiPolcart(x0, x0);
1653
+ {
1654
+ const tmp = new Float64Array(3);
1655
+ tmp[0] = x0[0]; tmp[1] = x0[1]; tmp[2] = x0[2];
1656
+ swiCoortrf(tmp, tmp, SSY_PLANE_INCL);
1657
+ x0[0] = tmp[0]; x0[1] = tmp[1]; x0[2] = tmp[2];
1658
+ }
1659
+ swiCartpol(x0, x0);
1660
+ x0[0] += SSY_PLANE_NODE;
1661
+ const x00 = x0[0] * RADTODEG;
1662
+ for (let i = 1; i <= ito; i++)
1663
+ cusp[i] = sweDegnorm(cusp[i] - dvpxe - sip.ayanT0 - x00);
1664
+ for (let i = 0; i <= SE_NASCMC; i++) {
1665
+ if (i === 2) continue;
1666
+ ascmc[i] = sweDegnorm(ascmc[i] - dvpxe - sip.ayanT0 - x00);
1667
+ }
1668
+ if (hsys === 'N') {
1669
+ for (let i = 1; i <= ito; i++) cusp[i] = (i - 1) * 30;
1670
+ }
1671
+ return retc;
1672
+ }
1673
+
1674
+ /* ==================================================================
1675
+ * sweHouseName
1676
+ * ================================================================== */
1677
+
1678
+ export function sweHouseName(hsys: string): string {
1679
+ let h = hsys;
1680
+ if (h !== 'i') h = h.toUpperCase();
1681
+ switch (h) {
1682
+ case 'A': return 'equal';
1683
+ case 'B': return 'Alcabitius';
1684
+ case 'C': return 'Campanus';
1685
+ case 'D': return 'equal (MC)';
1686
+ case 'E': return 'equal';
1687
+ case 'F': return 'Carter poli-equ.';
1688
+ case 'G': return 'Gauquelin sectors';
1689
+ case 'H': return 'horizon/azimut';
1690
+ case 'I': return 'Sunshine';
1691
+ case 'i': return 'Sunshine/alt.';
1692
+ case 'J': return 'Savard-A';
1693
+ case 'K': return 'Koch';
1694
+ case 'L': return 'Pullen SD';
1695
+ case 'M': return 'Morinus';
1696
+ case 'N': return 'equal/1=Aries';
1697
+ case 'O': return 'Porphyry';
1698
+ case 'Q': return 'Pullen SR';
1699
+ case 'R': return 'Regiomontanus';
1700
+ case 'S': return 'Sripati';
1701
+ case 'T': return 'Polich/Page';
1702
+ case 'U': return 'Krusinski-Pisa-Goelzer';
1703
+ case 'V': return 'equal/Vehlow';
1704
+ case 'W': return 'equal/ whole sign';
1705
+ case 'X': return 'axial rotation system/Meridian houses';
1706
+ case 'Y': return 'APC houses';
1707
+ default: return 'Placidus';
1708
+ }
1709
+ }
1710
+
1711
+ /* ==================================================================
1712
+ * sweHousePos - planet house position
1713
+ * ================================================================== */
1714
+
1715
+ export function sweHousePos(
1716
+ armc: number, geolat: number, eps: number, hsys: string,
1717
+ xpin: number[], serr: { value: string } | null,
1718
+ ): number {
1719
+ const xp = [0, 0, 0, 0, 0, 0];
1720
+ const xeq = [0, 0, 0, 0, 0, 0];
1721
+ let hpos = 0;
1722
+ const sine = sind(eps);
1723
+ const cose = cosd(eps);
1724
+ let tanfi: number;
1725
+ hsys = hsys.toUpperCase();
1726
+
1727
+ /* check if input is a house cusp */
1728
+ const hcusp = new Array(37).fill(0);
1729
+ const ascmcArr = new Array(10).fill(0);
1730
+ ascmcArr[9] = 99; // dirty hack for Sunshine
1731
+ if (sweHousesArmcEx2(armc, geolat, eps, hsys, hcusp, ascmcArr, null, null, serr) !== ERR) {
1732
+ hpos = 0;
1733
+ for (let i = 1; i <= 12; i++) {
1734
+ if (Math.abs(sweDifdeg2n(xpin[0], hcusp[i])) < MILLIARCSEC && xpin[1] === 0) {
1735
+ hpos = i;
1736
+ }
1737
+ }
1738
+ if (hpos > 0) return hpos;
1739
+ }
1740
+ let dsun = 0;
1741
+ if (hsys === 'I') dsun = ascmcArr[9];
1742
+ if (hsys === 'Y') {
1743
+ const xeqt = [ascmcArr[0], 0, 1];
1744
+ sweCotrans(xeqt, xeqt, -eps);
1745
+ dsun = xeqt[1];
1746
+ }
1747
+
1748
+ let isAboveHor = false;
1749
+ let isWesternHalf = false;
1750
+ xeq[0] = xpin[0];
1751
+ xeq[1] = xpin[1];
1752
+ xeq[2] = 1;
1753
+ sweCotrans(xeq, xeq, -eps);
1754
+ let ra = xeq[0];
1755
+ let de = xeq[1];
1756
+ let mdd = sweDegnorm(ra - armc);
1757
+ let mdn = sweDegnorm(mdd + 180);
1758
+ if (mdd >= 180) mdd -= 360;
1759
+ if (mdn >= 180) mdn -= 360;
1760
+
1761
+ switch (hsys) {
1762
+ case 'N': {
1763
+ xp[0] = xpin[0];
1764
+ hpos = xp[0] / 30.0 + 1;
1765
+ break;
1766
+ }
1767
+ case 'A': case 'E': case 'D': case 'V': case 'W': {
1768
+ let asc = asc1(sweDegnorm(armc + 90), geolat, sine, cose);
1769
+ asc = fixAscPolar(asc, armc, eps, geolat);
1770
+ xp[0] = sweDegnorm(xpin[0] - asc);
1771
+ if (hsys === 'V') xp[0] = sweDegnorm(xp[0] + 15);
1772
+ if (hsys === 'W') xp[0] = sweDegnorm(xp[0] + (asc % 30));
1773
+ if (hsys === 'D') {
1774
+ const mc = armcToMc(armc, eps);
1775
+ xp[0] = sweDegnorm(xpin[0] - mc - 90);
1776
+ }
1777
+ xp[0] = sweDegnorm(xp[0] + MILLIARCSEC);
1778
+ hpos = xp[0] / 30.0 + 1;
1779
+ break;
1780
+ }
1781
+ case 'O': case 'B': case 'S': {
1782
+ let asc = asc1(sweDegnorm(armc + 90), geolat, sine, cose);
1783
+ const mc = armcToMc(armc, eps);
1784
+ asc = fixAscPolar(asc, armc, eps, geolat);
1785
+ if (hsys === 'O' || hsys === 'S') {
1786
+ xp[0] = sweDegnorm(xpin[0] - asc);
1787
+ xp[0] = sweDegnorm(xp[0] + MILLIARCSEC);
1788
+ if (xp[0] < 180) hpos = 1;
1789
+ else { hpos = 7; xp[0] -= 180; }
1790
+ const acmc2 = sweDifdeg2n(asc, mc);
1791
+ if (xp[0] < 180 - acmc2)
1792
+ hpos += xp[0] * 3 / (180 - acmc2);
1793
+ else
1794
+ hpos += 3 + (xp[0] - 180 + acmc2) * 3 / acmc2;
1795
+ if (hsys === 'S') {
1796
+ hpos += 0.5;
1797
+ if (hpos > 12) hpos = 1;
1798
+ }
1799
+ } else { /* Alcabitius */
1800
+ const dek = asind(sind(asc) * sine);
1801
+ tanfi = tand(geolat);
1802
+ let r = -tanfi * tand(dek);
1803
+ const sda = Math.acos(r) * RADTODEG;
1804
+ const sna = 180 - sda;
1805
+ if (mdd > 0) {
1806
+ if (mdd < sda) hpos = mdd * 90 / sda;
1807
+ else hpos = 90 + (mdd - sda) * 90 / sna;
1808
+ } else {
1809
+ if (mdd > -sna) hpos = 360 + mdd * 90 / sna;
1810
+ else hpos = 270 + (mdd + sna) * 90 / sda;
1811
+ }
1812
+ hpos = sweDegnorm(hpos - 90) / 30.0 + 1.0;
1813
+ if (hpos >= 13.0) hpos -= 12;
1814
+ }
1815
+ break;
1816
+ }
1817
+ case 'X': {
1818
+ hpos = sweDegnorm(mdd - 90) / 30.0 + 1.0;
1819
+ break;
1820
+ }
1821
+ case 'F': {
1822
+ const x3 = [asc1(sweDegnorm(armc + 90), geolat, sine, cose), 0, 0];
1823
+ x3[0] = fixAscPolar(x3[0], armc, eps, geolat);
1824
+ sweCotrans(x3, x3, -eps);
1825
+ hpos = sweDegnorm(ra - x3[0]) / 30.0 + 1;
1826
+ break;
1827
+ }
1828
+ case 'M': {
1829
+ const a2 = xpin[0];
1830
+ if (Math.abs(a2 - 90) > VERY_SMALL && Math.abs(a2 - 270) > VERY_SMALL) {
1831
+ const tant2 = tand(a2);
1832
+ hpos = atand(tant2 / cose);
1833
+ if (a2 > 90 && a2 <= 270) hpos = sweDegnorm(hpos + 180);
1834
+ } else {
1835
+ hpos = Math.abs(a2 - 90) <= VERY_SMALL ? 90 : 270;
1836
+ }
1837
+ hpos = sweDegnorm(hpos - armc - 90);
1838
+ hpos = hpos / 30.0 + 1;
1839
+ break;
1840
+ }
1841
+ case 'K': {
1842
+ let isInvalid = false;
1843
+ let isCircumpolar = false;
1844
+ let adp: number;
1845
+ if (90 - geolat < de || -90 - geolat > de) {
1846
+ adp = 90; isCircumpolar = true;
1847
+ } else if (geolat - 90 > de || geolat + 90 < de) {
1848
+ adp = -90; isCircumpolar = true;
1849
+ } else {
1850
+ adp = asind(tand(geolat) * tand(de));
1851
+ }
1852
+ let admc = tand(eps) * tand(geolat) * sind(armc);
1853
+ if (Math.abs(admc) > 1) {
1854
+ admc = admc > 1 ? 1 : -1;
1855
+ isCircumpolar = true;
1856
+ }
1857
+ admc = asind(admc);
1858
+ const samc = 90 + admc;
1859
+ if (samc === 0) isInvalid = true;
1860
+ if (Math.abs(samc) > 0) {
1861
+ if (mdd >= 0) {
1862
+ const dfac = (mdd - adp + admc) / samc;
1863
+ xp[0] = sweDegnorm((dfac - 1) * 90);
1864
+ xp[0] = sweDegnorm(xp[0] + MILLIARCSEC);
1865
+ if (dfac > 2 || dfac < 0) isInvalid = true;
1866
+ } else {
1867
+ const dfac = (mdd + 180 + adp + admc) / samc;
1868
+ xp[0] = sweDegnorm((dfac + 1) * 90);
1869
+ xp[0] = sweDegnorm(xp[0] + MILLIARCSEC);
1870
+ if (dfac > 2 || dfac < 0) isInvalid = true;
1871
+ }
1872
+ }
1873
+ if (isInvalid) {
1874
+ xp[0] = 0;
1875
+ hpos = 0;
1876
+ if (serr) serr.value = 'Koch house position failed in circumpolar area';
1877
+ break;
1878
+ }
1879
+ if (isCircumpolar && serr) {
1880
+ serr.value = 'Koch house position, doubtful result in circumpolar area';
1881
+ }
1882
+ hpos = xp[0] / 30.0 + 1;
1883
+ break;
1884
+ }
1885
+ case 'C': {
1886
+ xeq[0] = sweDegnorm(mdd - 90);
1887
+ sweCotrans(xeq, xp, -geolat);
1888
+ xp[0] = sweDegnorm(xp[0] + MILLIARCSEC);
1889
+ hpos = xp[0] / 30.0 + 1;
1890
+ break;
1891
+ }
1892
+ case 'J': {
1893
+ const sinfi2 = sind(geolat);
1894
+ let xs1: number, xs2: number;
1895
+ if (Math.abs(geolat) < VERY_SMALL) {
1896
+ xs2 = 1 / 3.0; xs1 = 2 / 3.0;
1897
+ } else {
1898
+ xs2 = sind(geolat / 3) / sinfi2;
1899
+ xs1 = sind(2 * geolat / 3) / sinfi2;
1900
+ }
1901
+ xs2 = asind(xs2);
1902
+ xs1 = asind(xs1);
1903
+ const hcusp2 = new Array(13).fill(0);
1904
+ hcusp2[1] = 0; hcusp2[2] = xs2; hcusp2[3] = xs1;
1905
+ hcusp2[4] = 90; hcusp2[5] = 180 - xs1; hcusp2[6] = 180 - xs2;
1906
+ hcusp2[7] = 180; hcusp2[8] = 180 + xs2; hcusp2[9] = 180 + xs1;
1907
+ hcusp2[10] = 270; hcusp2[11] = 360 - xs1; hcusp2[12] = 360 - xs2;
1908
+ xeq[0] = sweDegnorm(mdd - 90);
1909
+ sweCotrans(xeq, xp, -geolat);
1910
+ const a3 = xp[0];
1911
+ let d2: number, c1: number, c2: number;
1912
+ if (sweDifdeg2n(hcusp2[6], hcusp2[1]) > 0) {
1913
+ d2 = sweDegnorm(a3 - hcusp2[1]);
1914
+ let ii: number;
1915
+ for (ii = 1; ii <= 12; ii++) {
1916
+ let j = ii + 1;
1917
+ c2 = j > 12 ? 360 : sweDegnorm(hcusp2[j] - hcusp2[1]);
1918
+ if (d2 < c2) break;
1919
+ }
1920
+ c1 = sweDegnorm(hcusp2[ii] - hcusp2[1]);
1921
+ const hsize = c2! - c1;
1922
+ hpos = hsize === 0 ? ii : ii + (d2 - c1) / hsize;
1923
+ } else {
1924
+ d2 = sweDegnorm(hcusp2[1] - a3);
1925
+ let ii: number;
1926
+ for (ii = 1; ii <= 12; ii++) {
1927
+ let j = ii + 1;
1928
+ c2 = j > 12 ? 360 : sweDegnorm(hcusp2[1] - hcusp2[j]);
1929
+ if (d2 < c2) break;
1930
+ }
1931
+ c1 = sweDegnorm(hcusp2[1] - hcusp2[ii]);
1932
+ const hsize = c2! - c1;
1933
+ hpos = hsize === 0 ? ii : ii + (d2 - c1) / hsize;
1934
+ }
1935
+ break;
1936
+ }
1937
+ case 'U': {
1938
+ let geolat2 = geolat;
1939
+ if (Math.abs(geolat2) < VERY_SMALL)
1940
+ geolat2 = geolat2 >= 0 ? VERY_SMALL : -VERY_SMALL;
1941
+ let asc2u = asc1(sweDegnorm(armc + 90), geolat2, sine, cose);
1942
+ asc2u = fixAscPolar(asc2u, armc, eps, geolat2);
1943
+ const xu = [asc2u, 0, 1];
1944
+ sweCotrans(xu, xu, -eps);
1945
+ const raep = sweDegnorm(armc + 90);
1946
+ xu[0] = sweDegnorm(raep - xu[0]);
1947
+ sweCotrans(xu, xu, -(90 - geolat2));
1948
+ let tanx = tand(xu[0]);
1949
+ let xtemp: number;
1950
+ if (geolat2 === 0) xtemp = tanx >= 0 ? 90 : -90;
1951
+ else xtemp = atand(tanx / cosd(90 - geolat2));
1952
+ if (xu[0] > 90 && xu[0] <= 270) xtemp = sweDegnorm(xtemp + 180);
1953
+ xu[0] = sweDegnorm(xtemp);
1954
+ const raaz = sweDegnorm(raep - xu[0]);
1955
+ xu[0] = raaz; xu[1] = 0;
1956
+ xu[0] = sweDegnorm(raep - xu[0]);
1957
+ sweCotrans(xu, xu, -(90 - geolat2));
1958
+ xu[1] = xu[1] + 90;
1959
+ sweCotrans(xu, xu, 90 - geolat2);
1960
+ const oblaz = xu[1];
1961
+ const xasc2 = [asc2u, 0, 1];
1962
+ sweCotrans(xasc2, xasc2, -eps);
1963
+ xasc2[0] = sweDegnorm(xasc2[0] - raaz);
1964
+ xtemp = atand(tand(xasc2[0]) / cosd(oblaz));
1965
+ if (xasc2[0] > 90 && xasc2[0] <= 270) xtemp = sweDegnorm(xtemp + 180);
1966
+ xasc2[0] = sweDegnorm(xtemp);
1967
+ xp[0] = sweDegnorm(xeq[0] - raaz);
1968
+ xtemp = atand(tand(xp[0]) / cosd(oblaz));
1969
+ if (xp[0] > 90 && xp[0] <= 270) xtemp = sweDegnorm(xtemp + 180);
1970
+ xp[0] = sweDegnorm(xtemp);
1971
+ xp[0] = sweDegnorm(xp[0] - xasc2[0]);
1972
+ xp[0] = sweDegnorm(xp[0] + MILLIARCSEC);
1973
+ hpos = xp[0] / 30.0 + 1;
1974
+ break;
1975
+ }
1976
+ case 'H': {
1977
+ xeq[0] = sweDegnorm(mdd - 90);
1978
+ sweCotrans(xeq, xp, 90 - geolat);
1979
+ xp[0] = sweDegnorm(xp[0] + MILLIARCSEC);
1980
+ hpos = xp[0] / 30.0 + 1;
1981
+ break;
1982
+ }
1983
+ case 'R': {
1984
+ if (Math.abs(mdd) < VERY_SMALL) xp[0] = 270;
1985
+ else if (180 - Math.abs(mdd) < VERY_SMALL) xp[0] = 90;
1986
+ else {
1987
+ let geolat2 = geolat, de2 = de;
1988
+ if (90 - Math.abs(geolat2) < VERY_SMALL)
1989
+ geolat2 = geolat2 > 0 ? 90 - VERY_SMALL : -90 + VERY_SMALL;
1990
+ if (90 - Math.abs(de2) < VERY_SMALL)
1991
+ de2 = de2 > 0 ? 90 - VERY_SMALL : -90 + VERY_SMALL;
1992
+ const a4 = tand(geolat2) * tand(de2) + cosd(mdd);
1993
+ xp[0] = sweDegnorm(atand(-a4 / sind(mdd)));
1994
+ if (mdd < 0) xp[0] += 180;
1995
+ xp[0] = sweDegnorm(xp[0]);
1996
+ xp[0] = sweDegnorm(xp[0] + MILLIARCSEC);
1997
+ }
1998
+ hpos = xp[0] / 30.0 + 1;
1999
+ break;
2000
+ }
2001
+ case 'I': case 'Y': {
2002
+ if (geolat > 90 - MILLIARCSEC) geolat = 90 - MILLIARCSEC;
2003
+ if (geolat < -90 + MILLIARCSEC) geolat = -90 + MILLIARCSEC;
2004
+ if (90 - Math.abs(de) < VERY_SMALL)
2005
+ de = de > 0 ? 90 - VERY_SMALL : -90 + VERY_SMALL;
2006
+ let a5 = tand(geolat) * tand(de) + cosd(mdd);
2007
+ xp[0] = sweDegnorm(atand(-a5 / sind(mdd)));
2008
+ if (mdd < 0) xp[0] += 180;
2009
+ xp[0] = sweDegnorm(xp[0]);
2010
+ let sinad = tand(de) * tand(geolat);
2011
+ a5 = sinad + cosd(mdd);
2012
+ if (a5 >= 0) isAboveHor = true;
2013
+ let harmc = 90 - geolat;
2014
+ if (geolat < 0) harmc = 90 + geolat;
2015
+ let darmc = sweDegnorm(xp[0] - 270);
2016
+ if (darmc > 180) {
2017
+ isWesternHalf = true;
2018
+ darmc = 360 - darmc;
2019
+ }
2020
+ sinad = tand(dsun) * tand(geolat);
2021
+ let ad: number;
2022
+ if (sinad >= 1) ad = 90;
2023
+ else if (sinad <= -1) ad = -90;
2024
+ else ad = asind(sinad);
2025
+ let sad = 90 + ad;
2026
+ let san = 90 - ad;
2027
+ if (sad === 0 && isAboveHor) {
2028
+ xp[0] = 270;
2029
+ } else if (san === 0 && !isAboveHor) {
2030
+ xp[0] = 90;
2031
+ } else {
2032
+ let sa = sad;
2033
+ if (!isAboveHor) {
2034
+ dsun = -dsun;
2035
+ sa = san;
2036
+ darmc = 180 - darmc;
2037
+ isWesternHalf = !isWesternHalf;
2038
+ }
2039
+ const aa = acosd(cosd(harmc) * cosd(darmc));
2040
+ const aUsed = aa < VERY_SMALL ? VERY_SMALL : aa;
2041
+ let sinpsi = sind(harmc) / sind(aUsed);
2042
+ if (sinpsi > 1) sinpsi = 1;
2043
+ if (sinpsi < -1) sinpsi = -1;
2044
+ let y = sind(dsun) / sinpsi;
2045
+ if (y > 1) y = 90 - VERY_SMALL;
2046
+ else if (y < -1) y = -(90 - VERY_SMALL);
2047
+ else y = asind(y);
2048
+ let d2 = acosd(cosd(y) / cosd(dsun));
2049
+ if (dsun < 0) d2 = -d2;
2050
+ if (geolat < 0) d2 = -d2;
2051
+ darmc += d2;
2052
+ if (isWesternHalf) xp[0] = 270 - (darmc / sa) * 90;
2053
+ else xp[0] = 270 + (darmc / sa) * 90;
2054
+ if (!isAboveHor) xp[0] = sweDegnorm(xp[0] + 180);
2055
+ }
2056
+ xp[0] = sweDegnorm(xp[0] + MILLIARCSEC);
2057
+ hpos = xp[0] / 30.0 + 1;
2058
+ break;
2059
+ }
2060
+ case 'T': {
2061
+ let fh = geolat;
2062
+ if (fh > 89.999) fh = 89.999;
2063
+ if (fh < -89.999) fh = -89.999;
2064
+ mdd = sweDegnorm(mdd);
2065
+ if (de > 90 - VERY_SMALL) de = 90 - VERY_SMALL;
2066
+ if (de < -90 + VERY_SMALL) de = -90 + VERY_SMALL;
2067
+ let sinad = tand(de) * tand(fh);
2068
+ if (sinad > 1.0) sinad = 1.0;
2069
+ if (sinad < -1.0) sinad = -1.0;
2070
+ const a6 = sinad + cosd(mdd);
2071
+ if (a6 >= 0) isAboveHor = true;
2072
+ if (!isAboveHor) {
2073
+ ra = sweDegnorm(ra + 180);
2074
+ de = -de;
2075
+ mdd = sweDegnorm(mdd + 180);
2076
+ }
2077
+ if (mdd > 180) ra = sweDegnorm(armc - mdd);
2078
+ tanfi = tand(fh);
2079
+ let ra0 = sweDegnorm(armc + 90);
2080
+ xp[1] = 1;
2081
+ xeq[1] = de;
2082
+ let fac2 = 2;
2083
+ let nloop = 0;
2084
+ while (Math.abs(xp[1]) > 0.000001 && nloop < 1000) {
2085
+ if (xp[1] > 0) {
2086
+ fh = atand(tand(fh) - tanfi / fac2);
2087
+ ra0 -= 90 / fac2;
2088
+ } else {
2089
+ fh = atand(tand(fh) + tanfi / fac2);
2090
+ ra0 += 90 / fac2;
2091
+ }
2092
+ xeq[0] = sweDegnorm(ra - ra0);
2093
+ sweCotrans(xeq, xp, 90 - fh);
2094
+ fac2 *= 2;
2095
+ nloop++;
2096
+ }
2097
+ hpos = sweDegnorm(ra0 - armc);
2098
+ if (mdd > 180) hpos = sweDegnorm(-hpos);
2099
+ if (!isAboveHor) hpos = sweDegnorm(hpos + 180);
2100
+ hpos = sweDegnorm(hpos - 90) / 30 + 1;
2101
+ break;
2102
+ }
2103
+ case 'P': case 'G': {
2104
+ if (90 - Math.abs(de) <= Math.abs(geolat)) {
2105
+ if (de * geolat < 0) xp[0] = sweDegnorm(90 + mdn / 2);
2106
+ else xp[0] = sweDegnorm(270 + mdd / 2);
2107
+ if (serr) serr.value = 'Otto Ludwig procedure within circumpolar regions.';
2108
+ } else {
2109
+ const sinad2 = tand(de) * tand(geolat);
2110
+ const ad2 = asind(sinad2);
2111
+ const a7 = sinad2 + cosd(mdd);
2112
+ if (a7 >= 0) isAboveHor = true;
2113
+ const sad2 = 90 + ad2;
2114
+ const san2 = 90 - ad2;
2115
+ if (isAboveHor) xp[0] = (mdd / sad2 + 3) * 90;
2116
+ else xp[0] = (mdn / san2 + 1) * 90;
2117
+ xp[0] = sweDegnorm(xp[0] + MILLIARCSEC);
2118
+ }
2119
+ if (hsys === 'G') {
2120
+ xp[0] = 360 - xp[0];
2121
+ hpos = xp[0] / 10.0 + 1;
2122
+ } else {
2123
+ hpos = xp[0] / 30.0 + 1;
2124
+ }
2125
+ break;
2126
+ }
2127
+ default: {
2128
+ /* simplified algorithm for unknown systems */
2129
+ hpos = 0;
2130
+ const hcusp3 = new Array(37).fill(0);
2131
+ const ascmc3 = new Array(10).fill(0);
2132
+ if (sweHousesArmcEx2(armc, geolat, eps, hsys, hcusp3, ascmc3, null, null, serr) === ERR) {
2133
+ if (serr) serr.value = `swe_house_pos(): failed for system ${hsys}`;
2134
+ break;
2135
+ }
2136
+ let d3: number, c1: number = 0, c2: number = 0;
2137
+ let ii: number = 1;
2138
+ if (sweDifdeg2n(hcusp3[6], hcusp3[1]) > 0) {
2139
+ d3 = sweDegnorm(xpin[0] - hcusp3[1]);
2140
+ for (ii = 1; ii <= 12; ii++) {
2141
+ const j = ii + 1;
2142
+ c2 = j > 12 ? 360 : sweDegnorm(hcusp3[j] - hcusp3[1]);
2143
+ if (d3 < c2) break;
2144
+ }
2145
+ c1 = sweDegnorm(hcusp3[ii] - hcusp3[1]);
2146
+ } else {
2147
+ d3 = sweDegnorm(hcusp3[1] - xpin[0]);
2148
+ for (ii = 1; ii <= 12; ii++) {
2149
+ const j = ii + 1;
2150
+ c2 = j > 12 ? 360 : sweDegnorm(hcusp3[1] - hcusp3[j]);
2151
+ if (d3 < c2) break;
2152
+ }
2153
+ c1 = sweDegnorm(hcusp3[1] - hcusp3[ii]);
2154
+ }
2155
+ const hsize = c2 - c1;
2156
+ hpos = hsize === 0 ? ii : ii + (d3 - c1) / hsize;
2157
+ if (serr) serr.value = `swe_house_pos(): using simplified algorithm for system ${hsys}`;
2158
+ break;
2159
+ }
2160
+ }
2161
+ return hpos;
2162
+ }
2163
+
2164
+ /** ARMC to MC - public export (wrapper for C swi_armc_to_mc) */
2165
+ export function swiArmcToMcHouse(armc: number, eps: number): number {
2166
+ return armcToMc(armc, eps);
2167
+ }