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