1 /* 2 * This library is free software; you can redistribute it and/or 3 * modify it under the terms of the GNU Lesser General Public 4 * License as published by the Free Software Foundation; either 5 * version 2 of the License, or (at your option) any later version. 6 * 7 * This library is distributed in the hope that it will be useful, 8 * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 10 * Lesser General Public License for more details. 11 * 12 * You should have received a copy of the GNU General Public License 13 * along with this program; if not, write to the Free Software 14 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 15 * 16 * Copyright (C) 2000 - 2005 Liam Girdwood <lgirdwood@gmail.com> 17 * 18 * The functions in this file use the Lunar Solution ELP 2000-82B by 19 * Michelle Chapront-Touze and Jean Chapront. 20 */ 21 22 module nova.lunar; 23 24 import std.math; 25 26 import nova.vsop87; 27 import nova.solar; 28 import nova.earth; 29 import nova.transform; 30 import nova.rise_set; 31 import nova.utility; 32 33 import nova.lunar_priv; 34 35 import nova.elp.elp1; 36 import nova.elp.elp2; 37 import nova.elp.elp3; 38 import nova.elp.elp4; 39 import nova.elp.elp5; 40 import nova.elp.elp6; 41 import nova.elp.elp7; 42 import nova.elp.elp8; 43 import nova.elp.elp9; 44 import nova.elp.elp10; 45 import nova.elp.elp11; 46 import nova.elp.elp12; 47 import nova.elp.elp13; 48 import nova.elp.elp14; 49 import nova.elp.elp15; 50 import nova.elp.elp16; 51 import nova.elp.elp17; 52 import nova.elp.elp18; 53 import nova.elp.elp19; 54 import nova.elp.elp20; 55 import nova.elp.elp21; 56 import nova.elp.elp22; 57 import nova.elp.elp23; 58 import nova.elp.elp24; 59 import nova.elp.elp25; 60 import nova.elp.elp26; 61 import nova.elp.elp27; 62 import nova.elp.elp28; 63 import nova.elp.elp29; 64 import nova.elp.elp30; 65 import nova.elp.elp31; 66 import nova.elp.elp32; 67 import nova.elp.elp33; 68 import nova.elp.elp34; 69 import nova.elp.elp35; 70 import nova.elp.elp36; 71 72 enum LN_LUNAR_STANDART_HORIZON = 0.125; 73 74 /* AU in KM */ 75 enum AU = 149597870; 76 77 /* sequence sizes */ 78 enum ELP1_SIZE = 1023; /* Main problem. Longitude periodic terms (sine) */ 79 enum ELP2_SIZE = 918; /* Main problem. Latitude (sine) */ 80 enum ELP3_SIZE = 704; /* Main problem. Distance (cosine) */ 81 enum ELP4_SIZE = 347; /* Earth figure perturbations. Longitude */ 82 enum ELP5_SIZE = 316; /* Earth figure perturbations. Latitude */ 83 enum ELP6_SIZE = 237; /* Earth figure perturbations. Distance */ 84 enum ELP7_SIZE = 14; /* Earth figure perturbations. Longitude/t */ 85 enum ELP8_SIZE = 11; /* Earth figure perturbations. Latitude/t */ 86 enum ELP9_SIZE = 8; /* Earth figure perturbations. Distance/t */ 87 enum ELP10_SIZE = 14328; /* Planetary perturbations. Table 1 Longitude */ 88 enum ELP11_SIZE = 5233; /* Planetary perturbations. Table 1 Latitude */ 89 enum ELP12_SIZE = 6631; /* Planetary perturbations. Table 1 Distance */ 90 enum ELP13_SIZE = 4384; /* Planetary perturbations. Table 1 Longitude/t */ 91 enum ELP14_SIZE = 833; /* Planetary perturbations. Table 1 Latitude/t */ 92 enum ELP15_SIZE = 1715; /* Planetary perturbations. Table 1 Distance/t */ 93 enum ELP16_SIZE = 170; /* Planetary perturbations. Table 2 Longitude */ 94 enum ELP17_SIZE = 150; /* Planetary perturbations. Table 2 Latitude */ 95 enum ELP18_SIZE = 114; /* Planetary perturbations. Table 2 Distance */ 96 enum ELP19_SIZE = 226; /* Planetary perturbations. Table 2 Longitude/t */ 97 enum ELP20_SIZE = 188; /* Planetary perturbations. Table 2 Latitude/t */ 98 enum ELP21_SIZE = 169; /* Planetary perturbations. Table 2 Distance/t */ 99 enum ELP22_SIZE = 3; /* Tidal effects. Longitude */ 100 enum ELP23_SIZE = 2; /* Tidal effects. Latitude */ 101 enum ELP24_SIZE = 2; /* Tidal effects. Distance */ 102 enum ELP25_SIZE = 6; /* Tidal effects. Longitude/t */ 103 enum ELP26_SIZE = 4; /* Tidal effects. Latitude/t */ 104 enum ELP27_SIZE = 5; /* Tidal effects. Distance/t */ 105 enum ELP28_SIZE = 20; /* Moon figure perturbations. Longitude */ 106 enum ELP29_SIZE = 12; /* Moon figure perturbations. Latitude */ 107 enum ELP30_SIZE = 14; /* Moon figure perturbations. Distance */ 108 enum ELP31_SIZE = 11; /* Relativistic perturbations. Longitude */ 109 enum ELP32_SIZE = 4; /* Relativistic perturbations. Latitude */ 110 enum ELP33_SIZE = 10; /* Relativistic perturbations. Distance */ 111 enum ELP34_SIZE = 28; /* Planetary perturbations - solar eccentricity. Longitude/t2 */ 112 enum ELP35_SIZE = 13; /* Planetary perturbations - solar eccentricity. Latitude/t2 */ 113 enum ELP36_SIZE = 19; /* Planetary perturbations - solar eccentricity. Distance/t2 */ 114 115 116 /* Chapront theory lunar constants */ 117 enum RAD = (648000.0 / PI); 118 enum DEG = (PI / 180.0); 119 enum PIS2 = (PI / 2.0); 120 enum ATH = 384747.9806743165; 121 enum A0 = 384747.9806448954; 122 enum AM = 0.074801329518; 123 enum ALPHA = 0.002571881335; 124 enum DTASM = (2.0 * ALPHA / (3.0 * AM)); 125 enum W12 = (1732559343.73604 / RAD); 126 enum PRECES = (5029.0966 / RAD); 127 enum C1 = 60.0; 128 enum C2 = 3600.0; 129 130 /* Corrections of the constants for DE200/LE200 */ 131 enum DELNU = ((0.55604 / RAD) / W12); 132 enum DELE = (0.01789 / RAD); 133 enum DELG = (-0.08066 / RAD); 134 enum DELNP = ((-0.06424 / RAD) / W12); 135 enum DELEP = (-0.12879 / RAD); 136 137 /* Precession matrix */ 138 enum P1 = 0.10180391e-4; 139 enum P2 = 0.47020439e-6; 140 enum P3 = -0.5417367e-9; 141 enum P4 = -0.2507948e-11; 142 enum P5 = 0.463486e-14; 143 enum Q1 = -0.113469002e-3; 144 enum Q2 = 0.12372674e-6; 145 enum Q3 = 0.1265417e-8; 146 enum Q4 = -0.1371808e-11; 147 enum Q5 = -0.320334e-14; 148 149 /* initialise lunar constants */ 150 void init_lunar_constants (); 151 152 /* constants with corrections for DE200 / LE200 */ 153 static const double[5] W1 = 154 [ 155 ((218.0 + (18.0 / 60.0) + (59.95571 / 3600.0))) * DEG, 156 1732559343.73604 / RAD, 157 -5.8883 / RAD, 158 0.006604 / RAD, 159 -0.00003169 / RAD 160 ]; 161 162 // #if 0 163 // /* These arrays not currently used */ 164 // static const double W2[5] = 165 // { 166 // ((83.0 + (21.0 / 60.0) + (11.67475 / 3600.0))) * DEG, 167 // 14643420.2632 / RAD, 168 // -38.2776 / RAD, 169 // -0.045047 / RAD, 170 // 0.00021301 / RAD 171 // }; 172 // 173 // static const double W3[5] = 174 // { 175 // (125.0 + (2.0 / 60.0) + (40.39816 / 3600.0)) * DEG, 176 // -6967919.3622 / RAD, 177 // 6.3622 / RAD, 178 // 0.007625 / RAD, 179 // -0.00003586 / RAD 180 // }; 181 // 182 // static const double earth[5] = 183 // { 184 // (100.0 + (27.0 / 60.0) + (59.22059 / 3600.0)) * DEG, 185 // 129597742.2758 / RAD, 186 // -0.0202 / RAD, 187 // 0.000009 / RAD, 188 // 0.00000015 / RAD 189 // }; 190 // 191 // static const double peri[5] = 192 // { 193 // (102.0 + (56.0 / 60.0) + (14.42753 / 3600.0)) * DEG, 194 // 1161.2283 / RAD, 195 // 0.5327 / RAD, 196 // -0.000138 / RAD, 197 // 0.0 198 // }; 199 // #endif 200 201 /* Delaunay's arguments.*/ 202 static const double[5][4] del = [ 203 [ 5.198466741027443, 7771.377146811758394, -0.000028449351621, 0.000000031973462, -0.000000000154365 ], 204 [ -0.043125180208125, 628.301955168488007, -0.000002680534843, 0.000000000712676, 0.000000000000727 ], 205 [ 2.355555898265799, 8328.691426955554562, 0.000157027757616, 0.000000250411114, -0.000000001186339 ], 206 [ 1.627905233371468, 8433.466158130539043, -0.000059392100004, -0.000000004949948, 0.000000000020217 ] 207 ]; 208 209 210 static const double[2] zeta = 211 [ 212 (218.0 + (18.0 / 60.0) + (59.95571 / 3600.0)) * DEG, 213 ((1732559343.73604 / RAD) + PRECES) 214 ]; 215 216 217 /* Planetary arguments */ 218 static const double[2][8] p = 219 [ 220 [(252.0 + 15.0 / C1 + 3.25986 / C2 ) * DEG, 538101628.68898 / RAD ], 221 [(181.0 + 58.0 / C1 + 47.28305 / C2) * DEG, 210664136.43355 / RAD ], 222 [(100.0 + (27.0 / 60.0) + (59.22059 / 3600.0)) * DEG, 129597742.2758 / RAD], 223 [(355.0 + 25.0 / C1 + 59.78866 / C2) * DEG, 68905077.59284 / RAD ], 224 [(34.0 + 21.0 / C1 + 5.34212 / C2) * DEG, 10925660.42861 / RAD ], 225 [(50.0 + 4.0 / C1 + 38.89694 / C2) * DEG, 4399609.65932 / RAD ], 226 [(314.0 + 3.0 / C1 + 18.01841 / C2) * DEG, 1542481.19393 / RAD ], 227 [(304.0 + 20.0 / C1 + 55.19575 / C2) * DEG, 786550.32074 / RAD ] 228 ]; 229 230 extern (C) { 231 232 /* sum lunar elp1 series */ 233 static @nogc double sum_series_elp1 (double[] t) nothrow 234 { 235 double result = 0; 236 double x,y; 237 double tgv; 238 int i,j,k; 239 240 for (j = 0; j < ELP1_SIZE; j++) { 241 /* derivatives of A */ 242 tgv = elp1[j].B[0] + DTASM * elp1[j].B[4]; 243 x = elp1[j].A + tgv * (DELNP - AM * DELNU) + 244 elp1[j].B[1] * DELG + elp1[j].B[2] * 245 DELE + elp1[j].B[3] * DELEP; 246 247 y = 0; 248 for (k = 0; k < 5; k++) { 249 for (i = 0; i < 4; i++) 250 y += elp1[j].ilu[i] * del[i][k] * t[k]; 251 } 252 253 /* y in correct quad */ 254 y = ln_range_radians2(y); 255 result += x * sin(y); 256 } 257 return result; 258 } 259 260 /* sum lunar elp2 series */ 261 static @nogc double sum_series_elp2 (double[] t) nothrow 262 { 263 double result = 0; 264 double x,y; 265 double tgv; 266 int i,j,k; 267 268 for (j = 0; j < ELP2_SIZE; j++) { 269 /* derivatives of A */ 270 tgv = elp2[j].B[0] + DTASM * elp2[j].B[4]; 271 x = elp2[j].A + tgv * (DELNP - AM * DELNU) + 272 elp2[j].B[1] * DELG + elp2[j].B[2] * 273 DELE + elp2[j].B[3] * DELEP; 274 275 y = 0; 276 for (k = 0; k < 5; k++) { 277 for (i = 0; i < 4; i++) 278 y += elp2[j].ilu[i] * del[i][k] * t[k]; 279 } 280 /* y in correct quad */ 281 y = ln_range_radians2(y); 282 result += x * sin(y); 283 } 284 return result; 285 } 286 287 /* sum lunar elp3 series */ 288 static @nogc double sum_series_elp3 (double[] t) nothrow 289 { 290 double result = 0; 291 double x,y; 292 double tgv; 293 int i,j,k; 294 295 for (j = 0; j < ELP3_SIZE; j++) { 296 /* derivatives of A */ 297 tgv = elp3[j].B[0] + DTASM * elp3[j].B[4]; 298 x = elp3[j].A + tgv * (DELNP - AM * DELNU) + 299 elp3[j].B[1] * DELG + elp3[j].B[2] * 300 DELE + elp3[j].B[3] * DELEP; 301 302 y = 0; 303 for (k = 0; k < 5; k++) { 304 for (i = 0; i < 4; i++) 305 y += elp3[j].ilu[i] * del[i][k] * t[k]; 306 } 307 y += (PI_2); 308 /* y in correct quad */ 309 y = ln_range_radians2(y); 310 result += x * sin(y); 311 } 312 return result; 313 } 314 315 316 /* sum lunar elp4 series */ 317 static @nogc double sum_series_elp4(double[] t) nothrow 318 { 319 double result = 0; 320 int i,j,k; 321 double y; 322 323 for (j = 0; j < ELP4_SIZE; j++) { 324 y = elp4[j].O * DEG; 325 for (k = 0; k < 2; k++) { 326 y += elp4[j].iz * zeta[k] * t[k]; 327 for (i = 0; i < 4; i++) 328 y += elp4[j].ilu[i] * del[i][k] * t[k]; 329 } 330 /* put y in correct quad */ 331 y = ln_range_radians2(y); 332 result += elp4[j].A * sin(y); 333 } 334 return result; 335 } 336 337 /* sum lunar elp5 series */ 338 static @nogc double sum_series_elp5(double[] t) nothrow 339 { 340 double result = 0; 341 int i,j,k; 342 double y; 343 344 for (j = 0; j < ELP5_SIZE; j++) { 345 y = elp5[j].O * DEG; 346 for (k = 0; k < 2; k++) { 347 y += elp5[j].iz * zeta[k] * t[k]; 348 for (i = 0; i < 4; i++) 349 y += elp5[j].ilu[i] * del[i][k] * t[k]; 350 } 351 /* put y in correct quad */ 352 y = ln_range_radians2(y); 353 result += elp5[j].A * sin(y); 354 } 355 return result; 356 } 357 358 359 /* sum lunar elp6 series */ 360 static @nogc double sum_series_elp6(double[] t) nothrow 361 { 362 double result = 0; 363 int i,j,k; 364 double y; 365 366 for (j = 0; j < ELP6_SIZE; j++) { 367 y = elp6[j].O * DEG; 368 for (k = 0; k < 2; k++) { 369 y += elp6[j].iz * zeta[k] * t[k]; 370 for (i = 0; i < 4; i++) 371 y += elp6[j].ilu[i] * del[i][k] * t[k]; 372 } 373 /* put y in correct quad */ 374 y = ln_range_radians2(y); 375 result += elp6[j].A * sin(y); 376 } 377 return result; 378 } 379 380 /* sum lunar elp7 series */ 381 static @nogc double sum_series_elp7(double[] t) nothrow 382 { 383 double result = 0; 384 int i,j,k; 385 double y, A; 386 387 for (j = 0; j < ELP7_SIZE; j++) { 388 A = elp7[j].A * t[1]; 389 y = elp7[j].O * DEG; 390 for (k = 0; k < 2; k++) { 391 y += elp7[j].iz * zeta[k] * t[k]; 392 for (i = 0; i < 4; i++) 393 y += elp7[j].ilu[i] * del[i][k] * t[k]; 394 } 395 /* put y in correct quad */ 396 y = ln_range_radians2(y); 397 result += A * sin(y); 398 } 399 return result; 400 } 401 402 /* sum lunar elp8 series */ 403 static @nogc double sum_series_elp8(double[] t) nothrow 404 { 405 double result = 0; 406 int i,j,k; 407 double y, A; 408 409 for (j = 0; j < ELP8_SIZE; j++) { 410 y = elp8[j].O * DEG; 411 A = elp8[j].A * t[1]; 412 for (k = 0; k < 2; k++) { 413 y += elp8[j].iz * zeta[k] * t[k]; 414 for (i = 0; i < 4; i++) 415 y += elp8[j].ilu[i] * del[i][k] * t[k]; 416 } 417 /* put y in correct quad */ 418 y = ln_range_radians2(y); 419 result += A * sin(y); 420 } 421 return result; 422 } 423 424 /* sum lunar elp9 series */ 425 static @nogc double sum_series_elp9(double[] t) nothrow 426 { 427 double result = 0; 428 int i,j,k; 429 double y, A; 430 431 for (j = 0; j < ELP9_SIZE; j++) { 432 A = elp9[j].A * t[1]; 433 y = elp9[j].O * DEG; 434 for (k = 0; k < 2; k++) { 435 y += elp9[j].iz * zeta[k] * t[k]; 436 for (i = 0; i < 4; i++) 437 y += elp9[j].ilu[i] * del[i][k] * t[k]; 438 } 439 /* put y in correct quad */ 440 y = ln_range_radians2(y); 441 result += A * sin(y); 442 } 443 return result; 444 } 445 446 /* sum lunar elp10 series */ 447 static @nogc double sum_series_elp10(double[] t) nothrow 448 { 449 double result = 0; 450 int i,j,k; 451 double y; 452 453 for (j = 0; j < ELP10_SIZE; j++) { 454 y = elp10[j].theta * DEG; 455 456 for (k = 0; k < 2; k++) { 457 y += (elp10[j].ipla[8] * del[0][k] 458 + elp10[j].ipla[9] * del[2][k] 459 + elp10[j].ipla[10] * del [3][k]) * t[k]; 460 for (i = 0; i < 8; i++) 461 y += elp10[j].ipla[i] * p[i][k] * t[k]; 462 } 463 464 /* put y in correct quad */ 465 y = ln_range_radians2(y); 466 result += elp10[j].O * sin(y); 467 } 468 return result; 469 } 470 471 /* sum lunar elp11 series */ 472 static @nogc double sum_series_elp11(double[] t) nothrow 473 { 474 double result = 0; 475 int i,j,k; 476 double y; 477 478 for (j = 0; j < ELP11_SIZE; j++) { 479 y = elp11[j].theta * DEG; 480 for (k = 0; k < 2; k++) { 481 y += (elp11[j].ipla[8] * del[0][k] 482 + elp11[j].ipla[9] * del[2][k] 483 + elp11[j].ipla[10] * del [3][k]) * t[k]; 484 for (i = 0; i < 8; i++) 485 y += elp11[j].ipla[i] * p[i][k] * t[k]; 486 } 487 /* put y in correct quad */ 488 y = ln_range_radians2(y); 489 result += elp11[j].O * sin(y); 490 } 491 return result; 492 } 493 494 /* sum lunar elp12 series */ 495 static @nogc double sum_series_elp12(double[] t) nothrow 496 { 497 double result = 0; 498 int i,j,k; 499 double y; 500 501 for (j = 0; j < ELP12_SIZE; j++) { 502 y = elp12[j].theta * DEG; 503 for (k = 0; k < 2; k++) { 504 y += (elp12[j].ipla[8] * del[0][k] 505 + elp12[j].ipla[9] * del[2][k] 506 + elp12[j].ipla[10] * del [3][k]) * t[k]; 507 for (i = 0; i < 8; i++) 508 y += elp12[j].ipla[i] * p[i][k] * t[k]; 509 } 510 /* put y in correct quad */ 511 y = ln_range_radians2(y); 512 result += elp12[j].O * sin(y); 513 } 514 return result; 515 } 516 517 /* sum lunar elp13 series */ 518 static @nogc double sum_series_elp13(double[] t) nothrow 519 { 520 double result = 0; 521 int i,j,k; 522 double y,x; 523 524 for (j = 0; j < ELP13_SIZE; j++) { 525 y = elp13[j].theta * DEG; 526 for (k = 0; k < 2; k++) { 527 y += (elp13[j].ipla[8] * del[0][k] 528 + elp13[j].ipla[9] * del[2][k] 529 + elp13[j].ipla[10] * del [3][k]) * t[k]; 530 for (i = 0; i < 8; i++) 531 y += elp13[j].ipla[i] * p[i][k] * t[k]; 532 } 533 /* put y in correct quad */ 534 y = ln_range_radians2(y); 535 x = elp13[j].O * t[1]; 536 result += x * sin(y); 537 } 538 return result; 539 } 540 541 /* sum lunar elp14 series */ 542 static @nogc double sum_series_elp14(double[] t) nothrow 543 { 544 double result = 0; 545 int i,j,k; 546 double y,x; 547 548 for (j = 0; j < ELP14_SIZE; j++) { 549 y = elp14[j].theta * DEG; 550 for (k = 0; k < 2; k++) { 551 y += (elp14[j].ipla[8] * del[0][k] 552 + elp14[j].ipla[9] * del[2][k] 553 + elp14[j].ipla[10] * del [3][k]) * t[k]; 554 for (i = 0; i < 8; i++) 555 y += elp14[j].ipla[i] * p[i][k] * t[k]; 556 } 557 /* put y in correct quad */ 558 y = ln_range_radians2(y); 559 x = elp14[j].O * t[1]; 560 result += x * sin(y); 561 } 562 return result; 563 } 564 565 566 /* sum lunar elp15 series */ 567 static @nogc double sum_series_elp15(double[] t) nothrow 568 { 569 double result = 0; 570 int i,j,k; 571 double y,x; 572 573 for (j = 0; j < ELP15_SIZE; j++) { 574 y = elp15[j].theta * DEG; 575 for (k = 0; k < 2; k++) { 576 y += (elp15[j].ipla[8] * del[0][k] 577 + elp15[j].ipla[9] * del[2][k] 578 + elp15[j].ipla[10] * del [3][k]) * t[k]; 579 for (i = 0; i < 8; i++) 580 y += elp15[j].ipla[i] * p[i][k] * t[k]; 581 } 582 /* put y in correct quad */ 583 y = ln_range_radians2(y); 584 x = elp15[j].O * t[1]; 585 result += x * sin(y); 586 } 587 return result; 588 } 589 590 /* sum lunar elp16 series */ 591 static @nogc double sum_series_elp16(double[] t) nothrow 592 { 593 double result = 0; 594 int i,j,k; 595 double y; 596 597 for (j = 0; j < ELP16_SIZE; j++) { 598 y = elp16[j].theta * DEG; 599 for (k = 0; k < 2; k++) { 600 for (i = 0; i < 4; i++) 601 y += elp16[j].ipla[i + 7] * del[i][k] * t[k]; 602 for (i = 0; i < 7; i++) 603 y += elp16[j].ipla[i] * p[i][k] * t[k]; 604 } 605 /* put y in correct quad */ 606 y = ln_range_radians2(y); 607 result += elp16[j].O * sin(y); 608 } 609 return result; 610 } 611 612 static @nogc double sum_series_elp17(double[] t) nothrow 613 { 614 double result = 0; 615 int i,j,k; 616 double y; 617 618 for (j = 0; j < ELP17_SIZE; j++) { 619 y = elp17[j].theta * DEG; 620 for (k = 0; k < 2; k++) { 621 for (i = 0; i < 4; i++) 622 y += elp17[j].ipla[i + 7] * del[i][k] * t[k]; 623 for (i = 0; i < 7; i++) 624 y += elp17[j].ipla[i] * p[i][k] * t[k]; 625 } 626 /* put y in correct quad */ 627 y = ln_range_radians2(y); 628 result += elp17[j].O * sin(y); 629 } 630 return result; 631 } 632 633 static @nogc double sum_series_elp18(double[] t) nothrow 634 { 635 double result = 0; 636 int i,j,k; 637 double y; 638 639 for (j = 0; j < ELP18_SIZE; j++) { 640 y = elp18[j].theta * DEG; 641 for (k = 0; k < 2; k++) { 642 for (i = 0; i < 4; i++) 643 y += elp18[j].ipla[i + 7] * del[i][k] * t[k]; 644 for (i = 0; i < 7; i++) 645 y += elp18[j].ipla[i] * p[i][k] * t[k]; 646 } 647 /* put y in correct quad */ 648 y = ln_range_radians2(y); 649 result += elp18[j].O * sin(y); 650 } 651 return result; 652 } 653 654 static @nogc double sum_series_elp19(double[] t) nothrow 655 { 656 double result = 0; 657 int i,j,k; 658 double y,x; 659 660 for (j = 0; j < ELP19_SIZE; j++) { 661 y = elp19[j].theta * DEG; 662 for (k = 0; k < 2; k++) { 663 for (i = 0; i < 4; i++) 664 y += elp19[j].ipla[i + 7] * del[i][k] * t[k]; 665 for (i = 0; i < 7; i++) 666 y += elp19[j].ipla[i] * p[i][k] * t[k]; 667 } 668 /* put y in correct quad */ 669 y = ln_range_radians2(y); 670 x = elp19[j].O * t[1]; 671 result += x * sin(y); 672 } 673 return result; 674 } 675 676 static @nogc double sum_series_elp20(double[] t) nothrow 677 { 678 double result = 0; 679 int i,j,k; 680 double y,x; 681 682 for (j = 0; j < ELP20_SIZE; j++) { 683 y = elp20[j].theta * DEG; 684 for (k = 0; k < 2; k++) { 685 for (i = 0; i < 4; i++) 686 y += elp20[j].ipla[i + 7] * del[i][k] * t[k]; 687 for (i = 0; i < 7; i++) 688 y += elp20[j].ipla[i] * p[i][k] * t[k]; 689 } 690 /* put y in correct quad */ 691 y = ln_range_radians2(y); 692 x = elp20[j].O * t[1]; 693 result += x * sin(y); 694 } 695 return result; 696 } 697 698 static @nogc double sum_series_elp21(double[] t) nothrow 699 { 700 double result = 0; 701 int i,j,k; 702 double y,x; 703 704 for (j = 0; j < ELP21_SIZE; j++) { 705 y = elp21[j].theta * DEG; 706 for (k = 0; k < 2; k++) { 707 for (i = 0; i < 4; i++) 708 y += elp21[j].ipla[i + 7] * del[i][k] * t[k]; 709 for (i = 0; i < 7; i++) 710 y += elp21[j].ipla[i] * p[i][k] * t[k]; 711 } 712 /* put y in correct quad */ 713 y = ln_range_radians2(y); 714 x = elp21[j].O * t[1]; 715 result += x * sin(y); 716 } 717 return result; 718 } 719 720 /* sum lunar elp22 series */ 721 static @nogc double sum_series_elp22(double[] t) nothrow 722 { 723 double result = 0; 724 int i,j,k; 725 double y; 726 727 for (j = 0; j < ELP22_SIZE; j++) { 728 y = elp22[j].O * DEG; 729 for (k = 0; k < 2; k++) { 730 y += elp22[j].iz * zeta[k] * t[k]; 731 for (i = 0; i < 4; i++) 732 y += elp22[j].ilu[i] * del[i][k] * t[k]; 733 } 734 /* put y in correct quad */ 735 y = ln_range_radians2(y); 736 result += elp22[j].A * sin(y); 737 } 738 return result; 739 } 740 741 /* sum lunar elp23 series */ 742 static @nogc double sum_series_elp23(double[] t) nothrow 743 { 744 double result = 0; 745 int i,j,k; 746 double y; 747 748 for (j = 0; j < ELP23_SIZE; j++) { 749 y = elp23[j].O * DEG; 750 for (k = 0; k < 2; k++) { 751 y += elp23[j].iz * zeta[k] * t[k]; 752 for (i = 0; i < 4; i++) 753 y += elp23[j].ilu[i] * del[i][k] * t[k]; 754 } 755 /* put y in correct quad */ 756 y = ln_range_radians2(y); 757 result += elp23[j].A * sin(y); 758 } 759 return result; 760 } 761 762 /* sum lunar elp24 series */ 763 static @nogc double sum_series_elp24(double[] t) nothrow 764 { 765 double result = 0; 766 int i,j,k; 767 double y; 768 769 for (j = 0; j < ELP24_SIZE; j++) { 770 y = elp24[j].O * DEG; 771 for (k = 0; k < 2; k++) { 772 y += elp24[j].iz * zeta[k] * t[k]; 773 for (i = 0; i < 4; i++) 774 y += elp24[j].ilu[i] * del[i][k] * t[k]; 775 } 776 /* put y in correct quad */ 777 y = ln_range_radians2(y); 778 result += elp24[j].A * sin(y); 779 } 780 return result; 781 } 782 783 /* sum lunar elp25 series */ 784 static @nogc double sum_series_elp25(double[] t) nothrow 785 { 786 double result = 0; 787 int i,j,k; 788 double y, A; 789 790 for (j = 0; j < ELP25_SIZE; j++) { 791 A = elp25[j].A * t[1]; 792 y = elp25[j].O * DEG; 793 for (k = 0; k < 2; k++) { 794 y += elp25[j].iz * zeta[k] * t[k]; 795 for (i = 0; i < 4; i++) 796 y += elp25[j].ilu[i] * del[i][k] * t[k]; 797 } 798 /* put y in correct quad */ 799 y = ln_range_radians2(y); 800 result += A * sin(y); 801 } 802 return result; 803 } 804 805 /* sum lunar elp26 series */ 806 static @nogc double sum_series_elp26(double[] t) nothrow 807 { 808 double result = 0; 809 int i,j,k; 810 double y, A; 811 812 for (j = 0; j < ELP26_SIZE; j++) { 813 A = elp26[j].A * t[1]; 814 y = elp26[j].O * DEG; 815 for (k = 0; k < 2; k++) { 816 y += elp26[j].iz * zeta[k] * t[k]; 817 for (i = 0; i < 4; i++) 818 y += elp26[j].ilu[i] * del[i][k] * t[k]; 819 } 820 /* put y in correct quad */ 821 y = ln_range_radians2(y); 822 result += A * sin(y); 823 } 824 return result; 825 } 826 827 /* sum lunar elp27 series */ 828 static @nogc double sum_series_elp27(double[] t) nothrow 829 { 830 double result = 0; 831 int i,j,k; 832 double y, A; 833 834 for (j = 0; j < ELP27_SIZE; j++) { 835 A = elp27[j].A * t[1]; 836 y = elp27[j].O * DEG; 837 for (k = 0; k < 2; k++) { 838 y += elp27[j].iz * zeta[k] * t[k]; 839 for (i = 0; i < 4; i++) 840 y += elp27[j].ilu[i] * del[i][k] * t[k]; 841 } 842 /* put y in correct quad */ 843 y = ln_range_radians2(y); 844 result += A * sin(y); 845 } 846 return result; 847 } 848 849 /* sum lunar elp28 series */ 850 static @nogc double sum_series_elp28(double[] t) nothrow 851 { 852 double result = 0; 853 int i,j,k; 854 double y; 855 856 for (j = 0; j < ELP28_SIZE; j++) { 857 y = elp28[j].O * DEG; 858 for (k = 0; k < 2; k++) { 859 y += elp28[j].iz * zeta[k] * t[k]; 860 for (i = 0; i < 4; i++) 861 y += elp28[j].ilu[i] * del[i][k] * t[k]; 862 } 863 /* put y in correct quad */ 864 y = ln_range_radians2(y); 865 result += elp28[j].A * sin(y); 866 } 867 return result; 868 } 869 870 /* sum lunar elp29 series */ 871 static @nogc double sum_series_elp29(double[] t) nothrow 872 { 873 double result = 0; 874 int i,j,k; 875 double y; 876 877 for (j = 0; j < ELP29_SIZE; j++) { 878 y = elp29[j].O * DEG; 879 for (k = 0; k < 2; k++) { 880 y += elp29[j].iz * zeta[k] * t[k]; 881 for (i = 0; i < 4; i++) 882 y += elp29[j].ilu[i] * del[i][k] * t[k]; 883 } 884 /* put y in correct quad */ 885 y = ln_range_radians2(y); 886 result += elp29[j].A * sin(y); 887 } 888 return result; 889 } 890 891 892 /* sum lunar elp30 series */ 893 static @nogc double sum_series_elp30(double[] t) nothrow 894 { 895 double result = 0; 896 int i,j,k; 897 double y; 898 899 for (j = 0; j < ELP30_SIZE; j++) { 900 y = elp30[j].O * DEG; 901 for (k = 0; k < 2; k++) { 902 y += elp30[j].iz * zeta[k] * t[k]; 903 for (i = 0; i < 4; i++) 904 y += elp30[j].ilu[i] * del[i][k] * t[k]; 905 } 906 /* put y in correct quad */ 907 y = ln_range_radians2(y); 908 result += elp30[j].A * sin(y); 909 } 910 return result; 911 } 912 913 914 /* sum lunar elp31 series */ 915 static @nogc double sum_series_elp31(double[] t) nothrow 916 { 917 double result = 0; 918 int i,j,k; 919 double y; 920 921 for (j = 0; j < ELP31_SIZE; j++) { 922 y = elp31[j].O * DEG; 923 for (k = 0; k < 2; k++) { 924 y += elp31[j].iz * zeta[k] * t[k]; 925 for (i = 0; i < 4; i++) 926 y += elp31[j].ilu[i] * del[i][k] * t[k]; 927 } 928 /* put y in correct quad */ 929 y = ln_range_radians2(y); 930 result += elp31[j].A * sin(y); 931 } 932 return result; 933 } 934 935 /* sum lunar elp32 series */ 936 static @nogc double sum_series_elp32(double[] t) nothrow 937 { 938 double result = 0; 939 int i,j,k; 940 double y; 941 942 for (j = 0; j < ELP32_SIZE; j++) { 943 y = elp32[j].O * DEG; 944 for (k = 0; k < 2; k++) { 945 y += elp32[j].iz * zeta[k] * t[k]; 946 for (i = 0; i < 4; i++) 947 y += elp32[j].ilu[i] * del[i][k] * t[k]; 948 } 949 /* put y in correct quad */ 950 y = ln_range_radians2(y); 951 result += elp32[j].A * sin(y); 952 } 953 return result; 954 } 955 956 /* sum lunar elp33 series */ 957 static @nogc double sum_series_elp33(double[] t) nothrow 958 { 959 double result = 0; 960 int i,j,k; 961 double y; 962 963 for (j = 0; j < ELP33_SIZE; j++) { 964 y = elp33[j].O * DEG; 965 for (k = 0; k < 2; k++) { 966 y += elp33[j].iz * zeta[k] * t[k]; 967 for (i = 0; i < 4; i++) 968 y += elp33[j].ilu[i] * del[i][k] * t[k]; 969 } 970 /* put y in correct quad */ 971 y = ln_range_radians2(y); 972 result += elp33[j].A * sin(y); 973 } 974 return result; 975 } 976 977 /* sum lunar elp34 series */ 978 static @nogc double sum_series_elp34(double[] t) nothrow 979 { 980 double result = 0; 981 int i,j,k; 982 double y, A; 983 984 for (j = 0; j < ELP34_SIZE; j++) { 985 A = elp34[j].A * t[2]; 986 y = elp34[j].O * DEG; 987 for (k = 0; k < 2; k++) { 988 y += elp34[j].iz * zeta[k] * t[k]; 989 for (i = 0; i < 4; i++) 990 y += elp34[j].ilu[i] * del[i][k] * t[k]; 991 } 992 /* put y in correct quad */ 993 y = ln_range_radians2(y); 994 result += A * sin(y); 995 } 996 return result; 997 } 998 /* sum lunar elp35 series */ 999 static @nogc double sum_series_elp35(double[] t) nothrow 1000 { 1001 double result = 0; 1002 int i,j,k; 1003 double y, A; 1004 1005 for (j = 0; j < ELP35_SIZE; j++) { 1006 A = elp35[j].A * t[2]; 1007 y = elp35[j].O * DEG; 1008 for (k = 0; k < 2; k++) { 1009 y += elp35[j].iz * zeta[k] * t[k]; 1010 for (i = 0; i < 4; i++) 1011 y += elp35[j].ilu[i] * del[i][k] * t[k]; 1012 } 1013 /* put y in correct quad */ 1014 y = ln_range_radians2(y); 1015 result += A * sin(y); 1016 } 1017 return result; 1018 } 1019 1020 /* sum lunar elp36 series */ 1021 static @nogc double sum_series_elp36(double[] t) nothrow 1022 { 1023 double result = 0; 1024 int i,j,k; 1025 double y, A; 1026 1027 for (j = 0; j < ELP36_SIZE; j++) { 1028 A = elp36[j].A * t[2]; 1029 y = elp36[j].O * DEG; 1030 for (k = 0; k < 2; k++) { 1031 y += elp36[j].iz * zeta[k] * t[k]; 1032 for (i = 0; i < 4; i++) 1033 y += elp36[j].ilu[i] * del[i][k] * t[k]; 1034 } 1035 /* put y in correct quad */ 1036 y = ln_range_radians2(y); 1037 result += A * sin(y); 1038 } 1039 return result; 1040 } 1041 1042 /* internal function used for find_max/find zero lunar phase calculations */ 1043 static @nogc double lunar_phase(double jd, ref double arg) nothrow 1044 { 1045 ln_lnlat_posn moon; 1046 ln_helio_posn sol; 1047 double phase; 1048 1049 ln_get_lunar_ecl_coords(jd, moon, 0); 1050 ln_get_solar_geom_coords(jd, sol); 1051 1052 phase = fmod((ln_rad_to_deg(moon.lng - sol.L)) 1053 + 3.0 * PI - arg, 2.0 * PI) - PI; 1054 1055 return phase; 1056 } 1057 1058 /* internal function used for find_max/find zero lunar phase calculations */ 1059 static @nogc double lunar_distance(double jd, ref double arg) nothrow 1060 { 1061 return ln_get_lunar_earth_dist(jd); 1062 } 1063 1064 /* internal function used for find_max/find zero lunar phase calculations */ 1065 static @nogc double lunar_neg_distance(double jd, ref double arg) nothrow 1066 { 1067 return -ln_get_lunar_earth_dist(jd); 1068 } 1069 1070 /* internal function used for find_max/find zero lunar phase calculations */ 1071 static @nogc double _lunar_ecl_lat(double jd, ref double arg) nothrow 1072 { 1073 ln_lnlat_posn pos; 1074 1075 ln_get_lunar_ecl_coords(jd, pos, 0); 1076 1077 return pos.lat; 1078 } 1079 1080 /*! \fn void ln_get_lunar_geo_posn(double JD, struct ln_rect_posn *pos, double precision); 1081 * \param JD Julian day. 1082 * \param pos Pointer to a geocentric position structure to held result. 1083 * \param precision The truncation level of the series in radians for longitude 1084 * and latitude and in km for distance. (Valid range 0 - 0.01, 0 being highest accuracy) 1085 * \ingroup lunar 1086 * 1087 * Calculate the rectangular geocentric lunar coordinates to the inertial mean 1088 * ecliptic and equinox of J2000. 1089 * The geocentric coordinates returned are in units of km. 1090 * 1091 * This function is based upon the Lunar Solution ELP2000-82B by 1092 * Michelle Chapront-Touze and Jean Chapront of the Bureau des Longitudes, 1093 * Paris. 1094 */ 1095 /* ELP 2000-82B theory */ 1096 @nogc void ln_get_lunar_geo_posn(double JD, ref ln_rect_posn moon, double precision) nothrow 1097 { 1098 double[5] t; 1099 double[36] elp; 1100 double a,b,c; 1101 double x,y,z; 1102 double pw,qw, pwqw, pw2, qw2, ra; 1103 1104 /* calc julian centuries */ 1105 t[0] = 1.0; 1106 t[1] =(JD - 2451545.0) / 36525.0; 1107 t[2] = t[1] * t[1]; 1108 t[3] = t[2] * t[1]; 1109 t[4] = t[3] * t[1]; 1110 1111 /* sum elp series */ 1112 elp[0] = sum_series_elp1(t); 1113 elp[1] = sum_series_elp2(t); 1114 elp[2] = sum_series_elp3(t); 1115 elp[3] = sum_series_elp4(t); 1116 elp[4] = sum_series_elp5(t); 1117 elp[5] = sum_series_elp6(t); 1118 elp[6] = sum_series_elp7(t); 1119 elp[7] = sum_series_elp8(t); 1120 elp[8] = sum_series_elp9(t); 1121 elp[9] = sum_series_elp10(t); 1122 elp[10] = sum_series_elp11(t); 1123 elp[11] = sum_series_elp12(t); 1124 elp[12] = sum_series_elp13(t); 1125 elp[13] = sum_series_elp14(t); 1126 elp[14] = sum_series_elp15(t); 1127 elp[15] = sum_series_elp16(t); 1128 elp[16] = sum_series_elp17(t); 1129 elp[17] = sum_series_elp18(t); 1130 elp[18] = sum_series_elp19(t); 1131 elp[19] = sum_series_elp20(t); 1132 elp[20] = sum_series_elp21(t); 1133 elp[21] = sum_series_elp22(t); 1134 elp[22] = sum_series_elp23(t); 1135 elp[23] = sum_series_elp24(t); 1136 elp[24] = sum_series_elp25(t); 1137 elp[25] = sum_series_elp26(t); 1138 elp[26] = sum_series_elp27(t); 1139 elp[27] = sum_series_elp28(t); 1140 elp[28] = sum_series_elp29(t); 1141 elp[29] = sum_series_elp30(t); 1142 elp[30] = sum_series_elp31(t); 1143 elp[31] = sum_series_elp32(t); 1144 elp[32] = sum_series_elp33(t); 1145 elp[33] = sum_series_elp34(t); 1146 elp[34] = sum_series_elp35(t); 1147 elp[35] = sum_series_elp36(t); 1148 1149 a = elp[0] + elp[3] + elp[6] + elp[9] + elp[12] + 1150 elp[15] + elp[18] + elp[21] + elp[24] + 1151 elp[27] + elp[30] + elp[33]; 1152 b = elp[1] + elp[4] + elp[7] + elp[10] + elp[13] + 1153 elp[16] + elp[19] + elp[22] + elp[25] + 1154 elp[28] + elp[31] + elp[34]; 1155 c = elp[2] + elp[5] + elp[8] + elp[11] + elp[14] + 1156 elp[17] + elp[20] + elp[23] + elp[26] + 1157 elp[29] + elp[32] + elp[35]; 1158 1159 /* calculate geocentric coords */ 1160 a = a / RAD + W1[0] + W1[1] * t[1] + W1[2] * t[2] + W1[3] * t[3] 1161 + W1[4] * t[4]; 1162 b = b / RAD; 1163 c = c * A0 / ATH; 1164 1165 x = c * cos(b); 1166 y = x * sin(a); 1167 x = x * cos(a); 1168 z = c * sin(b); 1169 1170 /* Laskars series */ 1171 pw = (P1 + P2 * t[1] + P3 * t[2] + P4 * t[3] + P5 * t[4]) * t[1]; 1172 qw = (Q1 + Q2 * t[1] + Q3 * t[2] + Q4 * t[3] + Q5 * t[4]) * t[1]; 1173 ra = 2.0 * sqrt(1.0 - pw * pw - qw * qw); 1174 pwqw = 2.0 * pw * qw; 1175 pw2 = 1.0 - 2.0 * pw * pw; 1176 qw2 = 1.0 - 2.0 * qw * qw; 1177 pw = pw * ra; 1178 qw = qw * ra; 1179 a = pw2 * x + pwqw * y + pw * z; 1180 b = pwqw * x + qw2 * y - qw * z; 1181 c = -pw * x + qw * y + (pw2 + qw2 - 1.0) * z; 1182 1183 /* save result */ 1184 moon.X = a; 1185 moon.Y = b; 1186 moon.Z = c; 1187 } 1188 1189 /*! \fn void ln_get_lunar_equ_coords_prec(double JD, struct ln_equ_posn *position, double precision); 1190 * \param JD Julian Day 1191 * \param position Pointer to a struct ln_lnlat_posn to store result. 1192 * \param precision The truncation level of the series in radians for longitude 1193 * and latitude and in km for distance. (Valid range 0 - 0.01, 0 being highest accuracy) 1194 * \ingroup lunar 1195 * 1196 * Calculate the lunar RA and DEC for Julian day JD. 1197 * Accuracy is better than 10 arcsecs in right ascension and 4 arcsecs in declination. 1198 */ 1199 @nogc void ln_get_lunar_equ_coords_prec(double JD, ref ln_equ_posn position, 1200 double precision) nothrow 1201 { 1202 ln_lnlat_posn ecl; 1203 1204 ln_get_lunar_ecl_coords(JD, ecl, precision); 1205 ln_get_equ_from_ecl(ecl, JD, position); 1206 } 1207 1208 /*! \fn void ln_get_lunar_equ_coords(double JD, struct ln_equ_posn *position); 1209 * \param JD Julian Day 1210 * \param position Pointer to a struct ln_lnlat_posn to store result. 1211 * \ingroup lunar 1212 * 1213 * Calculate the lunar RA and DEC for Julian day JD at the highest precision. 1214 * Accuracy is better than 10 arcsecs in right ascension and 4 arcsecs in declination. 1215 */ 1216 @nogc void ln_get_lunar_equ_coords(double JD, ref ln_equ_posn position) nothrow 1217 { 1218 ln_get_lunar_equ_coords_prec(JD, position, 0); 1219 } 1220 1221 /*! \fn void ln_get_lunar_ecl_coords(double JD, struct ln_lnlat_posn *position, double precision); 1222 * \param JD Julian Day 1223 * \param position Pointer to a struct ln_lnlat_posn to store result. 1224 * \param precision The truncation level of the series in radians for longitude 1225 * and latitude and in km for distance. (Valid range 0 - 0.01, 0 being highest accuracy) 1226 * \ingroup lunar 1227 * 1228 * Calculate the lunar longitude and latitude for Julian day JD. 1229 * Accuracy is better than 10 arcsecs in longitude and 4 arcsecs in latitude. 1230 * 1231 * Per Meeus, chapter 47, if you need higher precision than this, see 1232 * Chaperont's _Lunar Tables and Programs_. 1233 */ 1234 @nogc void ln_get_lunar_ecl_coords(double JD, ref ln_lnlat_posn position, 1235 double precision) nothrow 1236 { 1237 ln_rect_posn moon; 1238 1239 /* get lunar geocentric position */ 1240 ln_get_lunar_geo_posn(JD, moon, precision); 1241 1242 /* convert to long and lat */ 1243 position.lng = atan2(moon.Y, moon.X); 1244 position.lat = atan2(moon.Z, 1245 (sqrt((moon.X * moon.X) + (moon.Y * moon.Y)))); 1246 position.lng = ln_range_degrees(ln_rad_to_deg(position.lng)); 1247 position.lat = ln_rad_to_deg(position.lat); 1248 } 1249 1250 /*! \fn double ln_get_lunar_earth_dist(double JD); 1251 * \param JD Julian Day 1252 * \return The distance between the Earth and Moon in km. 1253 * \ingroup lunar 1254 * 1255 * Calculates the distance between the centre of the Earth and the 1256 * centre of the Moon in km. 1257 */ 1258 @nogc double ln_get_lunar_earth_dist(double JD) nothrow 1259 { 1260 ln_rect_posn moon; 1261 1262 ln_get_lunar_geo_posn(JD, moon, 0.00001); 1263 return sqrt((moon.X * moon.X) + (moon.Y * moon.Y) + (moon.Z * moon.Z)); 1264 } 1265 1266 1267 /*! \fn double ln_get_lunar_phase(double JD); 1268 * \param JD Julian Day 1269 * \return Phase angle. (Value between 0 and 180) 1270 * \ingroup lunar 1271 * 1272 * Calculates the angle Sun - Moon - Earth. 1273 */ 1274 @nogc double ln_get_lunar_phase(double JD) nothrow 1275 { 1276 double phase = 0; 1277 ln_lnlat_posn moon, sunlp; 1278 double lunar_elong; 1279 double R, delta; 1280 1281 /* get lunar and solar long + lat */ 1282 ln_get_lunar_ecl_coords(JD, moon, 0.0001); 1283 ln_get_solar_ecl_coords(JD, sunlp); 1284 1285 /* calc lunar geocentric elongation equ 48.2 */ 1286 lunar_elong = acos(cos(ln_deg_to_rad(moon.lat)) * 1287 cos(ln_deg_to_rad(sunlp.lng - moon.lng))); 1288 1289 /* now calc phase Equ 48.2 */ 1290 R = ln_get_earth_solar_dist(JD); 1291 delta = ln_get_lunar_earth_dist(JD); 1292 R = R * AU; /* convert R to km */ 1293 phase = atan2((R * sin(lunar_elong)), (delta - R * cos(lunar_elong))); 1294 return ln_rad_to_deg(phase); 1295 } 1296 1297 /*! \fn double ln_get_lunar_disk(double JD); 1298 * \param JD Julian Day 1299 * \return Illuminated fraction. (Value between 0 and 1) 1300 * \brief Calculate the illuminated fraction of the moons disk 1301 * \ingroup lunar 1302 * 1303 * Calculates the illuminated fraction of the Moon's disk. 1304 */ 1305 @nogc double ln_get_lunar_disk(double JD) nothrow 1306 { 1307 double i; 1308 1309 /* Equ 48.1 */ 1310 i = ln_deg_to_rad(ln_get_lunar_phase(JD)); 1311 return (1.0 + cos(i)) / 2.0; 1312 } 1313 1314 /*! \fn double ln_get_lunar_bright_limb(double JD); 1315 * \param JD Julian Day 1316 * \return The position angle in degrees. 1317 * \brief Calculate the position angle of the Moon's bright limb. 1318 * \ingroup lunar 1319 * 1320 * Calculates the position angle of the midpoint of the illuminated limb of the 1321 * moon, reckoned eastward from the north point of the disk. 1322 * 1323 * The angle is near 270 deg for first quarter and near 90 deg after a full moon. 1324 * The position angle of the cusps are +90 deg and -90 deg. 1325 */ 1326 @nogc double ln_get_lunar_bright_limb(double JD) nothrow 1327 { 1328 double angle; 1329 double x,y; 1330 1331 ln_equ_posn moon, sunlp; 1332 1333 /* get lunar and solar long + lat */ 1334 ln_get_lunar_equ_coords(JD, moon); 1335 ln_get_solar_equ_coords(JD, sunlp); 1336 1337 /* Equ 48.5 */ 1338 x = cos(ln_deg_to_rad(sunlp.dec)) * sin(ln_deg_to_rad(sunlp.ra - moon.ra)); 1339 y = sin((ln_deg_to_rad(sunlp.dec)) * cos(ln_deg_to_rad(moon.dec))) 1340 - (cos(ln_deg_to_rad(sunlp.dec)) * sin(ln_deg_to_rad(moon.dec)) 1341 * cos(ln_deg_to_rad(sunlp.ra - moon.ra))); 1342 angle = atan2(x,y); 1343 1344 angle = ln_range_radians(angle); 1345 return ln_rad_to_deg(angle); 1346 } 1347 1348 1349 /*! \fn double ln_get_lunar_rst(double JD, struct ln_lnlat_posn *observer, struct ln_rst_time *rst); 1350 * \param JD Julian day 1351 * \param observer Observers position 1352 * \param rst Pointer to store Rise, Set and Transit time in JD 1353 * \return 0 for success, else 1 for circumpolar. 1354 * \todo Improve lunar standard altitude for rst 1355 * 1356 * Calculate the time the rise, set and transit (crosses the local meridian at upper culmination) 1357 * time of the Moon for the given Julian day. 1358 * 1359 * Note: this functions returns 1 if the Moon is circumpolar, that is it remains the whole 1360 * day either above or below the horizon. 1361 */ 1362 @nogc int ln_get_lunar_rst(double JD, const ref ln_lnlat_posn observer, 1363 ref ln_rst_time rst) nothrow 1364 { 1365 return ln_get_body_rst_horizon(JD, observer, 1366 cast(get_equ_body_coords_t)&ln_get_lunar_equ_coords, 1367 LN_LUNAR_STANDART_HORIZON, rst); 1368 } 1369 1370 /*! \fn double ln_get_lunar_sdiam(double JD) 1371 * \param JD Julian day 1372 * \return Semidiameter in arc seconds 1373 * \todo Use Topocentric distance. 1374 * 1375 * Calculate the semidiameter of the Moon in arc seconds for the 1376 * given julian day. 1377 */ 1378 @nogc double ln_get_lunar_sdiam(double JD) nothrow 1379 { 1380 double So = 358473400; 1381 double dist; 1382 1383 dist = ln_get_lunar_earth_dist(JD); 1384 return So / dist; 1385 } 1386 1387 /*! \fn double ln_get_lunar_long_asc_node(double JD); 1388 * \param JD Julian Day. 1389 * \return Longitude of ascending node in degrees. 1390 * 1391 * Calculate the mean longitude of the Moons ascending node 1392 * for the given Julian day. 1393 */ 1394 @nogc double ln_get_lunar_long_asc_node(double JD) nothrow 1395 { 1396 /* calc julian centuries */ 1397 double T =(JD - 2451545.0) / 36525.0; 1398 double omega = 125.0445479; 1399 double T2 = T * T; 1400 double T3 = T2 * T; 1401 double T4 = T3 * T; 1402 1403 /* equ 47.7 */ 1404 omega -= 1934.1362891 * T + 0.0020754 * T2 + T3 / 467441.0 - 1405 T4 / 60616000.0; 1406 return omega; 1407 } 1408 1409 1410 /*! \fn double ln_get_lunar_long_perigee(double JD); 1411 * \param JD Julian Day 1412 * \return Longitude of Moons mean perigee in degrees. 1413 * 1414 * Calculate the longitude of the Moon's mean perigee. 1415 */ 1416 @nogc double ln_get_lunar_long_perigee(double JD) nothrow 1417 { 1418 /* calc julian centuries */ 1419 double T =(JD - 2451545.0) / 36525.0; 1420 double per = 83.3532465; 1421 double T2 = T * T; 1422 double T3 = T2 * T; 1423 double T4 = T3 * T; 1424 1425 /* equ 47.7 */ 1426 per += 4069.0137287 * T - 0.0103200 * T2 - 1427 T3 / 80053.0 + T4 / 18999000.0; 1428 return per; 1429 } 1430 1431 /*! \fn double ln_get_lunar_arg_latitude(double JD); 1432 * \param JD Julian Day 1433 * \return Moon's argument of latitude 1434 * 1435 * Calculate the Moon's argument of latitude (mean distance of the Moon from its ascending node) 1436 */ 1437 @nogc double ln_get_lunar_arg_latitude(double JD) nothrow 1438 { 1439 /* calc julian centuries */ 1440 double T =(JD - 2451545.0) / 36525.0; 1441 double arg = 93.2720993; 1442 double T2 = T * T; 1443 double T3 = T2 * T; 1444 double T4 = T3 * T; 1445 1446 /* equ 45.5 */ 1447 arg += 483202.0175273 * T - 0.0034029 * T2 - 1448 T3 / 3526000.0 + T4 / 863310000.0; 1449 1450 return arg; 1451 } 1452 1453 @nogc void ln_get_lunar_selenographic_coords(double JD, ref ln_lnlat_posn moon, 1454 ref ln_lnlat_posn position) nothrow 1455 { 1456 /* equ 51.1 */ 1457 static const double I = 0.02692030744861093755; // 1.54242 deg in radians 1458 double Omega = ln_get_lunar_long_asc_node(JD); 1459 double W = ln_deg_to_rad(moon.lng - Omega); 1460 double F = ln_get_lunar_arg_latitude(JD); 1461 1462 double tan_Ay = sin(W) * cos(ln_deg_to_rad(moon.lat)) * cos(I) - 1463 sin(ln_deg_to_rad(moon.lat)) * sin(I); 1464 double tan_Ax = cos(W) * cos(ln_deg_to_rad(moon.lat)); 1465 1466 position.lng = 1467 ln_range_degrees(ln_rad_to_deg(atan2(tan_Ay, tan_Ax)) - F); 1468 position.lng = 1469 (position.lng > 180.0 ? position.lng - 360.0 : position.lng); 1470 position.lat = 1471 ln_rad_to_deg(asin(-sin(W) * cos(ln_deg_to_rad(moon.lat)) * sin(I) - 1472 sin(ln_deg_to_rad(moon.lat))*cos(I))); 1473 } 1474 1475 /*! \fn void ln_get_lunar_opt_libr_coords(double JD, struct ln_lnlat_posn *position) 1476 * \param JD Julian Day 1477 * \param position Pointer to a struct ln_lnlat_posn to store result. 1478 * 1479 * Calculate Lunar optical libration coordinates, also known as selenographic Earth coordinates. 1480 * This is a point on the surface of the Moon where the Earth is in the zenith. 1481 */ 1482 @nogc void ln_get_lunar_opt_libr_coords(double JD, ref ln_lnlat_posn position) nothrow 1483 { 1484 ln_lnlat_posn moon; 1485 ln_get_lunar_ecl_coords(JD, moon, 0); 1486 ln_get_lunar_selenographic_coords(JD, moon, position); 1487 } 1488 1489 /*! \fn void ln_get_lunar_subsolar_coords(double JD, struct ln_lnlat_posn *position) 1490 * \param JD Julian Day 1491 * \param position Pointer to a struct ln_lnlat_posn to store result. 1492 * 1493 * Calculate coordinates of the subsolar point, aslo known as selenographic coordinates of the Sun. 1494 * This is a point on the surface of the Moon where the Sun is in the zenith. 1495 */ 1496 @nogc void ln_get_lunar_subsolar_coords(double JD, ref ln_lnlat_posn position) nothrow 1497 { 1498 ln_lnlat_posn moon; 1499 ln_lnlat_posn sun; 1500 double EM_dist = ln_get_lunar_earth_dist(JD); 1501 double ES_dist = ln_get_earth_solar_dist(JD) * AU; 1502 double dist_ratio = EM_dist / ES_dist; 1503 1504 ln_get_solar_ecl_coords(JD, sun); 1505 ln_get_lunar_ecl_coords(JD, moon, 0); 1506 1507 moon.lng = sun.lng + 180.0 + 57.296 * dist_ratio * 1508 cos(ln_deg_to_rad(moon.lat)) * 1509 sin(ln_deg_to_rad(sun.lng - moon.lng)); 1510 moon.lat = dist_ratio * moon.lat; 1511 1512 ln_get_lunar_selenographic_coords(JD, moon, position); 1513 } 1514 1515 /* 1516 * Notes on phase calculations. 1517 * In general, exact k cannot be easily computed (Meeus chapter 46 gives 1518 * approximation formula) and there is no guarantee that you can compute 1519 * exactly k for *next* (not accidentally previous) phase (or opposite - 1520 * previous, not accidentally next). 1521 1522 * Therefore k is firstly approximated and decreased (or increased) by 2 1523 * and then while loop increase this k until nd (JD of mean phase) is fisrt 1524 * one below or above given JD. This loop runs several times (1-3) only. 1525 */ 1526 1527 /*! \fn double ln_lunar_next_phase(double jd, double phase) 1528 * \param jd Julian Day 1529 * \param phase 0 for new moon, 0.25 for first quarter, 0.5 for full moon, 0.75 for last quarter 1530 * \return Julian day when the moon will next be at the specified phase. 1531 * 1532 * Find next moon phase relative to given time expressed as Julian Day. 1533 * 1534 */ 1535 @nogc double ln_lunar_next_phase(double jd, double phase) nothrow 1536 { 1537 double ph, k, angle; 1538 1539 k = floor((jd - 2451550.09766) / 29.530588861) + phase - 2.0; 1540 1541 while ((ph = 2451550.09766 + 29.530588861 * k + 0.00015437 * 1542 (k / 1236.85) * (k / 1236.85)) < jd) 1543 k += 1.0; 1544 1545 angle = 2.0 * PI * phase; 1546 1547 while ((ph = ln_find_zero(cast(find_zero_t)&lunar_phase, ph, ph + 0.01, angle)) < jd) 1548 ph += 29.530588861; 1549 1550 return ph; 1551 } 1552 1553 /*! \fn double ln_lunar_previous_phase(double jd, double phase) 1554 * \param jd Julian Day 1555 * \param phase 0 for new moon, 0.25 for first quarter, 0.5 for full moon, 0.75 for last quarter 1556 * \return Julian day when the moon was last at the specified phase 1557 * 1558 * Find previous moon phase relative to given time expressed as Julian Day. 1559 * 1560 */ 1561 @nogc double ln_lunar_previous_phase(double jd, double phase) nothrow 1562 { 1563 double ph, k, angle; 1564 1565 k = floor((jd - 2451550.09766) / 29.530588861) + phase + 2.0; 1566 1567 while ((ph = 2451550.09766 + 29.530588861 * k + 0.00015437 * 1568 (k / 1236.85) * (k / 1236.85)) > jd) 1569 k -= 1.0; 1570 1571 angle = 2.0 * PI * phase; 1572 1573 while ((ph = ln_find_zero(&lunar_phase, ph, ph + 0.01, angle)) > jd) 1574 ph -= 29.530588861; 1575 1576 return ph; 1577 } 1578 1579 /*! \fn double ln_lunar_next_apsis(double jd, int mode) 1580 * \param jd Julian Day 1581 * \param apogee 0 for perigee, 1 for apogee 1582 * 1583 * Find next moon apogee or perigee relative to given time expressed as Julian Day. 1584 * 1585 */ 1586 @nogc double ln_lunar_next_apsis(double jd, int apogee) nothrow 1587 { 1588 double ap, k; 1589 1590 k = floor((jd - 2451534.6698) / 27.55454989) + (0.5 * apogee) - 2.0; 1591 1592 while ((ap = 2451534.6698 + 27.55454989 * k + 0.0006691 * 1593 (k / 1325.55) * (k / 1325.55)) < jd) 1594 k += 1.0; 1595 1596 double ignored; 1597 if (apogee) { 1598 while ((ap = ln_find_max(&lunar_distance, ap - 3.0, ap + 3.0, ignored)) < jd) 1599 ap += 27.55454989; 1600 } else { 1601 while ((ap = ln_find_max(&lunar_neg_distance, ap - 3.0, ap + 3.0, ignored)) < jd) 1602 ap += 27.55454989; 1603 } 1604 1605 return ap; 1606 } 1607 1608 /*! \fn double ln_lunar_previous_apsis(double jd, int mode) 1609 * \param jd Julian Day 1610 * \param apogee 0 for perigee, 1 for apogee 1611 * 1612 * Find previous moon apogee or perigee relative to given time expressed as Julian Day. 1613 * 1614 */ 1615 @nogc double ln_lunar_previous_apsis(double jd, int apogee) nothrow 1616 { 1617 double ap, k; 1618 1619 k = floor((jd - 2451534.6698) / 27.55454989) + (0.5 * apogee) + 2.0; 1620 1621 while ((ap = 2451534.6698 + 27.55454989 * k + 0.0006691 * 1622 (k / 1325.55) * (k / 1325.55)) > jd) 1623 k -= 1.0; 1624 1625 double ignored; 1626 if (apogee) { 1627 while ((ap = ln_find_max(&lunar_distance, ap - 3.0, ap + 3.0, ignored)) > jd) 1628 ap -= 27.55454989; 1629 } else { 1630 while ((ap = ln_find_max(&lunar_neg_distance, ap - 3.0, ap + 3.0, ignored)) > jd) 1631 ap -= 27.55454989; 1632 } 1633 1634 return ap; 1635 } 1636 1637 /*! \fn double ln_lunar_next_node(double jd, int mode) 1638 * \param jd Julian Day 1639 * \param mode 0 for ascending, 1 for descending 1640 * \return Julian day when the moon will next be at the specified node. 1641 * 1642 * Find next moon node relative to given time expressed as Julian Day. 1643 * 1644 */ 1645 @nogc double ln_lunar_next_node(double jd, int mode) nothrow 1646 { 1647 double nd, k; 1648 1649 k = floor((jd - 2451565.1619) / 27.212220817) + (0.5 * mode) - 2.0; 1650 1651 while ((nd = 2451565.1619 + 27.212220817 * k) < jd) 1652 k += 1.0; 1653 1654 double ignored; 1655 while ((nd = ln_find_zero(&_lunar_ecl_lat, nd - 3.0, 1656 nd + 3.0, ignored)) < jd) 1657 nd += 27.212220817; 1658 1659 return nd; 1660 } 1661 1662 /*! \fn double ln_lunar_previous_node(double jd, int mode) 1663 * \param jd Julian Day 1664 * \param mode 0 for ascending, 1 for descending 1665 * \return Julian day when the moon was last at the specified node. 1666 * 1667 * Find previous lunar node relative to given time expressed as Julian Day. 1668 * 1669 */ 1670 @nogc double ln_lunar_previous_node(double jd, int mode) nothrow 1671 { 1672 double nd, k; 1673 1674 k = floor((jd - 2451565.1619) / 27.212220817) + (0.5 * mode) + 2.0; 1675 1676 while ((nd = 2451565.1619 + 27.212220817 * k) > jd) 1677 k -= 1.0; 1678 1679 double ignored; 1680 while ((nd = ln_find_zero(&_lunar_ecl_lat, nd - 3.0, 1681 nd + 3.0, ignored)) > jd) 1682 nd -= 27.212220817 ; 1683 1684 return nd; 1685 } 1686 1687 /*! \example lunar.c 1688 * 1689 * Examples of how to use Lunar functions. 1690 */ 1691 1692 }