Coverage Report

Created: 2025-01-28 06:38

/src/icu/source/i18n/astro.h
Line
Count
Source (jump to first uncovered line)
1
// © 2016 and later: Unicode, Inc. and others.
2
// License & terms of use: http://www.unicode.org/copyright.html
3
/************************************************************************
4
 * Copyright (C) 1996-2008, International Business Machines Corporation *
5
 * and others. All Rights Reserved.                                     *
6
 ************************************************************************
7
 *  2003-nov-07   srl       Port from Java
8
 */
9
10
#ifndef ASTRO_H
11
#define ASTRO_H
12
13
#include "unicode/utypes.h"
14
15
#if !UCONFIG_NO_FORMATTING
16
17
#include "gregoimp.h"  // for Math
18
#include "unicode/unistr.h"
19
20
U_NAMESPACE_BEGIN
21
22
/**
23
 * <code>CalendarAstronomer</code> is a class that can perform the calculations to
24
 * determine the positions of the sun and moon, the time of sunrise and
25
 * sunset, and other astronomy-related data.  The calculations it performs
26
 * are in some cases quite complicated, and this utility class saves you
27
 * the trouble of worrying about them.
28
 * <p>
29
 * The measurement of time is a very important part of astronomy.  Because
30
 * astronomical bodies are constantly in motion, observations are only valid
31
 * at a given moment in time.  Accordingly, each <code>CalendarAstronomer</code>
32
 * object has a <code>time</code> property that determines the date
33
 * and time for which its calculations are performed.  You can set and
34
 * retrieve this property with {@link #setDate setDate}, {@link #getDate getDate}
35
 * and related methods.
36
 * <p>
37
 * Almost all of the calculations performed by this class, or by any
38
 * astronomer, are approximations to various degrees of accuracy.  The
39
 * calculations in this class are mostly modelled after those described
40
 * in the book
41
 * <a href="http://www.amazon.com/exec/obidos/ISBN=0521356997" target="_top">
42
 * Practical Astronomy With Your Calculator</a>, by Peter J.
43
 * Duffett-Smith, Cambridge University Press, 1990.  This is an excellent
44
 * book, and if you want a greater understanding of how these calculations
45
 * are performed it a very good, readable starting point.
46
 * <p>
47
 * <strong>WARNING:</strong> This class is very early in its development, and
48
 * it is highly likely that its API will change to some degree in the future.
49
 * At the moment, it basically does just enough to support {@link IslamicCalendar}
50
 * and {@link ChineseCalendar}.
51
 *
52
 * @author Laura Werner
53
 * @author Alan Liu
54
 * @internal
55
 */
