|
|
|
class Sunpositioning {
|
|
|
|
/* Earth */
|
|
|
|
/* J0: 0.0009
|
|
|
|
J1: 0.0053
|
|
|
|
J2: -0.0068
|
|
|
|
J3: 1 */
|
|
|
|
|
|
|
|
/*
|
|
|
|
h0 dSun sin(h0)
|
|
|
|
Mercury −0.69 1.38 −0.0120
|
|
|
|
Venus −0.37 0.74 −0.0064
|
|
|
|
Earth −0.83 0.53 −0.0146
|
|
|
|
Mars −0.17 0.35 −0.0031
|
|
|
|
*/
|
|
|
|
/*
|
|
|
|
M0 M1
|
|
|
|
Mercury 174.7948 4.09233445
|
|
|
|
Venus 50.4161 1.60213034
|
|
|
|
Earth 357.5291 0.98560028
|
|
|
|
Mars 19.3730 0.52402068
|
|
|
|
Jupiter 20.0202 0.08308529
|
|
|
|
Saturn 317.0207 0.03344414
|
|
|
|
Uranus 141.0498 0.01172834
|
|
|
|
Neptune 256.2250 0.00598103
|
|
|
|
Pluto 14.882 0.00396
|
|
|
|
*/
|
|
|
|
constructor(){
|
|
|
|
this.JD1970 = 2440588;
|
|
|
|
this.JD2000 = 2451545;
|
|
|
|
this.earthC_coefficient_component = {
|
|
|
|
C1: 1.9148,
|
|
|
|
C2: 0.0200,
|
|
|
|
C3: 0.0003,
|
|
|
|
C4: 0,
|
|
|
|
C5: 0,
|
|
|
|
C6: 0,
|
|
|
|
EC: 0.0000
|
|
|
|
};
|
|
|
|
this.earth_perihelion = 102.94719;
|
|
|
|
this.earth_obliquity = 23.44 * (Math.PI / 180);
|
|
|
|
this.earth_obliquity_degrees = 23.44;
|
|
|
|
this.earth_sideral_time = {
|
|
|
|
at_zero_long: 280.1470,
|
|
|
|
rate_of_change: 360.9856235
|
|
|
|
};
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
getSunInformation(date, lat, long) {
|
|
|
|
this.CLIENT_JD = this.dateToJD(date);
|
|
|
|
this.CLIENT_LATITUDE = lat;
|
|
|
|
this.CLIENT_LONGTITUDE = long;
|
|
|
|
this.CLIENT_lw = -long;
|
|
|
|
let position = this.getSunPosition();
|
|
|
|
return {
|
|
|
|
sun_position: {
|
|
|
|
azimuth: position.azimuth.degrees,
|
|
|
|
altitude: position.altitude.degrees
|
|
|
|
},
|
|
|
|
date: this.jdToDate(this.CLIENT_JD).toString(),
|
|
|
|
sunrise: this.jdToDate(this.sunriseandsunset(this.CLIENT_JD).sunrise).toString(),
|
|
|
|
sunset: this.jdToDate(this.sunriseandsunset(this.CLIENT_JD).sunset).toString(),
|
|
|
|
mean_anomaly: this.earthMeanAnomaly(this.CLIENT_JD),
|
|
|
|
solar_transit: this.solarTransit(this.CLIENT_JD),
|
|
|
|
equation_of_center: this.equation_of_center(this.CLIENT_JD),
|
|
|
|
h: this.getHourAngle(this.CLIENT_JD),
|
|
|
|
RA: this.rightAscension(this.CLIENT_JD),
|
|
|
|
clientJD: this.CLIENT_JD,
|
|
|
|
true_anomaly: this.earthTrueAnomaly(this.CLIENT_JD),
|
|
|
|
sideraltime: this.sideraltime(this.CLIENT_JD)
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
dateToJD(date) {
|
|
|
|
return date.valueOf() / ( 1000 * 60 * 60 * 24 ) - 0.5 + this.JD1970;
|
|
|
|
}
|
|
|
|
|
|
|
|
jdToDate(jd) {
|
|
|
|
return new Date((jd + 0.5 - this.JD1970) * ( 1000 * 60 * 60 * 24 ) )
|
|
|
|
}
|
|
|
|
|
|
|
|
equation_of_center(jd) {
|
|
|
|
/*
|
|
|
|
the C4 - C6 are 0, so I just calculate for Coefficient 1 - 3.
|
|
|
|
*/
|
|
|
|
let results = this.earthC_coefficient_component.C1 * Math.sin(this.earthMeanAnomaly(jd).rad) +
|
|
|
|
this.earthC_coefficient_component.C2 * Math.sin(2 * this.earthMeanAnomaly(jd).rad) +
|
|
|
|
this.earthC_coefficient_component.C3 * Math.sin(3 * this.earthMeanAnomaly(jd).rad);
|
|
|
|
return {
|
|
|
|
degrees: results,
|
|
|
|
rad: results * (Math.PI / 180)
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
earthMeanAnomaly(jd) {
|
|
|
|
return {
|
|
|
|
degrees: ( 357.5291 + 0.98560028 * ( jd - this.JD2000 ) ) % 360,
|
|
|
|
rad: (( 357.5291 + 0.98560028 * ( jd - this.JD2000 ) ) % 360) * (Math.PI / 180)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
earthTrueAnomaly(jd) {
|
|
|
|
let results = this.equation_of_center(jd).degrees + this.earthMeanAnomaly(jd).degrees;
|
|
|
|
return {
|
|
|
|
degrees: results,
|
|
|
|
rad: results * (Math.PI / 180)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
eclipticLongtitude(jd) {
|
|
|
|
let true_anomaly = this.earthTrueAnomaly(jd);
|
|
|
|
let results = (true_anomaly.degrees + this.earth_perihelion + 180) % 360;
|
|
|
|
return {
|
|
|
|
degrees: results,
|
|
|
|
rad: results * (Math.PI / 180)
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
rightAscension(jd) {
|
|
|
|
let ecliptic_longtitude = this.eclipticLongtitude(jd);
|
|
|
|
let results = Math.atan2(Math.sin(ecliptic_longtitude.rad) * Math.cos(this.earth_obliquity), Math.cos(ecliptic_longtitude.rad));
|
|
|
|
return {
|
|
|
|
degrees: results / (Math.PI / 180),
|
|
|
|
rad: results
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
declination(jd) {
|
|
|
|
let ecliptic_longtitude = this.eclipticLongtitude(jd);
|
|
|
|
let results = Math.asin(Math.sin(ecliptic_longtitude.rad) * Math.sin(this.earth_obliquity));
|
|
|
|
return {
|
|
|
|
degrees: results / (Math.PI / 180),
|
|
|
|
rad: results
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
sideraltime(jd) {
|
|
|
|
let results = (this.earth_sideral_time.at_zero_long + this.earth_sideral_time.rate_of_change * (jd - this.JD2000) - (this.CLIENT_lw)) % 360;
|
|
|
|
return results;
|
|
|
|
}
|
|
|
|
|
|
|
|
getHourAngle(jd) {
|
|
|
|
return this.sideraltime(jd) - this.rightAscension(jd).degrees;
|
|
|
|
}
|
|
|
|
|
|
|
|
getSunPosition() {
|
|
|
|
return {
|
|
|
|
azimuth: {
|
|
|
|
rad: Math.atan2(Math.sin(this.getHourAngle(this.CLIENT_JD) * Math.PI / 180),
|
|
|
|
Math.cos(this.getHourAngle(this.CLIENT_JD) * Math.PI / 180) * Math.sin(this.CLIENT_LATITUDE * Math.PI / 180) - Math.tan(this.declination(this.CLIENT_JD).rad) * Math.cos(this.CLIENT_LATITUDE * Math.PI / 180)),
|
|
|
|
degrees: Math.atan2(Math.sin(this.getHourAngle(this.CLIENT_JD) * Math.PI / 180),
|
|
|
|
Math.cos(this.getHourAngle(this.CLIENT_JD) * Math.PI / 180) * Math.sin(this.CLIENT_LATITUDE * Math.PI / 180) -
|
|
|
|
Math.tan(this.declination(this.CLIENT_JD).rad) * Math.cos(this.CLIENT_LATITUDE * Math.PI / 180)) / (Math.PI / 180)
|
|
|
|
},
|
|
|
|
altitude: {
|
|
|
|
rad: Math.asin(Math.sin(this.CLIENT_LATITUDE * (Math.PI / 180)) * Math.sin(this.declination(this.CLIENT_JD).rad) +
|
|
|
|
Math.cos(this.CLIENT_LATITUDE * Math.PI / 180) * Math.cos(this.declination(this.CLIENT_JD).rad) * Math.cos(this.getHourAngle(this.CLIENT_JD) * Math.PI / 180)),
|
|
|
|
degrees: Math.asin(Math.sin(this.CLIENT_LATITUDE * (Math.PI / 180)) * Math.sin(this.declination(this.CLIENT_JD).rad) +
|
|
|
|
Math.cos(this.CLIENT_LATITUDE * Math.PI / 180) * Math.cos(this.declination(this.CLIENT_JD).rad) * Math.cos(this.getHourAngle(this.CLIENT_JD) * Math.PI / 180)) / (Math.PI / 180)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
solarTransit(jd) {
|
|
|
|
let lw = this.CLIENT_lw;
|
|
|
|
let _JD2000 = this.JD2000
|
|
|
|
function nx() { return ((jd - _JD2000 - 0.0009) / 1 - (lw / 360)); }
|
|
|
|
let n = Math.round(nx());
|
|
|
|
function JDX() { return jd + 1 * ( n - nx() ); }
|
|
|
|
let M = this.earthMeanAnomaly(JDX()).degrees;
|
|
|
|
let L = (M + this.earth_perihelion + 180) % 360;
|
|
|
|
let JDtmp = JDX() + 0.0053 * Math.sin(M * Math.PI / 180) - 0.0068 * Math.sin(2 * (L * (Math.PI / 180)));
|
|
|
|
return JDtmp - (0 / 360 ) * 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
sunriseandsunset(jd) {
|
|
|
|
let jd_from_approx_transit = this.solarTransit(jd);
|
|
|
|
let sundeclination = this.declination(jd_from_approx_transit);
|
|
|
|
let Ht = Math.acos((-0.0146 - Math.sin(this.CLIENT_LATITUDE * Math.PI / 180) * Math.sin(sundeclination.rad)) /
|
|
|
|
Math.cos(this.CLIENT_LATITUDE * Math.PI / 180) * Math.cos(sundeclination.rad));
|
|
|
|
return {
|
|
|
|
sunrise: jd_from_approx_transit - ((Ht / (Math.PI / 180)) / 360) * 1,
|
|
|
|
sunset: jd_from_approx_transit + ((Ht / (Math.PI / 180)) / 360) * 1
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
module.exports = Sunpositioning;
|