package au.gov.ga.earthsci.worldwind.common.sun; import gov.nasa.worldwind.geom.LatLon; import java.util.Calendar; /** * Compute sun position for a given date/time and longitude/latitude. * * This is a simple Java port of the "PSA" solar positioning algorithm, as * documented in: * * Blanco-Muriel et al.: Computing the Solar Vector. Solar Energy Vol 70 No 5 pp * 431-441. http://dx.doi.org/10.1016/S0038-092X(00)00156-0 * * According to the paper, "The algorithm allows .. the true solar vector to be * determined with an accuracy of 0.5 minutes of arc for the period 1999�2015." * * @author Michael de Hoog (michael.dehoog@ga.gov.au) */ public class SunCalculator { public static LatLon subsolarPoint(Calendar time) { // Main variables double elapsedJulianDays; double decimalHours; double eclipticLongitude; double eclipticObliquity; double rightAscension, declination; // Calculate difference in days between the current Julian Day // and JD 2451545.0, which is noon 1 January 2000 Universal Time { // Calculate time of the day in UT decimal hours decimalHours = time.get(Calendar.HOUR_OF_DAY) + (time.get(Calendar.MINUTE) + time.get(Calendar.SECOND) / 60.0) / 60.0; // Calculate current Julian Day long aux1 = (time.get(Calendar.MONTH) - 14) / 12; long aux2 = (1461 * (time.get(Calendar.YEAR) + 4800 + aux1)) / 4 + (367 * (time.get(Calendar.MONTH) - 2 - 12 * aux1)) / 12 - (3 * ((time.get(Calendar.YEAR) + 4900 + aux1) / 100)) / 4 + time.get(Calendar.DAY_OF_MONTH) - 32075; double julianDate = (aux2) - 0.5 + decimalHours / 24.0; // Calculate difference between current Julian Day and JD 2451545.0 elapsedJulianDays = julianDate - 2451545.0; } // Calculate ecliptic coordinates (ecliptic longitude and obliquity of the // ecliptic in radians but without limiting the angle to be less than 2*Pi // (i.e., the result may be greater than 2*Pi) { double omega = 2.1429 - 0.0010394594 * elapsedJulianDays; double meanLongitude = 4.8950630 + 0.017202791698 * elapsedJulianDays; // Radians double meanAnomaly = 6.2400600 + 0.0172019699 * elapsedJulianDays; eclipticLongitude = meanLongitude + 0.03341607 * Math.sin(meanAnomaly) + 0.00034894 * Math.sin(2 * meanAnomaly) - 0.0001134 - 0.0000203 * Math.sin(omega); eclipticObliquity = 0.4090928 - 6.2140e-9 * elapsedJulianDays + 0.0000396 * Math.cos(omega); } // Calculate celestial coordinates ( right ascension and declination ) in radians // but without limiting the angle to be less than 2*Pi (i.e., the result may be // greater than 2*Pi) { double sin_EclipticLongitude = Math.sin(eclipticLongitude); double dY = Math.cos(eclipticObliquity) * sin_EclipticLongitude; double dX = Math.cos(eclipticLongitude); rightAscension = Math.atan2(dY, dX); declination = Math.asin(Math.sin(eclipticObliquity) * sin_EclipticLongitude); } double TWO_PI = Math.PI * 2.0; double greenwichMeanSiderealTime = 6.6974243242 + 0.0657098283 * elapsedJulianDays + decimalHours; double longitude = rightAscension - (Math.toRadians(greenwichMeanSiderealTime * 15.0) % TWO_PI) + Math.PI; // Normalize longitude while (longitude > Math.PI) { longitude -= TWO_PI; } while (longitude <= -Math.PI) { longitude += TWO_PI; } return LatLon.fromRadians(declination, longitude); } }