Fix polar cycles

Finally! It's still rough, inaccurate and slow, but again, better than completely broken.
This commit is contained in:
Minecon724 2024-09-26 19:40:18 +02:00
parent 23b5d85930
commit 6d38604507
Signed by: Minecon724
GPG key ID: 3CCC4D267742C8E8
2 changed files with 44 additions and 24 deletions

View file

@ -5,6 +5,7 @@ import eu.m724.wtapi.object.Twilight;
import eu.m724.wtapi.provider.twilight.CacheableTwilightTimeProvider; import eu.m724.wtapi.provider.twilight.CacheableTwilightTimeProvider;
import java.time.LocalDate; import java.time.LocalDate;
import java.time.LocalDateTime;
import static java.lang.Math.*; import static java.lang.Math.*;
@ -21,10 +22,14 @@ public class ApproximateTwilightTimeProvider extends CacheableTwilightTimeProvid
double equationOfTime = cache.equationOfTime(); double equationOfTime = cache.equationOfTime();
double latRad = toRadians(coordinates.latitude); double latRad = toRadians(coordinates.latitude);
double hourAngle = hourAngle(latRad, declination); double solarNoon = 720 - 4 * coordinates.longitude - equationOfTime;
System.out.println(hourAngle); LocalDateTime solarNoonDateTime = cache.date().atStartOfDay().plusSeconds((long) (solarNoon * 60));
if (Double.isNaN(hourAngle)) { // 90.833 deg = 1.5853349194640094 rad
double n1 = cos(1.5853349194640094) / (cos(latRad) * cos(declination));
n1 -= tan(latRad) * tan(declination);
if (n1 < -1) { // polar day
LocalDate sunriseDate = step(cache.date().minusDays(1), latRad, -1); LocalDate sunriseDate = step(cache.date().minusDays(1), latRad, -1);
LocalDate sunsetDate = step(cache.date().plusDays(1), latRad, 1); LocalDate sunsetDate = step(cache.date().plusDays(1), latRad, 1);
@ -34,46 +39,57 @@ public class ApproximateTwilightTimeProvider extends CacheableTwilightTimeProvid
return new Twilight( return new Twilight(
cache.date(), cache.date(),
backwardTwilight.sunrise(), backwardTwilight.sunrise(),
forwardTwilight.sunset() forwardTwilight.sunset(),
solarNoonDateTime,
true
);
} else if (n1 > 1) { // polar night
LocalDate sunriseDate = step(cache.date().plusDays(1), latRad, 1);
LocalDate sunsetDate = step(cache.date().minusDays(1), latRad, -1);
Twilight backwardTwilight = calculateTwilightTime(sunriseDate, coordinates);
Twilight forwardTwilight = calculateTwilightTime(sunsetDate, coordinates);
return new Twilight(
cache.date(),
backwardTwilight.sunrise(),
forwardTwilight.sunset(),
solarNoonDateTime,
true
); );
} }
double hourAngle = acos(n1);
double longitudeEffect = 4 * toDegrees(hourAngle); double longitudeEffect = 4 * toDegrees(hourAngle);
// sunrise = 720 - 4 * (coordinates.longitude + hourAngleDeg) - equationOfTime // sunrise = 720 - 4 * (coordinates.longitude + hourAngleDeg) - equationOfTime
// sunset = 720 - 4 * (coordinates.longitude - hourAngleDeg) - equationOfTime // sunset = 720 - 4 * (coordinates.longitude - hourAngleDeg) - equationOfTime
double solarNoon = 720 - 4 * coordinates.longitude - equationOfTime;
double sunrise = solarNoon - longitudeEffect; double sunrise = solarNoon - longitudeEffect;
double sunset = solarNoon + longitudeEffect; double sunset = solarNoon + longitudeEffect;
return new Twilight( return new Twilight(
cache.date(), cache.date(),
cache.date().atStartOfDay().plusMinutes((long) sunrise), cache.date().atStartOfDay().plusMinutes((long) sunrise),
cache.date().atStartOfDay().plusMinutes((long) sunset) cache.date().atStartOfDay().plusMinutes((long) sunset),
solarNoonDateTime,
false
); );
} }
private LocalDate step(LocalDate date, double latRad, int direction) { private LocalDate step(LocalDate date, double latRad, int direction) {
double declination = getDeclination(getFractionalYear(date)); double declination = getDeclination(getFractionalYear(date));
System.out.println("Step date: " + date); //System.out.println("Step date: " + date);
double hourAngle = hourAngle(latRad, declination); double n1 = cos(1.5853349194640094) / (cos(latRad) * cos(declination));
if (Double.isNaN(hourAngle)) { n1 -= tan(latRad) * tan(declination);
if (n1 < -1 || n1 > 1) {
return step(date.plusDays(direction), latRad, direction); return step(date.plusDays(direction), latRad, direction);
} }
System.out.println("this the one"); //System.out.println("this the one");
return date; return date;
} }
private double hourAngle(double latRad, double declination) {
// 90.833 deg = 1.5853349194640094 rad
double n1 = cos(1.5853349194640094) / (cos(latRad) * cos(declination));
double n2 = tan(latRad) * tan(declination);
System.out.println(n1 - n2);
return acos(n1 - n2);
}
@Override @Override
public ApproximateTwilightTimeCache initializeCache(LocalDate date) { public ApproximateTwilightTimeCache initializeCache(LocalDate date) {
double fractionalYear = getFractionalYear(date); double fractionalYear = getFractionalYear(date);

View file

@ -23,22 +23,24 @@ public class ApproximateTwilightTimeTest {
TwilightTimeProvider provider = new ApproximateTwilightTimeProvider(); TwilightTimeProvider provider = new ApproximateTwilightTimeProvider();
// used https://gml.noaa.gov/grad/solcalc/index.html for reference values // used https://gml.noaa.gov/grad/solcalc/index.html for reference values
testLocation(provider, 26, 6, 2023, 53.123394, 23.0864867, LocalDateTime.of(2023, 6, 26, 2, 2), LocalDateTime.of(2023, 6, 26, 18, 59)); testLocation(provider, 26, 6, 2023, 53.123394, 23.0864867, LocalDateTime.of(2023, 6, 26, 2, 2), LocalDateTime.of(2023, 6, 26, 18, 59), 0);
testLocation(provider, 13, 11, 2040, 45.432427, -122.3899276, LocalDateTime.of(2040, 11, 13, 15, 7), LocalDateTime.of(2040, 11, 14, 0, 41)); testLocation(provider, 13, 11, 2040, 45.432427, -122.3899276, LocalDateTime.of(2040, 11, 13, 15, 7), LocalDateTime.of(2040, 11, 14, 0, 41), 0);
testLocation(provider, 23, 3, 2021, 55.5024161, 9.6801853, LocalDateTime.of(2021, 3, 23, 5, 15), LocalDateTime.of(2021, 3, 23, 17, 41)); testLocation(provider, 23, 3, 2021, 55.5024161, 9.6801853, LocalDateTime.of(2021, 3, 23, 5, 15), LocalDateTime.of(2021, 3, 23, 17, 41), 0);
testLocation(provider, 6, 8,1990, -72.012117, 2.5240873, LocalDateTime.of(1990, 8, 6, 10, 0), LocalDateTime.of(1990, 8, 6, 13, 52)); testLocation(provider, 6, 8,1990, -72.012117, 2.5240873, LocalDateTime.of(1990, 8, 6, 10, 0), LocalDateTime.of(1990, 8, 6, 13, 52),0);
// TODO this is broken (very inaccurate) so fix // TODO this is broken (very inaccurate) so fix
ACCEPTABLE_DIFFERENCE = 172800; // 2 days ACCEPTABLE_DIFFERENCE = 172800; // 2 days
testLocation(provider, 5, 9,2021, 82.498665, -62.3458366, LocalDateTime.of(2021, 4, 5, 20, 55), LocalDateTime.of(2021, 9, 6, 18, 22)); // the reference values might be incorrect testLocation(provider, 5, 9,2021, 82.498665, -62.3458366, LocalDateTime.of(2021, 4, 5, 20, 55), LocalDateTime.of(2021, 9, 6, 18, 22), 1); // the reference values might be incorrect
testLocation(provider, 3, 2,2021, 82.498665, -62.3458366, LocalDateTime.of(2021, 2, 27, 7, 24), LocalDateTime.of(2020, 10, 13, 8, 46), -1); // the reference values might be incorrect
} }
private void testLocation(TwilightTimeProvider provider, int day, int month, int year, double latitude, double longitude, LocalDateTime actualSunrise, LocalDateTime actualSunset) { private void testLocation(TwilightTimeProvider provider, int day, int month, int year, double latitude, double longitude, LocalDateTime actualSunrise, LocalDateTime actualSunset, int polar) {
LocalDate date = LocalDate.of(year, month, day); LocalDate date = LocalDate.of(year, month, day);
Coordinates coordinates = new Coordinates(latitude, longitude); Coordinates coordinates = new Coordinates(latitude, longitude);
Twilight twilight = provider.calculateTwilightTime(date, coordinates); Twilight twilight = provider.calculateTwilightTime(date, coordinates);
System.out.println(date); System.out.println(date);
System.out.println(coordinates.latitude + " " + coordinates.longitude); System.out.println(coordinates.latitude + " " + coordinates.longitude);
System.out.println("Solar noon: " + twilight.solarNoon());
System.out.println("Calculated sunrise: " + twilight.sunrise()); System.out.println("Calculated sunrise: " + twilight.sunrise());
System.out.println("Actual sunrise: " + actualSunrise); System.out.println("Actual sunrise: " + actualSunrise);
@ -48,6 +50,8 @@ public class ApproximateTwilightTimeTest {
System.out.println("Actual sunset: " + actualSunset); System.out.println("Actual sunset: " + actualSunset);
assert Duration.between(twilight.sunset(), actualSunset).abs().getSeconds() < ACCEPTABLE_DIFFERENCE; assert Duration.between(twilight.sunset(), actualSunset).abs().getSeconds() < ACCEPTABLE_DIFFERENCE;
assert polar == (twilight.isPolarDay() ? 1 : twilight.isPolarNight() ? -1 : 0);
System.out.println(); System.out.println();
} }
} }