
org.h2gis.functions.spatial.earth.SunCalc Maven / Gradle / Ivy
The newest version!
/**
* H2GIS is a library that brings spatial support to the H2 Database Engine
* . H2GIS is developed by CNRS
* .
*
* This code is part of the H2GIS project. H2GIS is free software;
* you can redistribute it and/or modify it under the terms of the GNU
* Lesser General Public License as published by the Free Software Foundation;
* version 3.0 of the License.
*
* H2GIS is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details .
*
*
* For more information, please consult:
* or contact directly: info_at_h2gis.org
*/
package org.h2gis.functions.spatial.earth;
import com.vividsolutions.jts.geom.Coordinate;
import java.util.Date;
/**
* This class is a partial Java port of SunCalc. A BSD-licensed JavaScript library for
* calculating sun position, sunlight phases (times for sunrise, sunset, dusk,
* etc.), moon position and lunar phase for the given location and time, created
* by Vladimir Agafonkin (@mourner) as a part of the SunCalc.net project.
*
* @author Erwan Bocher
*/
public class SunCalc {
/* Constants */
private final static double rad = Math.PI / 180;
private final static double dayMs = 1000 * 60 * 60 * 24;
private final static double J1970 = 2440588;
private final static double J2000 = 2451545;
private final static double M0 = rad * 357.5291;
private final static double M1 = rad * 0.98560028;
private final static double J0 = 0.0009;
private final static double J1 = 0.0053;
private final static double J2 = -0.0069;
private final static double C1 = rad * 1.9148;
private final static double C2 = rad * 0.0200;
private final static double C3 = rad * 0.0003;
private final static double P = rad * 102.9372;// perihelion of the Earth
// obliquity of the Earth
//The mean obliquity of the ecliptic is calculated by a formula of Laskar (1986),
//given in Jean Meeus: "Astronomical Algorithms", p. 135.
private final static double e = rad * 23.4397;
private final static double th0 = rad * 280.16;
private final static double th1 = rad * 360.9856235;
private SunCalc() {
}
private static double dateToJulianDate(Date date) {
return date.getTime() / dayMs - 0.5 + J1970;
}
private static Date julianDateToDate(double j) {
return new Date(Math.round((j + 0.5 - J1970) * dayMs));
}
// general sun calculations
private static long getJulianCycle(double J, double lw) {
return Math.round(J - J2000 - J0 - lw / (2 * Math.PI));
}
private static double getSolarMeanAnomaly(double Js) {
return M0 + M1 * (Js - J2000);
}
private static double getEquationOfCenter(double M) {
return C1 * Math.sin(M) + C2 * Math.sin(2 * M) + C3 * Math.sin(3 * M);
}
private static double getEclipticLongitude(double M, double C) {
return M + P + C + Math.PI;
}
private static double getSunDeclination(double Ls) {
return Math.asin(Math.sin(Ls) * Math.sin(e));
}
// calculations for sun times
private static double getApproxTransit(double Ht, double lw, double n) {
return J2000 + J0 + (Ht + lw) / (2 * Math.PI) + n;
}
private static double getSolarTransit(double Js, double M, double Ls) {
return Js + (J1 * Math.sin(M)) + (J2 * Math.sin(2 * Ls));
}
private static double getHourAngle(double h, double phi, double d) {
return Math.acos((Math.sin(h) - Math.sin(phi) * Math.sin(d))
/ (Math.cos(phi) * Math.cos(d)));
}
// calculations for sun position
private static double getRightAscension(double Ls) {
return Math.atan2(Math.sin(Ls) * Math.cos(e), Math.cos(Ls));
}
private static double getSiderealTime(double J, double lw) {
return th0 + th1 * (J - J2000) - lw;
}
/**
* Sun azimuth in radians (direction along the horizon, measured from north to east)
* e.g. 0 is north
* @param H
* @param phi
* @param d
* @return
*/
private static double getAzimuth(double H, double phi, double d) {
return Math.atan2(Math.sin(H),
Math.cos(H) * Math.sin(phi) - Math.tan(d) * Math.cos(phi))+Math.PI;
}
/**
* Sun altitude above the horizon in radians.
* e.g. 0 at the horizon and PI/2 at the zenith
* @param H
* @param phi
* @param d
* @return
*/
private static double getAltitude(double H, double phi, double d) {
return Math.asin(Math.sin(phi) * Math.sin(d) + Math.cos(phi)
* Math.cos(d) * Math.cos(H));
}
/**
* Returns the sun position as a coordinate with the following properties
*
* x: sun azimuth in radians (direction along the horizon, measured from south to
* west), e.g. 0 is south and Math.PI * 3/4 is northwest.
* y: sun altitude above the horizon in radians, e.g. 0 at the
* horizon and PI/2 at the zenith (straight over your head).
*
*
* @param date
* @param lat
* @param lng
* @return
*/
public static Coordinate getPosition(Date date, double lat,
double lng) {
if (isGeographic(lat, lng)) {
double lw = rad * -lng;
double phi = rad * lat;
double J = dateToJulianDate(date);
double M = getSolarMeanAnomaly(J);
double C = getEquationOfCenter(M);
double Ls = getEclipticLongitude(M, C);
double d = getSunDeclination(Ls);
double a = getRightAscension(Ls);
double th = getSiderealTime(J, lw);
double H = th - a;
return new Coordinate(getAzimuth(H, phi, d),getAltitude(H, phi, d));
} else {
throw new IllegalArgumentException("The coordinate of the point must in latitude and longitude.");
}
}
/**
* Test if the point has valid latitude and longitude coordinates.
* @param latitude
* @param longitude
* @return
*/
public static boolean isGeographic(double latitude,
double longitude) {
return latitude > -90 && latitude < 90
&& longitude > -180 && longitude < 180;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy