Skip to content

Commit 227f6f6

Browse files
committed
illumination of moon
see issue #702
1 parent cd8a417 commit 227f6f6

File tree

4 files changed

+180
-87
lines changed

4 files changed

+180
-87
lines changed

calendar/src/main/java/net/time4j/calendar/astro/MoonPhase.java

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -313,6 +313,57 @@ public Moment atLunation(int n) {
313313

314314
}
315315

316+
/**
317+
* <p>Determines the degree of illumination of the moon at given moment. </p>
318+
*
319+
* <p>The accuracy is limited to percent values (two digits after decimal point). </p>
320+
*
321+
* @param moment universal time
322+
* @return degree of illumination in range {@code 0.00 <= i <= 1.00}
323+
*/
324+
/*[deutsch]
325+
* <p>Ermittelt den Beleuchtungsgrad des Mondes zur angegebenen Zeit. </p>
326+
*
327+
* <p>Die Genauigkeit ist auf Prozentwerte beschr&auml;nkt (zwei Nachkommastellen). </p>
328+
*
329+
* @param moment universal time
330+
* @return degree of illumination in range {@code 0.00 <= i <= 1.00}
331+
*/
332+
public static double getIllumination(Moment moment) {
333+
334+
double jct = JulianDay.ofEphemerisTime(moment).getCentury();
335+
336+
// Meeus (47.2)
337+
double meanElongation =
338+
297.8501921 + (445267.1114034 + (-0.0018819 + (1.0 / 545868 + (1.0 / 113065000) * jct) * jct) * jct) * jct;
339+
340+
// Meeus (47.3)
341+
double meanAnomalySun =
342+
357.5291092 + (35999.0502909 + (-0.0001536 + (1.0 / 24490000) * jct) * jct) * jct;
343+
344+
// Meeus (47.4)
345+
double meanAnomalyMoon =
346+
134.9633964 + (477198.8675055 + (0.0087414 + ((1.0 / 69699) + (1.0 / 14712000) * jct) * jct) * jct) * jct;
347+
348+
double i = // phase angle of moon for a geocentric observer, Meeus (48.4)
349+
180 - meanElongation
350+
- 6.289 * sin(meanAnomalyMoon)
351+
+ 2.1 * sin(meanAnomalySun)
352+
- 1.274 * sin(2 * meanElongation - meanAnomalyMoon)
353+
- 0.658 * sin(2 * meanElongation)
354+
- 0.214 * sin(2 * meanAnomalyMoon)
355+
- 0.11 * sin(meanElongation);
356+
357+
double k = (cos(i) + 1) / 2; // Meeus (48.1)
358+
359+
if (k >= 0.995) {
360+
return 1.0;
361+
} else {
362+
return Math.floor(k * 100) / 100; // rounding
363+
}
364+
365+
}
366+
316367
private int getEstimatedLunations(Moment moment) {
317368

318369
return MathUtils.safeCast(

calendar/src/test/java/net/time4j/calendar/astro/AstroSuite.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
{
1111
AstroTest.class,
1212
JulianDayTest.class,
13+
MoonTest.class,
1314
SunSydneyTest.class,
1415
TwilightTest.class
1516
}

calendar/src/test/java/net/time4j/calendar/astro/AstroTest.java

Lines changed: 0 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -799,91 +799,4 @@ public void latitudeOrLongitudeTwice() {
799799
.build();
800800
}
801801

802-
@Test
803-
public void newMoon() {
804-
assertThat(
805-
MoonPhase.NEW_MOON.atLunation(-283),
806-
is(PlainTimestamp.of(1977, 2, 18, 3, 36, 53).atUTC())); // Meeus (example 49.a)
807-
}
808-
809-
@Test
810-
public void moonPhaseOfLastQuarter() {
811-
assertThat(
812-
MoonPhase.LAST_QUARTER.atLunation(544),
813-
is(PlainTimestamp.of(2044, 1, 21, 23, 47, 7).atUTC())); // Meeus (example 49.b)
814-
}
815-
816-
// for following tests compare with
817-
// http://aa.usno.navy.mil/cgi-bin/aa_phases.pl?year=2017&month=10&day=7&nump=50&format=p
818-
819-
@Test
820-
public void newMoonBefore() {
821-
assertThat(
822-
MoonPhase.NEW_MOON.before(PlainTimestamp.of(2017, 11, 18, 11, 42).atUTC())
823-
.plus(30, TimeUnit.SECONDS)
824-
.with(Moment.PRECISION, TimeUnit.MINUTES),
825-
is(PlainTimestamp.of(2017, 10, 19, 19, 12).atUTC()));
826-
assertThat(
827-
MoonPhase.NEW_MOON.before(PlainTimestamp.of(2017, 11, 18, 11, 43).atUTC())
828-
.plus(30, TimeUnit.SECONDS)
829-
.with(Moment.PRECISION, TimeUnit.MINUTES),
830-
is(PlainTimestamp.of(2017, 11, 18, 11, 42).atUTC()));
831-
}
832-
833-
@Test
834-
public void newMoonAfter() {
835-
assertThat(
836-
MoonPhase.NEW_MOON.after(PlainTimestamp.of(2017, 10, 19, 19, 12).atUTC()) // 19:12:06
837-
.plus(30, TimeUnit.SECONDS)
838-
.with(Moment.PRECISION, TimeUnit.MINUTES),
839-
is(PlainTimestamp.of(2017, 10, 19, 19, 12).atUTC()));
840-
assertThat(
841-
MoonPhase.NEW_MOON.after(PlainTimestamp.of(2017, 10, 19, 19, 13).atUTC())
842-
.plus(30, TimeUnit.SECONDS)
843-
.with(Moment.PRECISION, TimeUnit.MINUTES),
844-
is(PlainTimestamp.of(2017, 11, 18, 11, 42).atUTC()));
845-
}
846-
847-
@Test
848-
public void moonPhaseOfFirstQuarterBefore() {
849-
assertThat(
850-
MoonPhase.FIRST_QUARTER.before(PlainTimestamp.of(2017, 11, 26, 17, 2).atUTC())
851-
.plus(30, TimeUnit.SECONDS)
852-
.with(Moment.PRECISION, TimeUnit.MINUTES),
853-
is(PlainTimestamp.of(2017, 10, 27, 22, 22).atUTC()));
854-
assertThat(
855-
MoonPhase.FIRST_QUARTER.before(PlainTimestamp.of(2017, 11, 26, 17, 3).atUTC()) // 17:02:56
856-
.plus(30, TimeUnit.SECONDS)
857-
.with(Moment.PRECISION, TimeUnit.MINUTES),
858-
is(PlainTimestamp.of(2017, 11, 26, 17, 3).atUTC()));
859-
}
860-
861-
@Test
862-
public void fullMoonBefore() {
863-
assertThat(
864-
MoonPhase.FULL_MOON.before(PlainTimestamp.of(2017, 12, 3, 15, 46).atUTC())
865-
.plus(30, TimeUnit.SECONDS)
866-
.with(Moment.PRECISION, TimeUnit.MINUTES),
867-
is(PlainTimestamp.of(2017, 11, 4, 5, 23).atUTC()));
868-
assertThat(
869-
MoonPhase.FULL_MOON.before(PlainTimestamp.of(2017, 12, 3, 15, 47).atUTC()) // 15:46:56
870-
.plus(30, TimeUnit.SECONDS)
871-
.with(Moment.PRECISION, TimeUnit.MINUTES),
872-
is(PlainTimestamp.of(2017, 12, 3, 15, 47).atUTC()));
873-
}
874-
875-
@Test
876-
public void moonPhaseOfLastQuarterBefore() {
877-
assertThat(
878-
MoonPhase.LAST_QUARTER.before(PlainTimestamp.of(2017, 11, 10, 20, 36).atUTC())
879-
.plus(30, TimeUnit.SECONDS)
880-
.with(Moment.PRECISION, TimeUnit.MINUTES),
881-
is(PlainTimestamp.of(2017, 10, 12, 12, 25).atUTC()));
882-
assertThat(
883-
MoonPhase.LAST_QUARTER.before(PlainTimestamp.of(2017, 11, 10, 20, 37).atUTC())
884-
.plus(30, TimeUnit.SECONDS)
885-
.with(Moment.PRECISION, TimeUnit.MINUTES),
886-
is(PlainTimestamp.of(2017, 11, 10, 20, 37).atUTC()));
887-
}
888-
889802
}
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
package net.time4j.calendar.astro;
2+
3+
import net.time4j.Moment;
4+
import net.time4j.PlainDate;
5+
import net.time4j.PlainTimestamp;
6+
import net.time4j.engine.EpochDays;
7+
import org.junit.Test;
8+
import org.junit.runner.RunWith;
9+
import org.junit.runners.JUnit4;
10+
11+
import java.util.concurrent.TimeUnit;
12+
13+
import static org.hamcrest.CoreMatchers.is;
14+
import static org.junit.Assert.assertThat;
15+
16+
17+
@RunWith(JUnit4.class)
18+
public class MoonTest {
19+
20+
@Test
21+
public void newMoon() {
22+
assertThat(
23+
MoonPhase.NEW_MOON.atLunation(-283),
24+
is(PlainTimestamp.of(1977, 2, 18, 3, 36, 53).atUTC())); // Meeus (example 49.a)
25+
}
26+
27+
@Test
28+
public void moonPhaseOfLastQuarter() {
29+
assertThat(
30+
MoonPhase.LAST_QUARTER.atLunation(544),
31+
is(PlainTimestamp.of(2044, 1, 21, 23, 47, 7).atUTC())); // Meeus (example 49.b)
32+
}
33+
34+
// for following tests compare with
35+
// http://aa.usno.navy.mil/cgi-bin/aa_phases.pl?year=2017&month=10&day=7&nump=50&format=p
36+
37+
@Test
38+
public void newMoonBefore() {
39+
assertThat(
40+
MoonPhase.NEW_MOON.before(PlainTimestamp.of(2017, 11, 18, 11, 42).atUTC())
41+
.plus(30, TimeUnit.SECONDS)
42+
.with(Moment.PRECISION, TimeUnit.MINUTES),
43+
is(PlainTimestamp.of(2017, 10, 19, 19, 12).atUTC()));
44+
assertThat(
45+
MoonPhase.NEW_MOON.before(PlainTimestamp.of(2017, 11, 18, 11, 43).atUTC())
46+
.plus(30, TimeUnit.SECONDS)
47+
.with(Moment.PRECISION, TimeUnit.MINUTES),
48+
is(PlainTimestamp.of(2017, 11, 18, 11, 42).atUTC()));
49+
}
50+
51+
@Test
52+
public void newMoonAfter() {
53+
assertThat(
54+
MoonPhase.NEW_MOON.after(PlainTimestamp.of(2017, 10, 19, 19, 12).atUTC()) // 19:12:06
55+
.plus(30, TimeUnit.SECONDS)
56+
.with(Moment.PRECISION, TimeUnit.MINUTES),
57+
is(PlainTimestamp.of(2017, 10, 19, 19, 12).atUTC()));
58+
assertThat(
59+
MoonPhase.NEW_MOON.after(PlainTimestamp.of(2017, 10, 19, 19, 13).atUTC())
60+
.plus(30, TimeUnit.SECONDS)
61+
.with(Moment.PRECISION, TimeUnit.MINUTES),
62+
is(PlainTimestamp.of(2017, 11, 18, 11, 42).atUTC()));
63+
}
64+
65+
@Test
66+
public void moonPhaseOfFirstQuarterBefore() {
67+
assertThat(
68+
MoonPhase.FIRST_QUARTER.before(PlainTimestamp.of(2017, 11, 26, 17, 2).atUTC())
69+
.plus(30, TimeUnit.SECONDS)
70+
.with(Moment.PRECISION, TimeUnit.MINUTES),
71+
is(PlainTimestamp.of(2017, 10, 27, 22, 22).atUTC()));
72+
assertThat(
73+
MoonPhase.FIRST_QUARTER.before(PlainTimestamp.of(2017, 11, 26, 17, 3).atUTC()) // 17:02:56
74+
.plus(30, TimeUnit.SECONDS)
75+
.with(Moment.PRECISION, TimeUnit.MINUTES),
76+
is(PlainTimestamp.of(2017, 11, 26, 17, 3).atUTC()));
77+
}
78+
79+
@Test
80+
public void fullMoonBefore() {
81+
assertThat(
82+
MoonPhase.FULL_MOON.before(PlainTimestamp.of(2017, 12, 3, 15, 46).atUTC())
83+
.plus(30, TimeUnit.SECONDS)
84+
.with(Moment.PRECISION, TimeUnit.MINUTES),
85+
is(PlainTimestamp.of(2017, 11, 4, 5, 23).atUTC()));
86+
assertThat(
87+
MoonPhase.FULL_MOON.before(PlainTimestamp.of(2017, 12, 3, 15, 47).atUTC()) // 15:46:56
88+
.plus(30, TimeUnit.SECONDS)
89+
.with(Moment.PRECISION, TimeUnit.MINUTES),
90+
is(PlainTimestamp.of(2017, 12, 3, 15, 47).atUTC()));
91+
}
92+
93+
@Test
94+
public void moonPhaseOfLastQuarterBefore() {
95+
assertThat(
96+
MoonPhase.LAST_QUARTER.before(PlainTimestamp.of(2017, 11, 10, 20, 36).atUTC())
97+
.plus(30, TimeUnit.SECONDS)
98+
.with(Moment.PRECISION, TimeUnit.MINUTES),
99+
is(PlainTimestamp.of(2017, 10, 12, 12, 25).atUTC()));
100+
assertThat(
101+
MoonPhase.LAST_QUARTER.before(PlainTimestamp.of(2017, 11, 10, 20, 37).atUTC())
102+
.plus(30, TimeUnit.SECONDS)
103+
.with(Moment.PRECISION, TimeUnit.MINUTES),
104+
is(PlainTimestamp.of(2017, 11, 10, 20, 37).atUTC()));
105+
}
106+
107+
@Test
108+
public void illuminationOfMoon() {
109+
long d = PlainDate.of(1992, 4, 12).get(EpochDays.JULIAN_DAY_NUMBER);
110+
Moment m = JulianDay.ofEphemerisTime(d - 0.5).toMoment();
111+
assertThat(
112+
MoonPhase.getIllumination(m),
113+
is(0.68)); // Meeus (example 48.a)
114+
assertThat(
115+
MoonPhase.getIllumination(MoonPhase.NEW_MOON.after(m)),
116+
is(0.0));
117+
assertThat(
118+
MoonPhase.getIllumination(MoonPhase.FIRST_QUARTER.after(m)),
119+
is(0.5));
120+
assertThat(
121+
MoonPhase.getIllumination(MoonPhase.FULL_MOON.after(m)),
122+
is(1.0));
123+
assertThat(
124+
MoonPhase.getIllumination(MoonPhase.LAST_QUARTER.after(m)),
125+
is(0.5));
126+
}
127+
128+
}

0 commit comments

Comments
 (0)