]> git.saurik.com Git - apple/icu.git/blame - icuSources/i18n/astro.h
ICU-6.2.14.tar.gz
[apple/icu.git] / icuSources / i18n / astro.h
CommitLineData
374ca955
A
1/************************************************************************
2 * Copyright (C) 1996-2003, 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
18U_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 */
54class U_I18N_API CalendarAstronomer : public UMemory {
55public:
56 // some classes
57
58public:
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 */
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)
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 */
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)
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 */
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
262public:
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 */
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
406private:
407 double getSiderealOffset();
408public:
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
493public:
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:
588 MoonAge(double l)
589 : value(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 U_I18N_API AngleFunc : public UMemory {
647 public:
648 virtual double eval(CalendarAstronomer&) = 0;
649 };
650 friend class AngleFunc;
651
652 UDate timeOfAngle(AngleFunc& func, double desired,
653 double periodDays, double epsilon, UBool next);
654
655 class U_I18N_API CoordFunc : public UMemory {
656 public:
657 virtual void eval(Equatorial& result, CalendarAstronomer&) = 0;
658 };
659 friend class CoordFunc;
660
661 double riseOrSet(CoordFunc& func, UBool rise,
662 double diameter, double refraction,
663 double epsilon);
664
665 //-------------------------------------------------------------------------
666 // Other utility methods
667 //-------------------------------------------------------------------------
668private:
669 /***
670 * Given 'value', add or subtract 'range' until 0 <= 'value' < range.
671 * The modulus operator.
672 */
673 inline static double normalize(double value, double range) {
674 return value - range * Math::floorDivide(value, range);
675 }
676
677 /**
678 * Normalize an angle so that it's in the range 0 - 2pi.
679 * For positive angles this is just (angle % 2pi), but the Java
680 * mod operator doesn't work that way for negative numbers....
681 */
682 inline static double norm2PI(double angle) {
683 return normalize(angle, CalendarAstronomer::PI * 2.0);
684 }
685
686 /**
687 * Normalize an angle into the range -PI - PI
688 */
689 inline static double normPI(double angle) {
690 return normalize(angle + PI, CalendarAstronomer::PI * 2.0) - PI;
691 }
692
693 /**
694 * Find the "true anomaly" (longitude) of an object from
695 * its mean anomaly and the eccentricity of its orbit. This uses
696 * an iterative solution to Kepler's equation.
697 *
698 * @param meanAnomaly The object's longitude calculated as if it were in
699 * a regular, circular orbit, measured in radians
700 * from the point of perigee.
701 *
702 * @param eccentricity The eccentricity of the orbit
703 *
704 * @return The true anomaly (longitude) measured in radians
705 */
706 double trueAnomaly(double meanAnomaly, double eccentricity);
707
708 /**
709 * Return the obliquity of the ecliptic (the angle between the ecliptic
710 * and the earth's equator) at the current time. This varies due to
711 * the precession of the earth's axis.
712 *
713 * @return the obliquity of the ecliptic relative to the equator,
714 * measured in radians.
715 */
716 double eclipticObliquity();
717
718 //-------------------------------------------------------------------------
719 // Private data
720 //-------------------------------------------------------------------------
721private:
722 /**
723 * Current time in milliseconds since 1/1/1970 AD
724 * @see java.util.Date#getTime
725 */
726 UDate fTime;
727
728 /* These aren't used yet, but they'll be needed for sunset calculations
729 * and equatorial to horizon coordinate conversions
730 */
731 double fLongitude;
732 double fLatitude;
733 double fGmtOffset;
734
735 //
736 // The following fields are used to cache calculated results for improved
737 // performance. These values all depend on the current time setting
738 // of this object, so the clearCache method is provided.
739 //
740
741 double julianDay ;
742 double julianCentury ;
743 double sunLongitude ;
744 double meanAnomalySun ;
745 double moonLongitude ;
746 double moonEclipLong ;
747 double meanAnomalyMoon ;
748 double eclipObliquity ;
749 double siderealT0 ;
750 double siderealTime ;
751
752 void clearCache();
753
754 Equatorial moonPosition;
755 UBool moonPositionSet;
756
757 /**
758 * @internal
759 */
760 UDate local(UDate localMillis);
761};
762
763U_NAMESPACE_END
764
765struct UHashtable;
766
767U_NAMESPACE_BEGIN
768
769/**
770 * Cache of month -> julian day
771 * @internal
772 */
773class U_I18N_API CalendarCache : public UMemory {
774public:
775 static int32_t get(CalendarCache** cache, int32_t key, UErrorCode &status);
776 static void put(CalendarCache** cache, int32_t key, int32_t value, UErrorCode &status);
777 virtual ~CalendarCache();
778private:
779 CalendarCache(int32_t size, UErrorCode& status);
780 static void createCache(CalendarCache** cache, UErrorCode& status);
781 /**
782 * not implemented
783 */
784 CalendarCache();
785 UHashtable *fTable;
786};
787
788U_NAMESPACE_END
789
790#endif
791#endif