137 lines
4.4 KiB
JavaScript
137 lines
4.4 KiB
JavaScript
|
/* Terminator.js -- Overlay day/night region on a Leaflet map */
|
||
|
|
||
|
Date.prototype.getJulian = function() {
|
||
|
/* Calculate the present UTC Julian Date. Function is valid after
|
||
|
* the beginning of the UNIX epoch 1970-01-01 and ignores leap
|
||
|
* seconds. */
|
||
|
return (this / 86400000) + 2440587.5;
|
||
|
}
|
||
|
|
||
|
Date.prototype.getGMST = function() {
|
||
|
/* Calculate Greenwich Mean Sidereal Time according to
|
||
|
http://aa.usno.navy.mil/faq/docs/GAST.php */
|
||
|
var julianDay = this.getJulian();
|
||
|
var d = julianDay - 2451545.0;
|
||
|
// Low precision equation is good enough for our purposes.
|
||
|
return (18.697374558 + 24.06570982441908 * d) % 24;
|
||
|
}
|
||
|
|
||
|
L.Terminator = L.Polygon.extend({
|
||
|
options: {
|
||
|
color: '#00',
|
||
|
opacity: 0.1,
|
||
|
fillColor: '#00',
|
||
|
fillOpacity: 0.1,
|
||
|
resolution: 2
|
||
|
},
|
||
|
|
||
|
initialize: function(options) {
|
||
|
this.version = '0.1.0';
|
||
|
this._R2D = 180 / Math.PI;
|
||
|
this._D2R = Math.PI / 180;
|
||
|
L.Util.setOptions(this, options);
|
||
|
var latLng = this._compute(this.options.time || null)
|
||
|
this.setLatLngs(latLng);
|
||
|
},
|
||
|
|
||
|
_sunEclipticPosition: function(julianDay) {
|
||
|
/* Compute the position of the Sun in ecliptic coordinates at
|
||
|
julianDay. Following
|
||
|
http://en.wikipedia.org/wiki/Position_of_the_Sun */
|
||
|
// Days since start of J2000.0
|
||
|
var n = julianDay - 2451545.0;
|
||
|
// mean longitude of the Sun
|
||
|
var L = 280.460 + 0.9856474 * n;
|
||
|
L %= 360;
|
||
|
// mean anomaly of the Sun
|
||
|
var g = 357.528 + 0.9856003 * n;
|
||
|
g %= 360;
|
||
|
// ecliptic longitude of Sun
|
||
|
var lambda = L + 1.915 * Math.sin(g * this._D2R) +
|
||
|
0.02 * Math.sin(2 * g * this._D2R);
|
||
|
// distance from Sun in AU
|
||
|
var R = 1.00014 - 0.01671 * Math.cos(g * this._D2R) -
|
||
|
0.0014 * Math.cos(2 * g * this._D2R);
|
||
|
return {"lambda": lambda, "R": R};
|
||
|
},
|
||
|
|
||
|
_eclipticObliquity: function(julianDay) {
|
||
|
// Following the short term expression in
|
||
|
// http://en.wikipedia.org/wiki/Axial_tilt#Obliquity_of_the_ecliptic_.28Earth.27s_axial_tilt.29
|
||
|
var n = julianDay - 2451545.0;
|
||
|
// Julian centuries since J2000.0
|
||
|
var T = n / 36525;
|
||
|
var epsilon = 23.43929111 -
|
||
|
T * (46.836769 / 3600
|
||
|
- T * (0.0001831 / 3600
|
||
|
+ T * (0.00200340 / 3600
|
||
|
- T * (0.576e-6 / 3600
|
||
|
- T * 4.34e-8 / 3600))));
|
||
|
return epsilon;
|
||
|
},
|
||
|
|
||
|
_sunEquatorialPosition: function(sunEclLng, eclObliq) {
|
||
|
/* Compute the Sun's equatorial position from its ecliptic
|
||
|
* position. Inputs are expected in degrees. Outputs are in
|
||
|
* degrees as well. */
|
||
|
var alpha = Math.atan(Math.cos(eclObliq * this._D2R)
|
||
|
* Math.tan(sunEclLng * this._D2R)) * this._R2D;
|
||
|
var delta = Math.asin(Math.sin(eclObliq * this._D2R)
|
||
|
* Math.sin(sunEclLng * this._D2R)) * this._R2D;
|
||
|
|
||
|
var lQuadrant = Math.floor(sunEclLng / 90) * 90;
|
||
|
var raQuadrant = Math.floor(alpha / 90) * 90;
|
||
|
alpha = alpha + (lQuadrant - raQuadrant);
|
||
|
|
||
|
return {"alpha": alpha, "delta": delta};
|
||
|
},
|
||
|
|
||
|
_hourAngle: function(lng, sunPos, gst) {
|
||
|
/* Compute the hour angle of the sun for a longitude on
|
||
|
* Earth. Return the hour angle in degrees. */
|
||
|
var lst = gst + lng / 15;
|
||
|
return lst * 15 - sunPos.alpha;
|
||
|
},
|
||
|
|
||
|
_latitude: function(ha, sunPos) {
|
||
|
/* For a given hour angle and sun position, compute the
|
||
|
* latitude of the terminator in degrees. */
|
||
|
var lat = Math.atan(-Math.cos(ha * this._D2R) /
|
||
|
Math.tan(sunPos.delta * this._D2R)) * this._R2D;
|
||
|
return lat;
|
||
|
},
|
||
|
|
||
|
_compute: function(time) {
|
||
|
if (time == null)
|
||
|
var today = new Date();
|
||
|
else
|
||
|
var today = new Date(time);
|
||
|
var julianDay = today.getJulian();
|
||
|
var gst = today.getGMST();
|
||
|
var latLng = [];
|
||
|
var ha, lat;
|
||
|
|
||
|
var sunEclPos = this._sunEclipticPosition(julianDay);
|
||
|
var eclObliq = this._eclipticObliquity(julianDay);
|
||
|
var sunEqPos = this._sunEquatorialPosition(sunEclPos.lambda, eclObliq);
|
||
|
for (var i = 0; i <= 720 * this.options.resolution; i++) {
|
||
|
lng = -360 + i / this.options.resolution;
|
||
|
ha = this._hourAngle(lng, sunEqPos, gst);
|
||
|
lat = this._latitude(ha, sunEqPos);
|
||
|
latLng[i+1] = [lat, lng];
|
||
|
}
|
||
|
if (sunEqPos.delta < 0) {
|
||
|
latLng[0] = [90, -360];
|
||
|
latLng[latLng.length] = [90, 360];
|
||
|
} else {
|
||
|
latLng[0] = [-90, -360];
|
||
|
latLng[latLng.length] = [-90, 360];
|
||
|
}
|
||
|
return latLng;
|
||
|
}
|
||
|
});
|
||
|
|
||
|
L.terminator = function(options) {
|
||
|
return new L.Terminator(options);
|
||
|
};
|