From 6d38604507edf512924706454c52b0563fc75cb6 Mon Sep 17 00:00:00 2001 From: Minecon724 Date: Thu, 26 Sep 2024 19:40:18 +0200 Subject: [PATCH] Fix polar cycles Finally! It's still rough, inaccurate and slow, but again, better than completely broken. --- .../ApproximateTwilightTimeProvider.java | 52 ++++++++++++------- .../twilight/ApproximateTwilightTimeTest.java | 16 +++--- 2 files changed, 44 insertions(+), 24 deletions(-) diff --git a/src/main/java/eu/m724/wtapi/provider/twilight/impl/approximate/ApproximateTwilightTimeProvider.java b/src/main/java/eu/m724/wtapi/provider/twilight/impl/approximate/ApproximateTwilightTimeProvider.java index dba690c..db1ef2b 100644 --- a/src/main/java/eu/m724/wtapi/provider/twilight/impl/approximate/ApproximateTwilightTimeProvider.java +++ b/src/main/java/eu/m724/wtapi/provider/twilight/impl/approximate/ApproximateTwilightTimeProvider.java @@ -5,6 +5,7 @@ import eu.m724.wtapi.object.Twilight; import eu.m724.wtapi.provider.twilight.CacheableTwilightTimeProvider; import java.time.LocalDate; +import java.time.LocalDateTime; import static java.lang.Math.*; @@ -21,10 +22,14 @@ public class ApproximateTwilightTimeProvider extends CacheableTwilightTimeProvid double equationOfTime = cache.equationOfTime(); double latRad = toRadians(coordinates.latitude); - double hourAngle = hourAngle(latRad, declination); - System.out.println(hourAngle); + double solarNoon = 720 - 4 * coordinates.longitude - equationOfTime; + 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 sunsetDate = step(cache.date().plusDays(1), latRad, 1); @@ -34,46 +39,57 @@ public class ApproximateTwilightTimeProvider extends CacheableTwilightTimeProvid return new Twilight( cache.date(), 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); // sunrise = 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 sunset = solarNoon + longitudeEffect; return new Twilight( cache.date(), 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) { double declination = getDeclination(getFractionalYear(date)); - System.out.println("Step date: " + date); - double hourAngle = hourAngle(latRad, declination); - if (Double.isNaN(hourAngle)) { + //System.out.println("Step date: " + date); + double n1 = cos(1.5853349194640094) / (cos(latRad) * cos(declination)); + n1 -= tan(latRad) * tan(declination); + if (n1 < -1 || n1 > 1) { return step(date.plusDays(direction), latRad, direction); } - System.out.println("this the one"); + //System.out.println("this the one"); 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 public ApproximateTwilightTimeCache initializeCache(LocalDate date) { double fractionalYear = getFractionalYear(date); diff --git a/src/test/java/eu/m724/wtapi/twilight/ApproximateTwilightTimeTest.java b/src/test/java/eu/m724/wtapi/twilight/ApproximateTwilightTimeTest.java index 453de54..7845ec8 100644 --- a/src/test/java/eu/m724/wtapi/twilight/ApproximateTwilightTimeTest.java +++ b/src/test/java/eu/m724/wtapi/twilight/ApproximateTwilightTimeTest.java @@ -23,22 +23,24 @@ public class ApproximateTwilightTimeTest { TwilightTimeProvider provider = new ApproximateTwilightTimeProvider(); // 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, 13, 11, 2040, 45.432427, -122.3899276, LocalDateTime.of(2040, 11, 13, 15, 7), LocalDateTime.of(2040, 11, 14, 0, 41)); - 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, 6, 8,1990, -72.012117, 2.5240873, LocalDateTime.of(1990, 8, 6, 10, 0), LocalDateTime.of(1990, 8, 6, 13, 52)); + 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), 0); + 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),0); // TODO this is broken (very inaccurate) so fix 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); Coordinates coordinates = new Coordinates(latitude, longitude); Twilight twilight = provider.calculateTwilightTime(date, coordinates); System.out.println(date); System.out.println(coordinates.latitude + " " + coordinates.longitude); + System.out.println("Solar noon: " + twilight.solarNoon()); System.out.println("Calculated sunrise: " + twilight.sunrise()); System.out.println("Actual sunrise: " + actualSunrise); @@ -48,6 +50,8 @@ public class ApproximateTwilightTimeTest { System.out.println("Actual sunset: " + actualSunset); assert Duration.between(twilight.sunset(), actualSunset).abs().getSeconds() < ACCEPTABLE_DIFFERENCE; + assert polar == (twilight.isPolarDay() ? 1 : twilight.isPolarNight() ? -1 : 0); + System.out.println(); } }