56
class U_I18N_API CalendarAstronomer : public UMemory {
57
public:
58
  // some classes
59
60
public:
61
  /**
62
   * Represents the position of an object in the sky relative to the ecliptic,
63
   * the plane of the earth's orbit around the Sun.
64
   * This is a spherical coordinate system in which the latitude
65
   * specifies the position north or south of the plane of the ecliptic.
66
   * The longitude specifies the position along the ecliptic plane
67
   * relative to the "First Point of Aries", which is the Sun's position in the sky
68
   * at the Vernal Equinox.
69
   * <p>
70
   * Note that Ecliptic objects are immutable and cannot be modified
71
   * once they are constructed.  This allows them to be passed and returned by
72
   * value without worrying about whether other code will modify them.
73
   *
74
   * @see CalendarAstronomer.Equatorial
75
   * @see CalendarAstronomer.Horizon
76
   * @internal
77
   */
78
  class U_I18N_API Ecliptic : public UMemory {
79
  public:
80
    /**
81
     * Constructs an Ecliptic coordinate object.
82
     * <p>
83
     * @param lat The ecliptic latitude, measured in radians.
84
     * @param lon The ecliptic longitude, measured in radians.
85
     * @internal
86
     */
87
0
    Ecliptic(double lat = 0, double lon = 0) {
88
0
      latitude = lat;
89
0
      longitude = lon;
90
0
    }
91
92
    /**
93
     * Setter for Ecliptic Coordinate object
94
     * @param lat The ecliptic latitude, measured in radians.
95
     * @param lon The ecliptic longitude, measured in radians.
96
     * @internal
97
     */
98
0
    void set(double lat, double lon) {
99
0
      latitude = lat;
100
0
      longitude = lon;
101
0
    }
102
103
    /**
104
     * Return a string representation of this object
105
     * @internal
106
     */
107
    UnicodeString toString() const;
108
109
    /**
110
     * The ecliptic latitude, in radians.  This specifies an object's
111
     * position north or south of the plane of the ecliptic,
112
     * with positive angles representing north.
113
     * @internal
114
     */
115
    double latitude;
116
117
    /**
118
     * The ecliptic longitude, in radians.
119
     * This specifies an object's position along the ecliptic plane
120
     * relative to the "First Point of Aries", which is the Sun's position
121
     * in the sky at the Vernal Equinox,
122
     * with positive angles representing east.
123
     * <p>
124
     * A bit of trivia: the first point of Aries is currently in the
125
     * constellation Pisces, due to the precession of the earth's axis.
126
     * @internal
127
     */
128
    double longitude;
129
  };
130
131
  /**
132
   * Represents the position of an
133
   * object in the sky relative to the plane of the earth's equator.
134
   * The <i>Right Ascension</i> specifies the position east or west
135
   * along the equator, relative to the sun's position at the vernal
136
   * equinox.  The <i>Declination</i> is the position north or south
137
   * of the equatorial plane.
138
   * <p>
139
   * Note that Equatorial objects are immutable and cannot be modified
140
   * once they are constructed.  This allows them to be passed and returned by
141
   * value without worrying about whether other code will modify them.
142
   *
143
   * @see CalendarAstronomer.Ecliptic
144
   * @see CalendarAstronomer.Horizon
145
   * @internal
146
   */
147
  class U_I18N_API Equatorial : public UMemory {
148
  public:
149
    /**
150
     * Constructs an Equatorial coordinate object.
151
     * <p>
152
     * @param asc The right ascension, measured in radians.
153
     * @param dec The declination, measured in radians.
154
     * @internal
155
     */
156
    Equatorial(double asc = 0, double dec = 0)
157
0
      : ascension(asc), declination(dec) { }
158
159
    /**
160
     * Setter
161
     * @param asc The right ascension, measured in radians.
162
     * @param dec The declination, measured in radians.
163
     * @internal
164
     */
165
0
    void set(double asc, double dec) {
166
0
      ascension = asc;
167
0
      declination = dec;
168
0
    }
169
170
    /**
171
     * Return a string representation of this object, with the
172
     * angles measured in degrees.
173
     * @internal
174
     */
175
    UnicodeString toString() const;
176
177
    /**
178
     * Return a string representation of this object with the right ascension
179
     * measured in hours, minutes, and seconds.
180
     * @internal
181
     */
182
    //String toHmsString() {
183
    //return radToHms(ascension) + "," + radToDms(declination);
184
    //}
185
186
    /**
187
     * The right ascension, in radians.
188
     * This is the position east or west along the equator
189
     * relative to the sun's position at the vernal equinox,
190
     * with positive angles representing East.
191
     * @internal
192
     */
193
    double ascension;
194
195
    /**
196
     * The declination, in radians.
197
     * This is the position north or south of the equatorial plane,
198
     * with positive angles representing north.
199
     * @internal
200
     */
201
    double declination;
202
  };
203
204
  /**
205
   * Represents the position of an  object in the sky relative to
206
   * the local horizon.
207
   * The <i>Altitude</i> represents the object's elevation above the horizon,
208
   * with objects below the horizon having a negative altitude.
209
   * The <i>Azimuth</i> is the geographic direction of the object from the
210
   * observer's position, with 0 representing north.  The azimuth increases
211
   * clockwise from north.
212
   * <p>
213
   * Note that Horizon objects are immutable and cannot be modified
214
   * once they are constructed.  This allows them to be passed and returned by
215
   * value without worrying about whether other code will modify them.
216
   *
217
   * @see CalendarAstronomer.Ecliptic
218
   * @see CalendarAstronomer.Equatorial
219
   * @internal
220
   */
221
  class U_I18N_API Horizon : public UMemory {
222
  public:
223
    /**
224
     * Constructs a Horizon coordinate object.
225
     * <p>
226
     * @param alt  The altitude, measured in radians above the horizon.
227
     * @param azim The azimuth, measured in radians clockwise from north.
228
     * @internal
229
     */
230
    Horizon(double alt=0, double azim=0)
231
0
      : altitude(alt), azimuth(azim) { }
232
233
    /**
234
     * Setter for Ecliptic Coordinate object
235
     * @param alt  The altitude, measured in radians above the horizon.
236
     * @param azim The azimuth, measured in radians clockwise from north.
237
     * @internal
238
     */
239
0
    void set(double alt, double azim) {
240
0
      altitude = alt;
241
0
      azimuth = azim;
242
0
    }
243
244
    /**
245
     * Return a string representation of this object, with the
246
     * angles measured in degrees.
247
     * @internal
248
     */
249
    UnicodeString toString() const;
250
251
    /**
252
     * The object's altitude above the horizon, in radians.
253
     * @internal
254
     */
255
    double altitude;
256
257
    /**
258
     * The object's direction, in radians clockwise from north.
259
     * @internal
260
     */
261
    double azimuth;
262
  };
263
264
public:
265
  //-------------------------------------------------------------------------
266
  // Assorted private data used for conversions
267
  //-------------------------------------------------------------------------
268
269
  // My own copies of these so compilers are more likely to optimize them away
270
  static const double PI;
271
272
  /**
273
   * The average number of solar days from one new moon to the next.  This is the time
274
   * it takes for the moon to return the same ecliptic longitude as the sun.
275
   * It is longer than the sidereal month because the sun's longitude increases
276
   * during the year due to the revolution of the earth around the sun.
277
   * Approximately 29.53.
278
   *
279
   * @see #SIDEREAL_MONTH
280
   * @internal
281
   * @deprecated ICU 2.4. This class may be removed or modified.
282
   */
283
  static const double SYNODIC_MONTH;
284
285
  //-------------------------------------------------------------------------
286
  // Constructors
287
  //-------------------------------------------------------------------------
288
289
  /**
290
   * Construct a new <code>CalendarAstronomer</code> object that is initialized to
291
   * the current date and time.
292
   * @internal
293
   */
294
  CalendarAstronomer();
295
296
  /**
297
   * Construct a new <code>CalendarAstronomer</code> object that is initialized to
298
   * the specified date and time.
299
   * @internal
300
   */
301
  CalendarAstronomer(UDate d);
302
303
  /**
304
   * Construct a new <code>CalendarAstronomer</code> object with the given
305
   * latitude and longitude.  The object's time is set to the current
306
   * date and time.
307
   * <p>
308
   * @param longitude The desired longitude, in <em>degrees</em> east of
309
   *                  the Greenwich meridian.
310
   *
311
   * @param latitude  The desired latitude, in <em>degrees</em>.  Positive
312
   *                  values signify North, negative South.
313
   *
314
   * @see java.util.Date#getTime()
315
   * @internal
316
   */
317
  CalendarAstronomer(double longitude, double latitude);
318
319
  /**
320
   * Destructor
321
   * @internal
322
   */
323
  ~CalendarAstronomer();
324
325
  //-------------------------------------------------------------------------
326
  // Time and date getters and setters
327
  //-------------------------------------------------------------------------
328
329
  /**
330
   * Set the current date and time of this <code>CalendarAstronomer</code> object.  All
331
   * astronomical calculations are performed based on this time setting.
332
   *
333
   * @param aTime the date and time, expressed as the number of milliseconds since
334
   *              1/1/1970 0:00 GMT (Gregorian).
335
   *
336
   * @see #setDate
337
   * @see #getTime
338
   * @internal
339
   */
340
  void setTime(UDate aTime);
341
342
343
  /**
344
   * Set the current date and time of this <code>CalendarAstronomer</code> object.  All
345
   * astronomical calculations are performed based on this time setting.
346
   *
347
   * @param aTime the date and time, expressed as the number of milliseconds since
348
   *              1/1/1970 0:00 GMT (Gregorian).
349
   *
350
   * @see #getTime
351
   * @internal
352
   */
353
0
  void setDate(UDate aDate) { setTime(aDate); }
354
355
  /**
356
   * Set the current date and time of this <code>CalendarAstronomer</code> object.  All
357
   * astronomical calculations are performed based on this time setting.
358
   *
359
   * @param jdn   the desired time, expressed as a "julian day number",
360
   *              which is the number of elapsed days since
361
   *              1/1/4713 BC (Julian), 12:00 GMT.  Note that julian day
362
   *              numbers start at <em>noon</em>.  To get the jdn for
363
   *              the corresponding midnight, subtract 0.5.
364
   *
365
   * @see #getJulianDay
366
   * @see #JULIAN_EPOCH_MS
367
   * @internal
368
   */
369
  void setJulianDay(double jdn);
370
371
  /**
372
   * Get the current time of this <code>CalendarAstronomer</code> object,
373
   * represented as the number of milliseconds since
374
   * 1/1/1970 AD 0:00 GMT (Gregorian).
375
   *
376
   * @see #setTime
377
   * @see #getDate
378
   * @internal
379
   */
380
  UDate getTime();
381
382
  /**
383
   * Get the current time of this <code>CalendarAstronomer</code> object,
384
   * expressed as a "julian day number", which is the number of elapsed
385
   * days since 1/1/4713 BC (Julian), 12:00 GMT.
386
   *
387
   * @see #setJulianDay
388
   * @see #JULIAN_EPOCH_MS
389
   * @internal
390
   */
391
  double getJulianDay();
392
393
  /**
394
   * Return this object's time expressed in julian centuries:
395
   * the number of centuries after 1/1/1900 AD, 12:00 GMT
396
   *
397
   * @see #getJulianDay
398
   * @internal
399
   */
400
  double getJulianCentury();
401
402
  /**
403
   * Returns the current Greenwich sidereal time, measured in hours
404
   * @internal
405
   */
406
  double getGreenwichSidereal();
407
408
private:
409
  double getSiderealOffset();
410
public:
411
  /**
412
   * Returns the current local sidereal time, measured in hours
413
   * @internal
414
   */
415
  double getLocalSidereal();
416
417
  /**
418
   * Converts local sidereal time to Universal Time.
419
   *
420
   * @param lst   The Local Sidereal Time, in hours since sidereal midnight
421
   *              on this object's current date.
422
   *
423
   * @return      The corresponding Universal Time, in milliseconds since
424
   *              1 Jan 1970, GMT.
425
   */
426
  //private:
427
  double lstToUT(double lst);
428
429
  /**
430
   *
431
   * Convert from ecliptic to equatorial coordinates.
432
   *
433
   * @param ecliptic     The ecliptic
434
   * @param result       Fillin result
435
   * @return reference to result
436
   */
437
  Equatorial& eclipticToEquatorial(Equatorial& result, const Ecliptic& ecliptic);
438
439
  /**
440
   * Convert from ecliptic to equatorial coordinates.
441
   *
442
   * @param eclipLong     The ecliptic longitude
443
   * @param eclipLat      The ecliptic latitude
444
   *
445
   * @return              The corresponding point in equatorial coordinates.
446
   * @internal
447
   */
448
  Equatorial& eclipticToEquatorial(Equatorial& result, double eclipLong, double eclipLat);
449
450
  /**
451
   * Convert from ecliptic longitude to equatorial coordinates.
452
   *
453
   * @param eclipLong     The ecliptic longitude
454
   *
455
   * @return              The corresponding point in equatorial coordinates.
456
   * @internal
457
   */
458
  Equatorial& eclipticToEquatorial(Equatorial& result, double eclipLong) ;
459
460
  /**
461
   * @internal
462
   */
463
  Horizon& eclipticToHorizon(Horizon& result, double eclipLong) ;
464
465
  //-------------------------------------------------------------------------
466
  // The Sun
467
  //-------------------------------------------------------------------------
468
469
  /**
470
   * The longitude of the sun at the time specified by this object.
471
   * The longitude is measured in radians along the ecliptic
472
   * from the "first point of Aries," the point at which the ecliptic
473
   * crosses the earth's equatorial plane at the vernal equinox.
474
   * <p>
475
   * Currently, this method uses an approximation of the two-body Kepler's
476
   * equation for the earth and the sun.  It does not take into account the
477
   * perturbations caused by the other planets, the moon, etc.
478
   * @internal
479
   */
480
  double getSunLongitude();
481
482
  /**
483
   * TODO Make this public when the entire class is package-private.
484
   */
485
  /*public*/ void getSunLongitude(double julianDay, double &longitude, double &meanAnomaly);
486
487
  /**
488
   * The position of the sun at this object's current date and time,
489
   * in equatorial coordinates.
490
   * @param result fillin for the result
491
   * @internal
492
   */
493
  Equatorial& getSunPosition(Equatorial& result);
494
495
public:
496
  /**
497
   * Constant representing the vernal equinox.
498
   * For use with {@link #getSunTime getSunTime}.
499
   * Note: In this case, "vernal" refers to the northern hemisphere's seasons.
500
   * @internal
501
   */
502
//  static double VERNAL_EQUINOX();
503
504
  /**
505
   * Constant representing the summer solstice.
506
   * For use with {@link #getSunTime getSunTime}.
507
   * Note: In this case, "summer" refers to the northern hemisphere's seasons.
508
   * @internal
509
   */
510
  static double SUMMER_SOLSTICE();
511
512
  /**
513
   * Constant representing the autumnal equinox.
514
   * For use with {@link #getSunTime getSunTime}.
515
   * Note: In this case, "autumn" refers to the northern hemisphere's seasons.
516
   * @internal
517
   */
518
//  static double AUTUMN_EQUINOX();
519
520
  /**
521
   * Constant representing the winter solstice.
522
   * For use with {@link #getSunTime getSunTime}.
523
   * Note: In this case, "winter" refers to the northern hemisphere's seasons.
524
   * @internal
525
   */
526
  static double WINTER_SOLSTICE();
527
528
  /**
529
   * Find the next time at which the sun's ecliptic longitude will have
530
   * the desired value.
531
   * @internal
532
   */
533
  UDate getSunTime(double desired, UBool next);
534
535
  /**
536
   * Returns the time (GMT) of sunrise or sunset on the local date to which
537
   * this calendar is currently set.
538
   *
539
   * NOTE: This method only works well if this object is set to a
540
   * time near local noon.  Because of variations between the local
541
   * official time zone and the geographic longitude, the
542
   * computation can flop over into an adjacent day if this object
543
   * is set to a time near local midnight.
544
   *
545
   * @internal
546
   */
547
  UDate getSunRiseSet(UBool rise);
548
549
  //-------------------------------------------------------------------------
550
  // The Moon
551
  //-------------------------------------------------------------------------
552
553
  /**
554
   * The position of the moon at the time set on this
555
   * object, in equatorial coordinates.
556
   * @internal
557
   * @return const reference to internal field of calendar astronomer. Do not use outside of the lifetime of this astronomer.
558
   */
559
  const Equatorial& getMoonPosition();
560
561
  /**
562
   * The "age" of the moon at the time specified in this object.
563
   * This is really the angle between the
564
   * current ecliptic longitudes of the sun and the moon,
565
   * measured in radians.
566
   *
567
   * @see #getMoonPhase
568
   * @internal
569
   */
570
  double getMoonAge();
571
572
  /**
573
   * Calculate the phase of the moon at the time set in this object.
574
   * The returned phase is a <code>double</code> in the range
575
   * <code>0 <= phase < 1</code>, interpreted as follows:
576
   * <ul>
577
   * <li>0.00: New moon
578
   * <li>0.25: First quarter
579
   * <li>0.50: Full moon
580
   * <li>0.75: Last quarter
581
   * </ul>
582
   *
583
   * @see #getMoonAge
584
   * @internal
585
   */
586
  double getMoonPhase();
587
588
  class U_I18N_API MoonAge : public UMemory {
589
  public:
590
    MoonAge(double l)
591
0
      :  value(l) { }
592
0
    void set(double l) { value = l; }
593
    double value;
594
  };
595
596
  /**
597
   * Constant representing a new moon.
598
   * For use with {@link #getMoonTime getMoonTime}
599
   * @internal
600
   */
601
  static const MoonAge NEW_MOON();
602
603
  /**
604
   * Constant representing the moon's first quarter.
605
   * For use with {@link #getMoonTime getMoonTime}
606
   * @internal
607
   */
608
//  static const MoonAge FIRST_QUARTER();
609
610
  /**
611
   * Constant representing a full moon.
612
   * For use with {@link #getMoonTime getMoonTime}
613
   * @internal
614
   */
615
  static const MoonAge FULL_MOON();
616
617
  /**
618
   * Constant representing the moon's last quarter.
619
   * For use with {@link #getMoonTime getMoonTime}
620
   * @internal
621
   */
622
//  static const MoonAge LAST_QUARTER();
623
624
  /**
625
   * Find the next or previous time at which the Moon's ecliptic
626
   * longitude will have the desired value.
627
   * <p>
628
   * @param desired   The desired longitude.
629
   * @param next      <tt>true</tt> if the next occurrence of the phase
630
   *                  is desired, <tt>false</tt> for the previous occurrence.
631
   * @internal
632
   */
633
  UDate getMoonTime(double desired, UBool next);
634
  UDate getMoonTime(const MoonAge& desired, UBool next);
635
636
  /**
637
   * Returns the time (GMT) of sunrise or sunset on the local date to which
638
   * this calendar is currently set.
639
   * @internal
640
   */
641
  UDate getMoonRiseSet(UBool rise);
642
643
  //-------------------------------------------------------------------------
644
  // Interpolation methods for finding the time at which a given event occurs
645
  //-------------------------------------------------------------------------
646
647
  // private
648
  class AngleFunc : public UMemory {
649
  public:
650
    virtual double eval(CalendarAstronomer&) = 0;
651
    virtual ~AngleFunc();
652
  };
653
  friend class AngleFunc;
654
655
  UDate timeOfAngle(AngleFunc& func, double desired,
656
                    double periodDays, double epsilon, UBool next);
657
658
  class CoordFunc : public UMemory {
659
  public:
660
    virtual void eval(Equatorial& result, CalendarAstronomer&) = 0;
661
    virtual ~CoordFunc();
662
  };
663
  friend class CoordFunc;
664
665
  double riseOrSet(CoordFunc& func, UBool rise,
666
                   double diameter, double refraction,
667
                   double epsilon);
668
669
  //-------------------------------------------------------------------------
670
  // Other utility methods
671
  //-------------------------------------------------------------------------
672
private:
673
674
  /**
675
   * Return the obliquity of the ecliptic (the angle between the ecliptic
676
   * and the earth's equator) at the current time.  This varies due to
677
   * the precession of the earth's axis.
678
   *
679
   * @return  the obliquity of the ecliptic relative to the equator,
680
   *          measured in radians.
681
   */
682
  double eclipticObliquity();
683
684
  //-------------------------------------------------------------------------
685
  // Private data
686
  //-------------------------------------------------------------------------
687
private:
688
  /**
689
   * Current time in milliseconds since 1/1/1970 AD
690
   * @see java.util.Date#getTime
691
   */
692
  UDate fTime;
693
694
  /* These aren't used yet, but they'll be needed for sunset calculations
695
   * and equatorial to horizon coordinate conversions
696
   */
697
  double fLongitude;
698
  double fLatitude;
699
  double fGmtOffset;
700
701
  //
702
  // The following fields are used to cache calculated results for improved
703
  // performance.  These values all depend on the current time setting
704
  // of this object, so the clearCache method is provided.
705
  //
706
707
  double    julianDay;
708
  double    julianCentury;
709
  double    sunLongitude;
710
  double    meanAnomalySun;
711
  double    moonLongitude;
712
  double    moonEclipLong;
713
  double    meanAnomalyMoon;
714
  double    eclipObliquity;
715
  double    siderealT0;
716
  double    siderealTime;
717
718
  void clearCache();
719
720
  Equatorial  moonPosition;
721
  UBool       moonPositionSet;
722
723
  /**
724
   * @internal
725
   */
726
//  UDate local(UDate localMillis);
727
};
728
729
U_NAMESPACE_END
730
731
struct UHashtable;
732
733
U_NAMESPACE_BEGIN
734
735
/**
736
 * Cache of month -> julian day
737
 * @internal
738
 */
739
class CalendarCache : public UMemory {
740
public:
741
  static int32_t get(CalendarCache** cache, int32_t key, UErrorCode &status);
742
  static void put(CalendarCache** cache, int32_t key, int32_t value, UErrorCode &status);
743
  virtual ~CalendarCache();
744
private:
745
  CalendarCache(int32_t size, UErrorCode& status);
746
  static void createCache(CalendarCache** cache, UErrorCode& status);
747
  /**
748
   * not implemented
749
   */
750
  CalendarCache();
751
  UHashtable *fTable;
752
};
753
754
U_NAMESPACE_END
755
756
#endif
757
#endif