mirror of
https://github.com/danieldemus/openhab-addons
synced 2026-07-29 12:34:21 +02:00
[astro] Refactor Moon Distance (#19974)
* Review Moon Distance and factorization of MoonCalc Signed-off-by: gael@lhopital.org <gael@lhopital.org>
This commit is contained in:
-5
@@ -49,14 +49,9 @@ public final class AstroBindingConstants {
|
||||
public static final String EVENT_PHASE_FULL = "FULL";
|
||||
public static final String EVENT_PHASE_NEW = "NEW";
|
||||
|
||||
public static final String EVENT_PERIGEE = "PERIGEE";
|
||||
public static final String EVENT_APOGEE = "APOGEE";
|
||||
|
||||
// event channelIds
|
||||
public static final String EVENT_CHANNEL_ID_MOON_PHASE = "phase#event";
|
||||
public static final String EVENT_CHANNEL_ID_ECLIPSE = "eclipse#event";
|
||||
public static final String EVENT_CHANNEL_ID_PERIGEE = "perigee#event";
|
||||
public static final String EVENT_CHANNEL_ID_APOGEE = "apogee#event";
|
||||
|
||||
public static final String EVENT_CHANNEL_ID_RISE = "rise#event";
|
||||
public static final String EVENT_CHANNEL_ID_SET = "set#event";
|
||||
|
||||
+5
-117
@@ -18,14 +18,15 @@ import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.util.Calendar;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.astro.internal.model.DistanceType;
|
||||
import org.openhab.binding.astro.internal.model.Eclipse;
|
||||
import org.openhab.binding.astro.internal.model.EclipseKind;
|
||||
import org.openhab.binding.astro.internal.model.EclipseType;
|
||||
import org.openhab.binding.astro.internal.model.Moon;
|
||||
import org.openhab.binding.astro.internal.model.MoonDistance;
|
||||
import org.openhab.binding.astro.internal.model.MoonPhase;
|
||||
import org.openhab.binding.astro.internal.model.MoonPhaseName;
|
||||
import org.openhab.binding.astro.internal.model.Position;
|
||||
@@ -95,16 +96,8 @@ public class MoonCalc {
|
||||
}
|
||||
});
|
||||
|
||||
double decimalYear = DateTimeUtils.getDecimalYear(calendar);
|
||||
MoonDistance apogee = moon.getApogee();
|
||||
double apogeeJd = getApogee(julianDate, decimalYear);
|
||||
apogee.setDate(DateTimeUtils.toCalendar(apogeeJd, zone, locale));
|
||||
apogee.setDistance(getDistance(apogeeJd));
|
||||
|
||||
MoonDistance perigee = moon.getPerigee();
|
||||
double perigeeJd = getPerigee(julianDate, decimalYear);
|
||||
perigee.setDate(DateTimeUtils.toCalendar(perigeeJd, zone, locale));
|
||||
perigee.setDistance(getDistance(perigeeJd));
|
||||
Set.of(DistanceType.APOGEE, DistanceType.PERIGEE)
|
||||
.forEach(type -> moon.setDistance(type, MoonDistanceCalc.get(type, julianDate)));
|
||||
|
||||
return moon;
|
||||
}
|
||||
@@ -118,9 +111,7 @@ public class MoonCalc {
|
||||
setMoonPhase(calendar, moon, zone, locale);
|
||||
setAzimuthElevationZodiac(julianDate, latitude, longitude, moon);
|
||||
|
||||
MoonDistance distance = moon.getDistance();
|
||||
distance.setDate(calendar);
|
||||
distance.setDistance(getDistance(julianDate));
|
||||
moon.setDistance(DistanceType.CURRENT, MoonDistanceCalc.calculate(julianDate));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -437,88 +428,6 @@ public class MoonCalc {
|
||||
return eclipseJd;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the date, where the moon is furthest away from the earth.
|
||||
*/
|
||||
private double getApogee(double julianDate, double decimalYear) {
|
||||
double k = Math.floor((decimalYear - 1999.97) * 13.2555) + .5;
|
||||
double jd = 0;
|
||||
do {
|
||||
double t = k / 1325.55;
|
||||
double d = 171.9179 + 335.9106046 * k - .010025 * t * t - .00001156 * t * t * t
|
||||
+ .000000055 * t * t * t * t;
|
||||
double m = 347.3477 + 27.1577721 * k - .0008323 * t * t - .000001 * t * t * t;
|
||||
double f = 316.6109 + 364.5287911 * k - .0125131 * t * t - .0000148 * t * t * t;
|
||||
jd = 2451534.6698 + 27.55454988 * k - .0006886 * t * t - .000001098 * t * t * t + .0000000052 * t * t
|
||||
+ .4392 * sinDeg(2 * d) + .0684 * sinDeg(4 * d) + (.0456 - .00011 * t) * sinDeg(m)
|
||||
+ (.0426 - .00011 * t) * sinDeg(2 * d - m) + .0212 * sinDeg(2 * f);
|
||||
jd += -.0189 * sinDeg(d) + .0144 * sinDeg(6 * d) + .0113 * sinDeg(4 * d - m) + .0047 * sinDeg(2 * d + 2 * f)
|
||||
+ .0036 * sinDeg(d + m) + .0035 * sinDeg(8 * d) + .0034 * sinDeg(6 * d - m)
|
||||
- .0034 * sinDeg(2 * d - 2 * f) + .0022 * sinDeg(2 * d - 2 * m) - .0017 * sinDeg(3 * d);
|
||||
jd += .0013 * sinDeg(4 * d + 2 * f) + .0011 * sinDeg(8 * d - m) + .001 * sinDeg(4 * d - 2 * m)
|
||||
+ .0009 * sinDeg(10 * d) + .0007 * sinDeg(3 * d + m) + .0006 * sinDeg(2 * m)
|
||||
+ .0005 * sinDeg(2 * d + m) + .0005 * sinDeg(2 * d + 2 * m) + .0004 * sinDeg(6 * d + 2 * f);
|
||||
jd += .0004 * sinDeg(6 * d - 2 * m) + .0004 * sinDeg(10 * d - m) - .0004 * sinDeg(5 * d)
|
||||
- .0004 * sinDeg(4 * d - 2 * f) + .0003 * sinDeg(2 * f + m) + .0003 * sinDeg(12 * d)
|
||||
+ .0003 * sinDeg(2 * d + 2 * f - m) - .0003 * sinDeg(d - m);
|
||||
k += 1;
|
||||
} while (jd < julianDate);
|
||||
return jd;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the date, where the moon is closest to the earth.
|
||||
*/
|
||||
private double getPerigee(double julianDate, double decimalYear) {
|
||||
double k = Math.floor((decimalYear - 1999.97) * 13.2555);
|
||||
double jd = 0;
|
||||
do {
|
||||
double t = k / 1325.55;
|
||||
double d = 171.9179 + 335.9106046 * k - .010025 * t * t - .00001156 * t * t * t
|
||||
+ .000000055 * t * t * t * t;
|
||||
double m = 347.3477 + 27.1577721 * k - .0008323 * t * t - .000001 * t * t * t;
|
||||
double f = 316.6109 + 364.5287911 * k - .0125131 * t * t - .0000148 * t * t * t;
|
||||
jd = 2451534.6698 + 27.55454988 * k - .0006886 * t * t - .000001098 * t * t * t + .0000000052 * t * t
|
||||
- 1.6769 * sinDeg(2 * d) + .4589 * sinDeg(4 * d) - .1856 * sinDeg(6 * d) + .0883 * sinDeg(8 * d);
|
||||
jd += -(.0773 + .00019 * t) * sinDeg(2 * d - m) + (.0502 - .00013 * t) * sinDeg(m) - .046 * sinDeg(10 * d)
|
||||
+ (.0422 - .00011 * t) * sinDeg(4 * d - m) - .0256 * sinDeg(6 * d - m) + .0253 * sinDeg(12 * d)
|
||||
+ .0237 * sinDeg(d);
|
||||
jd += .0162 * sinDeg(8 * d - m) - .0145 * sinDeg(14 * d) + .0129 * sinDeg(2 * f) - .0112 * sinDeg(3 * d)
|
||||
- .0104 * sinDeg(10 * d - m) + .0086 * sinDeg(16 * d) + .0069 * sinDeg(12 * d - m)
|
||||
+ .0066 * sinDeg(5 * d) - .0053 * sinDeg(2 * d + 2 * f);
|
||||
jd += -.0052 * sinDeg(18 * d) - .0046 * sinDeg(14 * d - m) - .0041 * sinDeg(7 * d)
|
||||
+ .004 * sinDeg(2 * d + m) + .0032 * sinDeg(20 * d) - .0032 * sinDeg(d + m)
|
||||
+ .0031 * sinDeg(16 * d - m);
|
||||
jd += -.0029 * sinDeg(4 * d + m) - .0027 * sinDeg(2 * d - 2 * m) + .0024 * sinDeg(4 * d - 2 * m)
|
||||
- .0021 * sinDeg(6 * d - 2 * m) - .0021 * sinDeg(22 * d) - .0021 * sinDeg(18 * d - m);
|
||||
jd += .0019 * sinDeg(6 * d + m) - .0018 * sinDeg(11 * d) - .0014 * sinDeg(8 * d + m)
|
||||
- .0014 * sinDeg(4 * d - 2 * f) - .0014 * sinDeg(6 * d - 2 * f) + .0014 * sinDeg(3 * d + m)
|
||||
- .0014 * sinDeg(5 * d + m) + .0013 * sinDeg(13 * d);
|
||||
jd += .0013 * sinDeg(20 * d - m) + .0011 * sinDeg(3 * d + 2 * m) - .0011 * sinDeg(4 * d + 2 * f - 2 * m)
|
||||
- .001 * sinDeg(d + 2 * m) - .0009 * sinDeg(22 * d - m) - .0008 * sinDeg(4 * f)
|
||||
+ .0008 * sinDeg(6 * d - 2 * f) + .0008 * sinDeg(2 * d - 2 * f + m);
|
||||
jd += .0007 * sinDeg(2 * m) + .0007 * sinDeg(2 * f - m) + .0007 * sinDeg(2 * d + 4 * f)
|
||||
- .0006 * sinDeg(2 * f - 2 * m) - .0006 * sinDeg(2 * d - 2 * f + 2 * m) + .0006 * sinDeg(24 * d)
|
||||
+ .0005 * sinDeg(4 * d - 4 * f) + .0005 * sinDeg(2 * d + 2 * m) - .0004 * sinDeg(d - m)
|
||||
+ .0027 * sinDeg(9 * d) + .0027 * sinDeg(4 * d + 2 * f);
|
||||
k += 1;
|
||||
} while (jd < julianDate);
|
||||
return jd;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the distance from the moon to earth.
|
||||
*/
|
||||
private double getDistance(double jd) {
|
||||
double t = (jd - 2451545) / 36525;
|
||||
double d = 297.8502042 + 445267.11151686 * t - .00163 * t * t + t * t * t / 545868 - t * t * t * t / 113065000;
|
||||
double m = 357.5291092 + 35999.0502909 * t - .0001536 * t * t + t * t * t / 24490000;
|
||||
double m1 = 134.9634114 + 477198.8676313 * t + .008997 * t * t + t * t * t / 69699 - t * t * t * t / 14712000;
|
||||
double f = 93.27209929999999 + 483202.0175273 * t - .0034029 * t * t - t * t * t / 3526000
|
||||
+ t * t * t * t / 863310000;
|
||||
return 385000.56 + getCoefficient(d, m, m1, f) / 1000;
|
||||
}
|
||||
|
||||
private double[] calcMoon(double t) {
|
||||
double p2 = 6.283185307;
|
||||
double arc = 206264.8062;
|
||||
@@ -647,27 +556,6 @@ public class MoonCalc {
|
||||
return ret;
|
||||
}
|
||||
|
||||
private double getCoefficient(double d, double m, double m1, double f) {
|
||||
int[] kd = new int[] { 0, 2, 2, 0, 0, 0, 2, 2, 2, 2, 0, 1, 0, 2, 0, 0, 4, 0, 4, 2, 2, 1, 1, 2, 2, 4, 2, 0, 2, 2,
|
||||
1, 2, 0, 0, 2, 2, 2, 4, 0, 3, 2, 4, 0, 2, 2, 2, 4, 0, 4, 1, 2, 0, 1, 3, 4, 2, 0, 1, 2, 2 };
|
||||
int[] km = new int[] { 0, 0, 0, 0, 1, 0, 0, -1, 0, -1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, -1, 0, 0, 0, 1, 0,
|
||||
-1, 0, -2, 1, 2, -2, 0, 0, -1, 0, 0, 1, -1, 2, 2, 1, -1, 0, 0, -1, 0, 1, 0, 1, 0, 0, -1, 2, 1, 0, 0 };
|
||||
int[] km1 = new int[] { 1, -1, 0, 2, 0, 0, -2, -1, 1, 0, -1, 0, 1, 0, 1, 1, -1, 3, -2, -1, 0, -1, 0, 1, 2, 0,
|
||||
-3, -2, -1, -2, 1, 0, 2, 0, -1, 1, 0, -1, 2, -1, 1, -2, -1, -1, -2, 0, 1, 4, 0, -2, 0, 2, 1, -2, -3, 2,
|
||||
1, -1, 3, -1 };
|
||||
int[] kf = new int[] { 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, -2, 2, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,
|
||||
0, 0, 0, 0, 0, 0, -2, 2, 0, 2, 0, 0, 0, 0, 0, 0, -2, 0, 0, 0, 0, -2, -2, 0, 0, 0, 0, 0, 0, 0, -2 };
|
||||
int[] kr = new int[] { -20905355, -3699111, -2955968, -569925, 48888, -3149, 246158, -152138, -170733, -204586,
|
||||
-129620, 108743, 104755, 10321, 0, 79661, -34782, -23210, -21636, 24208, 30824, -8379, -16675, -12831,
|
||||
-10445, -11650, 14403, -7003, 0, 10056, 6322, -9884, 5751, 0, -4950, 4130, 0, -3958, 0, 3258, 2616,
|
||||
-1897, -2117, 2354, 0, 0, -1423, -1117, -1571, -1739, 0, -4421, 0, 0, 0, 0, 1165, 0, 0, 8752 };
|
||||
double sr = 0;
|
||||
for (int t = 0; t < 60; t++) {
|
||||
sr += kr[t] * cosDeg(kd[t] * d + km[t] * m + km1[t] * m1 + kf[t] * f);
|
||||
}
|
||||
return sr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the azimuth, elevation and zodiac in the moon object.
|
||||
*/
|
||||
|
||||
+141
@@ -0,0 +1,141 @@
|
||||
/*
|
||||
* Copyright (c) 2010-2026 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.astro.internal.calc;
|
||||
|
||||
import static java.lang.Math.*;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.astro.internal.model.DistanceType;
|
||||
import org.openhab.binding.astro.internal.model.MoonDistance;
|
||||
import org.openhab.binding.astro.internal.util.AstroConstants;
|
||||
import org.openhab.binding.astro.internal.util.DateTimeUtils;
|
||||
|
||||
/**
|
||||
* Moon Distance Calculator
|
||||
*
|
||||
* @author Gaël L'hopital - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class MoonDistanceCalc {
|
||||
private static final double ANOMALISTIC_MONTH = 27.55454988;
|
||||
private static final double JDE_0 = 2451534.6698;
|
||||
private static final int[] KD = new int[] { 0, 2, 2, 0, 0, 0, 2, 2, 2, 2, 0, 1, 0, 2, 0, 0, 4, 0, 4, 2, 2, 1, 1, 2,
|
||||
2, 4, 2, 0, 2, 2, 1, 2, 0, 0, 2, 2, 2, 4, 0, 3, 2, 4, 0, 2, 2, 2, 4, 0, 4, 1, 2, 0, 1, 3, 4, 2, 0, 1, 2,
|
||||
2 };
|
||||
private static final int[] KM = new int[] { 0, 0, 0, 0, 1, 0, 0, -1, 0, -1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1,
|
||||
-1, 0, 0, 0, 1, 0, -1, 0, -2, 1, 2, -2, 0, 0, -1, 0, 0, 1, -1, 2, 2, 1, -1, 0, 0, -1, 0, 1, 0, 1, 0, 0, -1,
|
||||
2, 1, 0, 0 };
|
||||
private static final int[] KM1 = new int[] { 1, -1, 0, 2, 0, 0, -2, -1, 1, 0, -1, 0, 1, 0, 1, 1, -1, 3, -2, -1, 0,
|
||||
-1, 0, 1, 2, 0, -3, -2, -1, -2, 1, 0, 2, 0, -1, 1, 0, -1, 2, -1, 1, -2, -1, -1, -2, 0, 1, 4, 0, -2, 0, 2, 1,
|
||||
-2, -3, 2, 1, -1, 3, -1 };
|
||||
private static final int[] KF = new int[] { 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, -2, 2, -2, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, -2, 2, 0, 2, 0, 0, 0, 0, 0, 0, -2, 0, 0, 0, 0, -2, -2, 0, 0, 0, 0, 0, 0,
|
||||
0, -2 };
|
||||
private static final int[] KR = new int[] { -20905355, -3699111, -2955968, -569925, 48888, -3149, 246158, -152138,
|
||||
-170733, -204586, -129620, 108743, 104755, 10321, 0, 79661, -34782, -23210, -21636, 24208, 30824, -8379,
|
||||
-16675, -12831, -10445, -11650, 14403, -7003, 0, 10056, 6322, -9884, 5751, 0, -4950, 4130, 0, -3958, 0,
|
||||
3258, 2616, -1897, -2117, 2354, 0, 0, -1423, -1117, -1571, -1739, 0, -4421, 0, 0, 0, 0, 1165, 0, 0, 8752 };
|
||||
|
||||
/**
|
||||
* Calculates the distance from the moon to earth in metres
|
||||
*/
|
||||
public static MoonDistance calculate(double jd) {
|
||||
double t = DateTimeUtils.toJulianCenturies(jd);
|
||||
double t2 = t * t;
|
||||
double t3 = t2 * t;
|
||||
double t4 = t3 * t;
|
||||
double d = toRadians(297.8502042 + 445267.11151686 * t - .00163 * t2 + t3 / 545868 - t4 / 113065000);
|
||||
double m = toRadians(AstroConstants.E05_0 + 35999.0502909 * t - .0001536 * t2 + t3 / 24490000);
|
||||
double m1 = toRadians(134.9634114 + 477198.8676313 * t + .008997 * t2 + t3 / 69699 - t4 / 14712000);
|
||||
double f = toRadians(93.2720993 + 483202.0175273 * t - .0034029 * t2 - t3 / 3526000 + t4 / 863310000);
|
||||
return new MoonDistance(jd, 385000560 + getCoefficient(d, m, m1, f));
|
||||
}
|
||||
|
||||
public static MoonDistance get(DistanceType type, double julianDate) {
|
||||
if (DistanceType.CURRENT.equals(type)) {
|
||||
throw new IllegalArgumentException("MoonDistanceCalc.get only supports APOGEE and PERIGEE");
|
||||
}
|
||||
|
||||
double moment = getApogeePerigee(type, julianDate);
|
||||
return calculate(moment);
|
||||
}
|
||||
|
||||
private static double getCoefficient(double d, double m, double m1, double f) {
|
||||
double sr = 0;
|
||||
for (int t = 0; t < 60; t++) {
|
||||
sr += KR[t] * cos(KD[t] * d + KM[t] * m + KM1[t] * m1 + KF[t] * f);
|
||||
}
|
||||
return sr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the Julian date of the specified lunar distance extreme relative to the earth.
|
||||
* Depending on the given {@link DistanceType}, this returns either the apogee (furthest distance)
|
||||
* or the perigee (closest distance) that occurs on or after the given reference date.
|
||||
*
|
||||
* @param type the distance type to calculate (APOGEE or PERIGEE)
|
||||
* @param julianDate the reference Julian date from which to search forward
|
||||
* @return the Julian date of the requested lunar distance extreme
|
||||
*/
|
||||
private static double getApogeePerigee(DistanceType type, double julianDate) {
|
||||
double k = floor((julianDate - JDE_0) / ANOMALISTIC_MONTH) + (type.equals(DistanceType.APOGEE) ? 0.5 : 0) - 1;
|
||||
double jd = 0;
|
||||
do {
|
||||
double t = k / 1325.55;
|
||||
double t2 = t * t;
|
||||
double t3 = t2 * t;
|
||||
double t4 = t3 * t;
|
||||
double d = toRadians(171.9179 + 335.9106046 * k - .010025 * t2 - .00001156 * t3 + .000000055 * t4);
|
||||
double m = toRadians(347.3477 + 27.1577721 * k - .0008323 * t2 - .000001 * t3);
|
||||
double f = toRadians(316.6109 + 364.5287911 * k - .0125131 * t2 - .0000148 * t3);
|
||||
jd = JDE_0 + ANOMALISTIC_MONTH * k - .0006886 * t2 - .000001098 * t3 + .0000000052 * t2;
|
||||
if (DistanceType.APOGEE.equals(type)) {
|
||||
jd += .4392 * sin(2 * d) + .0684 * sin(4 * d) + (.0456 - .00011 * t) * sin(m)
|
||||
+ (.0426 - .00011 * t) * sin(2 * d - m) + .0212 * sin(2 * f);
|
||||
jd += -.0189 * sin(d) + .0144 * sin(6 * d) + .0113 * sin(4 * d - m) + .0047 * sin(2 * d + 2 * f)
|
||||
+ .0036 * sin(d + m) + .0035 * sin(8 * d) + .0034 * sin(6 * d - m) - .0034 * sin(2 * d - 2 * f)
|
||||
+ .0022 * sin(2 * d - 2 * m) - .0017 * sin(3 * d);
|
||||
jd += .0013 * sin(4 * d + 2 * f) + .0011 * sin(8 * d - m) + .001 * sin(4 * d - 2 * m)
|
||||
+ .0009 * sin(10 * d) + .0007 * sin(3 * d + m) + .0006 * sin(2 * m) + .0005 * sin(2 * d + m)
|
||||
+ .0005 * sin(2 * d + 2 * m) + .0004 * sin(6 * d + 2 * f);
|
||||
jd += .0004 * sin(6 * d - 2 * m) + .0004 * sin(10 * d - m) - .0004 * sin(5 * d)
|
||||
- .0004 * sin(4 * d - 2 * f) + .0003 * sin(2 * f + m) + .0003 * sin(12 * d)
|
||||
+ .0003 * sin(2 * d + 2 * f - m) - .0003 * sin(d - m);
|
||||
} else if (DistanceType.PERIGEE.equals(type)) {
|
||||
jd += -1.6769 * sin(2 * d) + .4589 * sin(4 * d) - .1856 * sin(6 * d) + .0883 * sin(8 * d);
|
||||
jd += -(.0773 + .00019 * t) * sin(2 * d - m) + (.0502 - .00013 * t) * sin(m) - .046 * sin(10 * d)
|
||||
+ (.0422 - .00011 * t) * sin(4 * d - m) - .0256 * sin(6 * d - m) + .0253 * sin(12 * d)
|
||||
+ .0237 * sin(d);
|
||||
jd += .0162 * sin(8 * d - m) - .0145 * sin(14 * d) + .0129 * sin(2 * f) - .0112 * sin(3 * d)
|
||||
- .0104 * sin(10 * d - m) + .0086 * sin(16 * d) + .0069 * sin(12 * d - m) + .0066 * sin(5 * d)
|
||||
- .0053 * sin(2 * d + 2 * f);
|
||||
jd += -.0052 * sin(18 * d) - .0046 * sin(14 * d - m) - .0041 * sin(7 * d) + .004 * sin(2 * d + m)
|
||||
+ .0032 * sin(20 * d) - .0032 * sin(d + m) + .0031 * sin(16 * d - m);
|
||||
jd += -.0029 * sin(4 * d + m) - .0027 * sin(2 * d - 2 * m) + .0024 * sin(4 * d - 2 * m)
|
||||
- .0021 * sin(6 * d - 2 * m) - .0021 * sin(22 * d) - .0021 * sin(18 * d - m);
|
||||
jd += .0019 * sin(6 * d + m) - .0018 * sin(11 * d) - .0014 * sin(8 * d + m) - .0014 * sin(4 * d - 2 * f)
|
||||
- .0014 * sin(6 * d - 2 * f) + .0014 * sin(3 * d + m) - .0014 * sin(5 * d + m)
|
||||
+ .0013 * sin(13 * d);
|
||||
jd += .0013 * sin(20 * d - m) + .0011 * sin(3 * d + 2 * m) - .0011 * sin(4 * d + 2 * f - 2 * m)
|
||||
- .001 * sin(d + 2 * m) - .0009 * sin(22 * d - m) - .0008 * sin(4 * f)
|
||||
+ .0008 * sin(6 * d - 2 * f) + .0008 * sin(2 * d - 2 * f + m);
|
||||
jd += .0007 * sin(2 * m) + .0007 * sin(2 * f - m) + .0007 * sin(2 * d + 4 * f)
|
||||
- .0006 * sin(2 * f - 2 * m) - .0006 * sin(2 * d - 2 * f + 2 * m) + .0006 * sin(24 * d)
|
||||
+ .0005 * sin(4 * d - 4 * f) + .0005 * sin(2 * d + 2 * m) - .0004 * sin(d - m)
|
||||
+ .0027 * sin(9 * d) + .0027 * sin(4 * d + 2 * f);
|
||||
}
|
||||
k += 1;
|
||||
} while (jd < julianDate);
|
||||
return jd;
|
||||
}
|
||||
}
|
||||
+8
-8
@@ -15,12 +15,15 @@ package org.openhab.binding.astro.internal.job;
|
||||
import static org.openhab.binding.astro.internal.AstroBindingConstants.*;
|
||||
import static org.openhab.binding.astro.internal.job.Job.scheduleEvent;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.Calendar;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.astro.internal.handler.AstroThingHandler;
|
||||
import org.openhab.binding.astro.internal.model.DistanceType;
|
||||
import org.openhab.binding.astro.internal.model.Eclipse;
|
||||
import org.openhab.binding.astro.internal.model.Moon;
|
||||
import org.openhab.binding.astro.internal.model.MoonPhase;
|
||||
@@ -102,14 +105,11 @@ public final class DailyJobMoon extends AbstractJob {
|
||||
}
|
||||
});
|
||||
|
||||
cal = moon.getPerigee().getDate();
|
||||
if (cal != null) {
|
||||
scheduleEvent(handler, cal, EVENT_PERIGEE, EVENT_CHANNEL_ID_PERIGEE, false, zone, locale);
|
||||
}
|
||||
cal = moon.getApogee().getDate();
|
||||
if (cal != null) {
|
||||
scheduleEvent(handler, cal, EVENT_APOGEE, EVENT_CHANNEL_ID_APOGEE, false, zone, locale);
|
||||
}
|
||||
Set.of(DistanceType.APOGEE, DistanceType.PERIGEE).forEach(type -> {
|
||||
if (moon.getDistanceType(type).getDate() instanceof Instant theMoment) {
|
||||
scheduleEvent(handler, theMoment, type.toString(), type.eventName(), false, zone, locale);
|
||||
}
|
||||
});
|
||||
} catch (Exception e) {
|
||||
LOGGER.warn("The daily moon job execution for \"{}\" failed: {}", handler.getThing().getUID(),
|
||||
e.getMessage());
|
||||
|
||||
+60
-4
@@ -18,6 +18,8 @@ import static org.openhab.binding.astro.internal.util.DateTimeUtils.*;
|
||||
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.time.Instant;
|
||||
import java.time.ZoneId;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.Calendar;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
@@ -76,14 +78,26 @@ public interface Job extends SchedulerRunnable, Runnable {
|
||||
* @param job the {@link Job} instance to schedule
|
||||
* @param eventAt the {@link Instant} instance denoting scheduled instant
|
||||
*/
|
||||
static void schedule(AstroThingHandler astroHandler, Job job, Instant eventAt) {
|
||||
try {
|
||||
static void schedule(AstroThingHandler astroHandler, Job job, Instant eventAt, ZoneId zone) {
|
||||
ZonedDateTime now = ZonedDateTime.now(zone);
|
||||
ZonedDateTime eventZDT = eventAt.atZone(zone);
|
||||
|
||||
if (isSameDay(eventZDT, now) && isTimeGreaterEquals(eventZDT, now)) {
|
||||
astroHandler.schedule(job, eventAt);
|
||||
} catch (Exception ex) {
|
||||
LOGGER.error("{}", ex.getMessage(), ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Schedules the provided {@link Job} instance
|
||||
*
|
||||
* @param astroHandler the {@link AstroThingHandler} instance
|
||||
* @param job the {@link Job} instance to schedule
|
||||
* @param eventAt the {@link Instant} instance denoting scheduled instant
|
||||
*/
|
||||
static void schedule(AstroThingHandler astroHandler, Job job, Instant eventAt) {
|
||||
astroHandler.schedule(job, eventAt);
|
||||
}
|
||||
|
||||
/**
|
||||
* Schedules an {@link EventJob} instance
|
||||
*
|
||||
@@ -97,6 +111,19 @@ public interface Job extends SchedulerRunnable, Runnable {
|
||||
scheduleEvent(astroHandler, eventAt, List.of(event), channelId, configAlreadyApplied, zone, locale);
|
||||
}
|
||||
|
||||
/**
|
||||
* Schedules an {@link EventJob} instance
|
||||
*
|
||||
* @param astroHandler the {@link AstroThingHandler} instance
|
||||
* @param eventAt the {@link Instant} instance denoting scheduled instant
|
||||
* @param event the event ID
|
||||
* @param channelId the channel ID
|
||||
*/
|
||||
static void scheduleEvent(AstroThingHandler astroHandler, Instant eventAt, String event, String channelId,
|
||||
boolean configAlreadyApplied, TimeZone zone, Locale locale) {
|
||||
scheduleEvent(astroHandler, eventAt, List.of(event), channelId, configAlreadyApplied, zone, locale);
|
||||
}
|
||||
|
||||
/**
|
||||
* Schedules an {@link EventJob} instance
|
||||
*
|
||||
@@ -126,6 +153,35 @@ public interface Job extends SchedulerRunnable, Runnable {
|
||||
schedule(astroHandler, new CompositeJob(astroHandler, jobs), instant, zone, locale);
|
||||
}
|
||||
|
||||
/**
|
||||
* Schedules an {@link EventJob} instance
|
||||
*
|
||||
* @param astroHandler the {@link AstroThingHandler} instance
|
||||
* @param eventAt the {@link Instant} instance denoting scheduled instant
|
||||
* @param events the event IDs to schedule
|
||||
* @param channelId the channel ID
|
||||
*/
|
||||
static void scheduleEvent(AstroThingHandler astroHandler, Instant eventAt, List<String> events, String channelId,
|
||||
boolean configAlreadyApplied, TimeZone zone, Locale locale) {
|
||||
if (events.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
final Instant instant;
|
||||
if (!configAlreadyApplied) {
|
||||
final Channel channel = astroHandler.getThing().getChannel(channelId);
|
||||
if (channel == null) {
|
||||
LOGGER.warn("Cannot find channel '{}' for thing '{}'.", channelId, astroHandler.getThing().getUID());
|
||||
return;
|
||||
}
|
||||
AstroChannelConfig config = channel.getConfiguration().as(AstroChannelConfig.class);
|
||||
instant = applyConfig(eventAt, config);
|
||||
} else {
|
||||
instant = eventAt;
|
||||
}
|
||||
List<Job> jobs = events.stream().map(e -> new EventJob(astroHandler, channelId, e)).collect(toList());
|
||||
schedule(astroHandler, new CompositeJob(astroHandler, jobs), instant, zone.toZoneId());
|
||||
}
|
||||
|
||||
/**
|
||||
* Schedules {@link Channel} events
|
||||
*
|
||||
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright (c) 2010-2026 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.astro.internal.model;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* Various types of observed distances
|
||||
*
|
||||
* @author Gaël L'hopital - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public enum DistanceType {
|
||||
APOGEE,
|
||||
PERIGEE,
|
||||
CURRENT;
|
||||
|
||||
public String eventName() {
|
||||
return this.name().toLowerCase(Locale.ROOT) + "#event";
|
||||
}
|
||||
}
|
||||
+20
-25
@@ -12,6 +12,11 @@
|
||||
*/
|
||||
package org.openhab.binding.astro.internal.model;
|
||||
|
||||
import java.util.EnumSet;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
@@ -21,14 +26,17 @@ import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class Moon extends RiseSet implements Planet {
|
||||
private final Map<DistanceType, MoonDistance> distances = new HashMap<>(DistanceType.values().length);
|
||||
|
||||
private MoonPhase phase = new MoonPhase();
|
||||
private MoonDistance apogee = new MoonDistance();
|
||||
private MoonDistance perigee = new MoonDistance();
|
||||
private MoonDistance distance = new MoonDistance();
|
||||
private Eclipse eclipse = new Eclipse(EclipseKind.PARTIAL, EclipseKind.TOTAL);
|
||||
private Position position = new Position();
|
||||
private Zodiac zodiac = Zodiac.NULL;
|
||||
|
||||
public Moon() {
|
||||
EnumSet.allOf(DistanceType.class).forEach(d -> distances.put(d, MoonDistance.NULL));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the moon phase.
|
||||
*/
|
||||
@@ -43,32 +51,26 @@ public class Moon extends RiseSet implements Planet {
|
||||
this.phase = phase;
|
||||
}
|
||||
|
||||
public MoonDistance getDistanceType(DistanceType type) {
|
||||
return Objects.requireNonNull(distances.get(type));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the apogee.
|
||||
*/
|
||||
public MoonDistance getApogee() {
|
||||
return apogee;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the apogee.
|
||||
*/
|
||||
public void setApogee(MoonDistance apogee) {
|
||||
this.apogee = apogee;
|
||||
return getDistanceType(DistanceType.APOGEE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the perigee.
|
||||
*/
|
||||
public MoonDistance getPerigee() {
|
||||
return perigee;
|
||||
return getDistanceType(DistanceType.PERIGEE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the perigee.
|
||||
*/
|
||||
public void setPerigee(MoonDistance perigee) {
|
||||
this.perigee = perigee;
|
||||
public void setDistance(DistanceType type, MoonDistance moonDistance) {
|
||||
distances.put(type, moonDistance);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -89,14 +91,7 @@ public class Moon extends RiseSet implements Planet {
|
||||
* Returns the current distance.
|
||||
*/
|
||||
public MoonDistance getDistance() {
|
||||
return distance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the current distance.
|
||||
*/
|
||||
public void setDistance(MoonDistance distance) {
|
||||
this.distance = distance;
|
||||
return getDistanceType(DistanceType.CURRENT);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+21
-23
@@ -12,55 +12,53 @@
|
||||
*/
|
||||
package org.openhab.binding.astro.internal.model;
|
||||
|
||||
import static org.openhab.core.library.unit.MetricPrefix.KILO;
|
||||
import static org.openhab.core.library.unit.SIUnits.METRE;
|
||||
|
||||
import java.util.Calendar;
|
||||
import java.time.Instant;
|
||||
|
||||
import javax.measure.quantity.Length;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.astro.internal.util.DateTimeUtils;
|
||||
import org.openhab.core.library.types.QuantityType;
|
||||
|
||||
/**
|
||||
* Holds a distance informations.
|
||||
* Holds a distance information.
|
||||
*
|
||||
* @author Gerhard Riegler - Initial contribution
|
||||
* @author Christoph Weitkamp - Introduced UoM
|
||||
* @author Gaël L'hopital - Use Instant, made immutable
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class MoonDistance {
|
||||
public static final MoonDistance NULL = new MoonDistance();
|
||||
|
||||
private @Nullable Calendar date;
|
||||
private double distance;
|
||||
private final @Nullable Instant date;
|
||||
private final double distance;
|
||||
|
||||
private MoonDistance() {
|
||||
this.date = null;
|
||||
this.distance = Double.NaN;
|
||||
}
|
||||
|
||||
public MoonDistance(double distanceJd, double distance) {
|
||||
this.date = DateTimeUtils.jdToInstant(distanceJd);
|
||||
this.distance = distance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the date of the calculated distance.
|
||||
*/
|
||||
@Nullable
|
||||
public Calendar getDate() {
|
||||
public Instant getDate() {
|
||||
return date;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the date of the calculated distance.
|
||||
* Returns the distance in metres.
|
||||
*/
|
||||
public void setDate(@Nullable Calendar date) {
|
||||
this.date = date;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the distance in kilometers.
|
||||
*/
|
||||
public QuantityType<Length> getDistance() {
|
||||
return new QuantityType<>(distance, KILO(METRE));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the distance in kilometers.
|
||||
*/
|
||||
public void setDistance(double kilometer) {
|
||||
this.distance = kilometer;
|
||||
public @Nullable QuantityType<Length> getDistance() {
|
||||
return Double.isNaN(distance) ? null : new QuantityType<>(distance, METRE);
|
||||
}
|
||||
}
|
||||
|
||||
+3
@@ -27,6 +27,9 @@ public class AstroConstants {
|
||||
public static final double TROPICAL_YEAR_SECONDS = TROPICAL_YEAR_DAYS * SECONDS_PER_DAY;
|
||||
public static final double SOLAR_MEAN_MOTION_PER_SECOND = MathUtils.TWO_PI / AstroConstants.TROPICAL_YEAR_SECONDS;
|
||||
|
||||
/** Constant term of the E5 angle. */
|
||||
public static final double E05_0 = 357.52910918;
|
||||
|
||||
/** Constructor */
|
||||
private AstroConstants() {
|
||||
throw new IllegalAccessError("Non-instantiable");
|
||||
|
||||
+18
@@ -13,6 +13,7 @@
|
||||
package org.openhab.binding.astro.internal.util;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.Calendar;
|
||||
import java.util.Locale;
|
||||
@@ -205,6 +206,14 @@ public class DateTimeUtils {
|
||||
&& cal1.get(Calendar.DAY_OF_YEAR) == cal2.get(Calendar.DAY_OF_YEAR);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true, if two ZonedDateTime objects are on the same day ignoring time.
|
||||
*/
|
||||
public static boolean isSameDay(@Nullable ZonedDateTime zdt1, @Nullable ZonedDateTime zdt2) {
|
||||
return zdt1 != null && zdt2 != null
|
||||
&& zdt1.toLocalDate().equals(zdt2.withZoneSameInstant(zdt1.getZone()).toLocalDate());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the next Calendar from today.
|
||||
*/
|
||||
@@ -245,6 +254,15 @@ public class DateTimeUtils {
|
||||
return truncCal1.getTimeInMillis() >= truncCal2.getTimeInMillis();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true, if inst1 is greater or equal than inst2, ignoring seconds.
|
||||
*/
|
||||
public static boolean isTimeGreaterEquals(ZonedDateTime inst1, ZonedDateTime inst2) {
|
||||
ZonedDateTime truncInst1 = inst1.truncatedTo(ChronoUnit.MINUTES);
|
||||
ZonedDateTime truncInst2 = inst2.truncatedTo(ChronoUnit.MINUTES);
|
||||
return !truncInst1.isBefore(truncInst2);
|
||||
}
|
||||
|
||||
public static Calendar getAdjustedEarliest(Calendar cal, AstroChannelConfig config) {
|
||||
int minutes = getMinutesFromTime(config.earliest);
|
||||
// MainUI sets earliest to 00:00 if unconfigured, which is why zero must be treated as such
|
||||
|
||||
@@ -113,6 +113,7 @@
|
||||
<item-type>DateTime</item-type>
|
||||
<label>Start Time</label>
|
||||
<description>The start time of the event</description>
|
||||
<category>calendar</category>
|
||||
<tags>
|
||||
<tag>Calculation</tag>
|
||||
<tag>Timestamp</tag>
|
||||
@@ -125,6 +126,7 @@
|
||||
<item-type>DateTime</item-type>
|
||||
<label>End Time</label>
|
||||
<description>The end time of the event</description>
|
||||
<category>calendar</category>
|
||||
<tags>
|
||||
<tag>Calculation</tag>
|
||||
<tag>Timestamp</tag>
|
||||
@@ -312,6 +314,7 @@
|
||||
<item-type>DateTime</item-type>
|
||||
<label>Total Eclipse</label>
|
||||
<description>The DateTime of the next total eclipse</description>
|
||||
<category>calendar</category>
|
||||
<tags>
|
||||
<tag>Calculation</tag>
|
||||
<tag>Timestamp</tag>
|
||||
@@ -323,6 +326,7 @@
|
||||
<item-type>DateTime</item-type>
|
||||
<label>Partial Eclipse</label>
|
||||
<description>The DateTime of the next partial eclipse</description>
|
||||
<category>calendar</category>
|
||||
<tags>
|
||||
<tag>Calculation</tag>
|
||||
<tag>Timestamp</tag>
|
||||
@@ -334,6 +338,7 @@
|
||||
<item-type>DateTime</item-type>
|
||||
<label>Ring Eclipse</label>
|
||||
<description>The DateTime of the next ring eclipse</description>
|
||||
<category>calendar</category>
|
||||
<tags>
|
||||
<tag>Calculation</tag>
|
||||
<tag>Timestamp</tag>
|
||||
@@ -411,6 +416,7 @@
|
||||
<item-type>DateTime</item-type>
|
||||
<label>First Quarter</label>
|
||||
<description>The DateTime the moon is in the first quarter</description>
|
||||
<category>calendar</category>
|
||||
<tags>
|
||||
<tag>Calculation</tag>
|
||||
<tag>Timestamp</tag>
|
||||
@@ -422,6 +428,7 @@
|
||||
<item-type>DateTime</item-type>
|
||||
<label>Third Quarter</label>
|
||||
<description>The DateTime the moon is in the third quarter</description>
|
||||
<category>calendar</category>
|
||||
<tags>
|
||||
<tag>Calculation</tag>
|
||||
<tag>Timestamp</tag>
|
||||
@@ -433,6 +440,7 @@
|
||||
<item-type>DateTime</item-type>
|
||||
<label>Full Moon</label>
|
||||
<description>The DateTime for full moon</description>
|
||||
<category>calendar</category>
|
||||
<tags>
|
||||
<tag>Calculation</tag>
|
||||
<tag>Timestamp</tag>
|
||||
@@ -444,6 +452,7 @@
|
||||
<item-type>DateTime</item-type>
|
||||
<label>New Moon</label>
|
||||
<description>The DateTime for new moon</description>
|
||||
<category>calendar</category>
|
||||
<tags>
|
||||
<tag>Calculation</tag>
|
||||
<tag>Timestamp</tag>
|
||||
@@ -570,6 +579,7 @@
|
||||
<item-type>DateTime</item-type>
|
||||
<label>Date</label>
|
||||
<description>The DateTime when the distance is reached</description>
|
||||
<category>calendar</category>
|
||||
<tags>
|
||||
<tag>Calculation</tag>
|
||||
<tag>Timestamp</tag>
|
||||
|
||||
+3
-42
@@ -48,7 +48,6 @@ public class MoonCalcTest {
|
||||
private static final double AMSTERDAM_LONGITUDE = 4.8978293;
|
||||
|
||||
private static final int ACCURACY_IN_MILLIS = 5 * 60 * 1000;
|
||||
private static final int ACCURACY_IN_KILOMETRES = 4;
|
||||
private static final double ACCURACY_IN_DEGREE = 0.3;
|
||||
|
||||
private @Nullable MoonCalc moonCalc;
|
||||
@@ -79,33 +78,6 @@ public class MoonCalcTest {
|
||||
assertNull(moon.getPhase().getName());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetMoonInfoForApogeeAccuracy() {
|
||||
Moon moon = Objects.requireNonNull(moonCalc).getMoonInfo(FEB_27_2019, AMSTERDAM_LATITUDE, AMSTERDAM_LONGITUDE,
|
||||
TIME_ZONE, Locale.ROOT);
|
||||
|
||||
// expected result from haevens-above.com is 406,391 km @ 04 March 2019 12:27
|
||||
assertEquals(406391, moon.getApogee().getDistance().doubleValue(), ACCURACY_IN_KILOMETRES);
|
||||
Calendar apogeeDate = moon.getApogee().getDate();
|
||||
assertNotNull(apogeeDate);
|
||||
assertEquals(MoonCalcTest.newCalendar(2019, Calendar.MARCH, 4, 12, 27, TIME_ZONE).getTimeInMillis(),
|
||||
apogeeDate.getTimeInMillis(), ACCURACY_IN_MILLIS);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetMoonInfoForPerigeeAccuracy() {
|
||||
Moon moon = Objects.requireNonNull(moonCalc).getMoonInfo(FEB_27_2019, AMSTERDAM_LATITUDE, AMSTERDAM_LONGITUDE,
|
||||
TIME_ZONE, Locale.ROOT);
|
||||
|
||||
// expected result from haevens-above.com is 359,377 km @ 19 February 2019 20:44
|
||||
assertEquals(359377, moon.getPerigee().getDistance().doubleValue(), ACCURACY_IN_KILOMETRES);
|
||||
|
||||
Calendar perigeeDate = moon.getPerigee().getDate();
|
||||
assertNotNull(perigeeDate);
|
||||
assertEquals(MoonCalcTest.newCalendar(2019, Calendar.MARCH, 19, 20, 48, TIME_ZONE).getTimeInMillis(),
|
||||
perigeeDate.getTimeInMillis(), ACCURACY_IN_MILLIS);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetMoonInfoForRiseAccuracy() {
|
||||
Moon moon = Objects.requireNonNull(moonCalc).getMoonInfo(FEB_27_2019, AMSTERDAM_LATITUDE, AMSTERDAM_LONGITUDE,
|
||||
@@ -113,7 +85,7 @@ public class MoonCalcTest {
|
||||
|
||||
Calendar riseStart = moon.getRise().getStart();
|
||||
assertNotNull(riseStart);
|
||||
// expected result from haevens-above.com is 03:00
|
||||
// expected result from heavens-above.com is 03:00
|
||||
assertEquals(MoonCalcTest.newCalendar(2019, Calendar.FEBRUARY, 27, 3, 0, TIME_ZONE).getTimeInMillis(),
|
||||
riseStart.getTimeInMillis(), ACCURACY_IN_MILLIS);
|
||||
}
|
||||
@@ -125,7 +97,7 @@ public class MoonCalcTest {
|
||||
|
||||
Calendar setStart = moon.getSet().getStart();
|
||||
assertNotNull(setStart);
|
||||
// expected result from haevens-above.com is 11:35
|
||||
// expected result from heavens-above.com is 11:35
|
||||
assertEquals(MoonCalcTest.newCalendar(2019, Calendar.FEBRUARY, 27, 11, 35, TIME_ZONE).getTimeInMillis(),
|
||||
setStart.getTimeInMillis(), ACCURACY_IN_MILLIS);
|
||||
}
|
||||
@@ -137,22 +109,11 @@ public class MoonCalcTest {
|
||||
Moon moon = moonCalc.getMoonInfo(FEB_27_2019, AMSTERDAM_LATITUDE, AMSTERDAM_LONGITUDE, TIME_ZONE, Locale.ROOT);
|
||||
moonCalc.setPositionalInfo(FEB_27_2019, AMSTERDAM_LATITUDE, AMSTERDAM_LONGITUDE, moon, TIME_ZONE, Locale.ROOT);
|
||||
|
||||
// expected result from haevens-above.com is Azimuth: 100.5, altitude -17
|
||||
// expected result from heavens-above.com is Azimuth: 100.5, altitude -17
|
||||
assertEquals(100.5, moon.getPosition().getAzimuth().doubleValue(), ACCURACY_IN_DEGREE);
|
||||
assertEquals(-17, moon.getPosition().getElevation().doubleValue(), ACCURACY_IN_DEGREE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetMoonInfoForMoonDistanceAccuracy() {
|
||||
MoonCalc moonCalc = this.moonCalc;
|
||||
assertNotNull(moonCalc);
|
||||
Moon moon = moonCalc.getMoonInfo(FEB_27_2019, AMSTERDAM_LATITUDE, AMSTERDAM_LONGITUDE, TIME_ZONE, Locale.ROOT);
|
||||
moonCalc.setPositionalInfo(FEB_27_2019, AMSTERDAM_LATITUDE, AMSTERDAM_LONGITUDE, moon, TIME_ZONE, Locale.ROOT);
|
||||
|
||||
// expected result from haevens-above.com is 392612 km
|
||||
assertEquals(392612, moon.getDistance().getDistance().doubleValue(), ACCURACY_IN_KILOMETRES);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetMoonInfoForMoonPhaseAccuracy() {
|
||||
MoonCalc moonCalc = this.moonCalc;
|
||||
|
||||
+130
@@ -0,0 +1,130 @@
|
||||
/*
|
||||
* Copyright (c) 2010-2026 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.astro.internal.calc;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import static org.openhab.core.library.unit.MetricPrefix.KILO;
|
||||
import static org.openhab.core.library.unit.SIUnits.METRE;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.Calendar;
|
||||
import java.util.GregorianCalendar;
|
||||
import java.util.Locale;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.openhab.binding.astro.internal.model.DistanceType;
|
||||
import org.openhab.binding.astro.internal.model.MoonDistance;
|
||||
import org.openhab.binding.astro.internal.util.DateTimeUtils;
|
||||
|
||||
/***
|
||||
* Specific unit tests to check if {@link MoonCalc} generates correct data for
|
||||
* Amsterdam city on 27 February 2019. In particular the following cases are
|
||||
* covered:
|
||||
* <ul>
|
||||
* <li>checks if generated data are the same (with some accuracy) as produced by
|
||||
* heavens-above.com</li>
|
||||
* </ul>
|
||||
*
|
||||
* @author Leo Siepel - Initial contribution
|
||||
* @see <a href="https://www.heavens-above.com/Moon.aspx">Heavens Above Moon</a>
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class MoonDistanceCalcTest {
|
||||
|
||||
private static final TimeZone TIME_ZONE = TimeZone.getTimeZone("Europe/Amsterdam");
|
||||
private static final Calendar FEB_27_2019 = newCalendar(2019, Calendar.FEBRUARY, 27, 1, 0, TIME_ZONE);
|
||||
|
||||
private static final int ACCURACY_IN_MILLIS = 5 * 60 * 1000;
|
||||
private static final int ACCURACY_IN_KILOMETRES = 4;
|
||||
|
||||
@Test
|
||||
public void testGetMoonInfoForApogeeAccuracy() {
|
||||
double jdate = DateTimeUtils.dateToJulianDate(FEB_27_2019);
|
||||
MoonDistance distance = MoonDistanceCalc.get(DistanceType.APOGEE, jdate);
|
||||
|
||||
// expected result from heavens-above.com is 406,391 km @ 04 March 2019 12:27
|
||||
var apogeeDistance = distance.getDistance();
|
||||
assertNotNull(apogeeDistance);
|
||||
var kmDistance = apogeeDistance.toUnit(KILO(METRE));
|
||||
assertNotNull(kmDistance);
|
||||
assertEquals(406391, kmDistance.doubleValue(), ACCURACY_IN_KILOMETRES);
|
||||
Instant apogeeDate = distance.getDate();
|
||||
assertNotNull(apogeeDate);
|
||||
assertEquals(newCalendar(2019, Calendar.MARCH, 4, 12, 27, TIME_ZONE).getTimeInMillis(),
|
||||
apogeeDate.toEpochMilli(), ACCURACY_IN_MILLIS);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetMoonInfoForPerigeeAccuracy() {
|
||||
double jdate = DateTimeUtils.dateToJulianDate(FEB_27_2019);
|
||||
MoonDistance distance = MoonDistanceCalc.get(DistanceType.PERIGEE, jdate);
|
||||
|
||||
// expected result from heavens-above.com is 359,377 km @ 19 February 2019 20:44
|
||||
var perigeeDistance = distance.getDistance();
|
||||
assertNotNull(perigeeDistance);
|
||||
var kmDistance = perigeeDistance.toUnit(KILO(METRE));
|
||||
assertNotNull(kmDistance);
|
||||
assertEquals(359377, kmDistance.doubleValue(), ACCURACY_IN_KILOMETRES);
|
||||
|
||||
Instant perigeeDate = distance.getDate();
|
||||
assertNotNull(perigeeDate);
|
||||
assertEquals(newCalendar(2019, Calendar.MARCH, 19, 20, 48, TIME_ZONE).getTimeInMillis(),
|
||||
perigeeDate.toEpochMilli(), ACCURACY_IN_MILLIS);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetMoonInfoForMoonDistanceAccuracy() {
|
||||
double jdate = DateTimeUtils.dateToJulianDate(FEB_27_2019);
|
||||
MoonDistance distance = MoonDistanceCalc.calculate(jdate);
|
||||
|
||||
// expected result from heavens-above.com is 392612 km
|
||||
var currentDistance = distance.getDistance();
|
||||
assertNotNull(currentDistance);
|
||||
var kmDistance = currentDistance.toUnit(KILO(METRE));
|
||||
assertNotNull(kmDistance);
|
||||
assertEquals(392612, kmDistance.doubleValue(), ACCURACY_IN_KILOMETRES);
|
||||
}
|
||||
|
||||
/***
|
||||
* Constructs a <code>GregorianCalendar</code> with the given date and time set
|
||||
* for the provided time zone.
|
||||
*
|
||||
* @param year
|
||||
* the value used to set the <code>YEAR</code> calendar field in the
|
||||
* calendar.
|
||||
* @param month
|
||||
* the value used to set the <code>MONTH</code> calendar field in the
|
||||
* calendar. Month value is 0-based. e.g., 0 for January.
|
||||
* @param dayOfMonth
|
||||
* the value used to set the <code>DAY_OF_MONTH</code> calendar field
|
||||
* in the calendar.
|
||||
* @param hourOfDay
|
||||
* the value used to set the <code>HOUR_OF_DAY</code> calendar field
|
||||
* in the calendar.
|
||||
* @param minute
|
||||
* the value used to set the <code>MINUTE</code> calendar field in
|
||||
* the calendar.
|
||||
* @param zone
|
||||
* the given time zone.
|
||||
* @return a {@link Calendar} set to the given date and time in the specified
|
||||
* time zone, truncated to minute precision.
|
||||
*/
|
||||
private static Calendar newCalendar(int year, int month, int dayOfMonth, int hourOfDay, int minute, TimeZone zone) {
|
||||
Calendar result = new GregorianCalendar(zone, Locale.ROOT);
|
||||
result.set(year, month, dayOfMonth, hourOfDay, minute);
|
||||
|
||||
return DateTimeUtils.truncateToMinute(result);
|
||||
}
|
||||
}
|
||||
+10
-10
@@ -36,7 +36,7 @@ import org.openhab.binding.astro.internal.util.DateTimeUtils;
|
||||
* covered:
|
||||
* <ul>
|
||||
* <li>checks if generated data are the same (with some accuracy) as produced by
|
||||
* haevens-above.com</li>
|
||||
* heavens-above.com</li>
|
||||
* <li>checks if the generated {@link Sun#getAllRanges()} are consistent with
|
||||
* each other</li>
|
||||
* </ul>
|
||||
@@ -102,7 +102,7 @@ public class SunCalcTest {
|
||||
assertNotNull(range);
|
||||
Calendar cal = range.getStart();
|
||||
assertNotNull(cal);
|
||||
// expected result from haevens-above.com is 27 Feb 2019 05:39 till 06:18
|
||||
// expected result from heavens-above.com is 27 Feb 2019 05:39 till 06:18
|
||||
assertEquals(SunCalcTest.newCalendar(2019, Calendar.FEBRUARY, 27, 5, 39, AMSTERDAM_TIME_ZONE).getTimeInMillis(),
|
||||
cal.getTimeInMillis(), ACCURACY_IN_MILLIS);
|
||||
cal = range.getEnd();
|
||||
@@ -120,7 +120,7 @@ public class SunCalcTest {
|
||||
assertNotNull(range);
|
||||
Calendar cal = range.getStart();
|
||||
assertNotNull(cal);
|
||||
// expected result from haevens-above.com is 27 Feb 2019 06:18 till 06:58
|
||||
// expected result from heavens-above.com is 27 Feb 2019 06:18 till 06:58
|
||||
assertEquals(SunCalcTest.newCalendar(2019, Calendar.FEBRUARY, 27, 6, 18, AMSTERDAM_TIME_ZONE).getTimeInMillis(),
|
||||
cal.getTimeInMillis(), ACCURACY_IN_MILLIS);
|
||||
cal = range.getEnd();
|
||||
@@ -138,7 +138,7 @@ public class SunCalcTest {
|
||||
assertNotNull(range);
|
||||
Calendar cal = range.getStart();
|
||||
assertNotNull(cal);
|
||||
// expected result from haevens-above.com is 27 Feb 2019 06:58 till 07:32
|
||||
// expected result from heavens-above.com is 27 Feb 2019 06:58 till 07:32
|
||||
assertEquals(SunCalcTest.newCalendar(2019, Calendar.FEBRUARY, 27, 6, 58, AMSTERDAM_TIME_ZONE).getTimeInMillis(),
|
||||
cal.getTimeInMillis(), ACCURACY_IN_MILLIS);
|
||||
cal = range.getEnd();
|
||||
@@ -156,7 +156,7 @@ public class SunCalcTest {
|
||||
assertNotNull(range);
|
||||
Calendar cal = range.getStart();
|
||||
assertNotNull(cal);
|
||||
// expected result from haevens-above.com is 27 Feb 2019 07:32
|
||||
// expected result from heavens-above.com is 27 Feb 2019 07:32
|
||||
assertEquals(SunCalcTest.newCalendar(2019, Calendar.FEBRUARY, 27, 7, 32, AMSTERDAM_TIME_ZONE).getTimeInMillis(),
|
||||
cal.getTimeInMillis(), ACCURACY_IN_MILLIS);
|
||||
}
|
||||
@@ -170,7 +170,7 @@ public class SunCalcTest {
|
||||
assertNotNull(range);
|
||||
Calendar cal = range.getStart();
|
||||
assertNotNull(cal);
|
||||
// expected result from haevens-above.com is 27 Feb 2019 12:54
|
||||
// expected result from heavens-above.com is 27 Feb 2019 12:54
|
||||
assertEquals(
|
||||
SunCalcTest.newCalendar(2019, Calendar.FEBRUARY, 27, 12, 54, AMSTERDAM_TIME_ZONE).getTimeInMillis(),
|
||||
cal.getTimeInMillis(), ACCURACY_IN_MILLIS);
|
||||
@@ -185,7 +185,7 @@ public class SunCalcTest {
|
||||
assertNotNull(range);
|
||||
Calendar cal = range.getStart();
|
||||
assertNotNull(cal);
|
||||
// expected result from haevens-above.com is 27 Feb 2019 18:15
|
||||
// expected result from heavens-above.com is 27 Feb 2019 18:15
|
||||
assertEquals(
|
||||
SunCalcTest.newCalendar(2019, Calendar.FEBRUARY, 27, 18, 15, AMSTERDAM_TIME_ZONE).getTimeInMillis(),
|
||||
cal.getTimeInMillis(), ACCURACY_IN_MILLIS);
|
||||
@@ -200,7 +200,7 @@ public class SunCalcTest {
|
||||
assertNotNull(range);
|
||||
Calendar cal = range.getStart();
|
||||
assertNotNull(cal);
|
||||
// expected result from haevens-above.com is 27 Feb 2019 18:15 till 18:50
|
||||
// expected result from heavens-above.com is 27 Feb 2019 18:15 till 18:50
|
||||
assertEquals(
|
||||
SunCalcTest.newCalendar(2019, Calendar.FEBRUARY, 27, 18, 15, AMSTERDAM_TIME_ZONE).getTimeInMillis(),
|
||||
cal.getTimeInMillis(), ACCURACY_IN_MILLIS);
|
||||
@@ -220,7 +220,7 @@ public class SunCalcTest {
|
||||
assertNotNull(range);
|
||||
Calendar cal = range.getStart();
|
||||
assertNotNull(cal);
|
||||
// expected result from haevens-above.com is 27 Feb 2019 18:50 till 19:29
|
||||
// expected result from heavens-above.com is 27 Feb 2019 18:50 till 19:29
|
||||
assertEquals(
|
||||
SunCalcTest.newCalendar(2019, Calendar.FEBRUARY, 27, 18, 50, AMSTERDAM_TIME_ZONE).getTimeInMillis(),
|
||||
cal.getTimeInMillis(), ACCURACY_IN_MILLIS);
|
||||
@@ -240,7 +240,7 @@ public class SunCalcTest {
|
||||
assertNotNull(range);
|
||||
Calendar cal = range.getStart();
|
||||
assertNotNull(cal);
|
||||
// expected result from haevens-above.com is 27 Feb 2019 19:29 till 20:09
|
||||
// expected result from heavens-above.com is 27 Feb 2019 19:29 till 20:09
|
||||
assertEquals(
|
||||
SunCalcTest.newCalendar(2019, Calendar.FEBRUARY, 27, 19, 29, AMSTERDAM_TIME_ZONE).getTimeInMillis(),
|
||||
cal.getTimeInMillis(), ACCURACY_IN_MILLIS);
|
||||
|
||||
+1
-1
@@ -34,7 +34,7 @@ import org.openhab.binding.astro.internal.util.DateTimeUtils;
|
||||
* covered:
|
||||
* <ul>
|
||||
* <li>checks if generated data are the same (with some accuracy) as produced by
|
||||
* haevens-above.com</li>
|
||||
* heavens-above.com</li>
|
||||
* </ul>
|
||||
*
|
||||
* @author Leo Siepel - Initial contribution
|
||||
|
||||
Reference in New Issue
Block a user