mirror of
https://github.com/overte-org/overte.git
synced 2025-04-19 16:23:39 +02:00
Script that uses date, time and coordinates to compute sun position - this is then used to position the keylight.
This commit is contained in:
parent
7f5897e90b
commit
9b9295aaec
1 changed files with 277 additions and 0 deletions
277
scripts/developer/sunModel.js
Normal file
277
scripts/developer/sunModel.js
Normal file
|
@ -0,0 +1,277 @@
|
|||
//
|
||||
// sunModel.js
|
||||
// scripts/developer
|
||||
//
|
||||
// Created by Nissim Hadar on 2017/12/27.
|
||||
// Copyright 2013 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
// Code is based on the NOAA model - see https://www.esrl.noaa.gov/gmd/grad/solcalc/
|
||||
//
|
||||
(function() {
|
||||
// Utility functions for trig. calculations
|
||||
function toRadians(angle_degs) {
|
||||
return angle_degs * (Math.PI / 180);
|
||||
}
|
||||
function toDegrees(angle_rads) {
|
||||
return angle_rads * (180.0 / Math.PI);
|
||||
}
|
||||
|
||||
// Parameters
|
||||
var latitude_degs = 47.751033;
|
||||
var longitude_degs = -122.228176;
|
||||
|
||||
// These are used a lot
|
||||
var latitude = toRadians(latitude_degs);
|
||||
var longitude = toRadians(longitude_degs);
|
||||
|
||||
// Code to check if Daylight Savings is active
|
||||
Date.prototype.stdTimezoneOffset = function() {
|
||||
var fy = this.getFullYear();
|
||||
if (!Date.prototype.stdTimezoneOffset.cache.hasOwnProperty(fy)) {
|
||||
var maxOffset = new Date(fy, 0, 1).getTimezoneOffset();
|
||||
var monthsTestOrder = [6, 7, 5, 8, 4, 9, 3, 10, 2, 11, 1];
|
||||
|
||||
for(var mi = 0;mi < 12; ++mi) {
|
||||
var offset = new Date(fy, monthsTestOrder[mi], 1).getTimezoneOffset();
|
||||
if (offset != maxOffset) {
|
||||
maxOffset = Math.max(maxOffset, offset);
|
||||
break;
|
||||
}
|
||||
}
|
||||
Date.prototype.stdTimezoneOffset.cache[fy] = maxOffset;
|
||||
}
|
||||
return Date.prototype.stdTimezoneOffset.cache[fy];
|
||||
};
|
||||
|
||||
// Cache the result for per year stdTimezoneOffset so that you don't need to recalculate it when testing multiple dates in
|
||||
// the same year.
|
||||
Date.prototype.stdTimezoneOffset.cache = {};
|
||||
|
||||
Date.prototype.isDST = function() {
|
||||
return this.getTimezoneOffset() < this.stdTimezoneOffset();
|
||||
};
|
||||
|
||||
// The Julian Date is the number of days (fractional) that have elapsed since Jan 1st, 4713 BC
|
||||
function getJulianDate(dateTime) {
|
||||
var month = dateTime.getMonth() + 1;
|
||||
var day = dateTime.getDate() + 1;
|
||||
var year = dateTime.getFullYear();
|
||||
|
||||
if (month <= 2) {
|
||||
year -= 1;
|
||||
month += 12;
|
||||
}
|
||||
|
||||
var A = Math.floor(year / 100);
|
||||
var B = 2 - A + Math.floor(A / 4);
|
||||
return Math.floor(365.25 * (year + 4716)) + Math.floor(30.6001 * (month + 1)) + day + B - 1524.5;
|
||||
}
|
||||
|
||||
function getMinutes(dateTime) {
|
||||
var hours = dateTime.getHours();
|
||||
var minutes = dateTime.getMinutes();
|
||||
var seconds = dateTime.getSeconds();
|
||||
|
||||
if (Date.prototype.isDST()) {
|
||||
hour -= 1;
|
||||
}
|
||||
|
||||
return hours * 60 + minutes + seconds / 60.0;
|
||||
}
|
||||
|
||||
function calcGeomMeanAnomalySun(t) {
|
||||
var M = 357.52911 + t * (35999.05029 - 0.0001537 * t);
|
||||
return M; // in degrees
|
||||
}
|
||||
|
||||
function calcSunEqOfCenter(t) {
|
||||
var m = calcGeomMeanAnomalySun(t);
|
||||
var mrad = toRadians(m);
|
||||
var sinm = Math.sin(mrad);
|
||||
var sin2m = Math.sin(mrad + mrad);
|
||||
var sin3m = Math.sin(mrad + mrad + mrad);
|
||||
var C = sinm * (1.914602 - t * (0.004817 + 0.000014 * t)) + sin2m * (0.019993 - 0.000101 * t) + sin3m * 0.000289;
|
||||
return C; // in degrees
|
||||
}
|
||||
|
||||
function calcGeomMeanLongSun(t) {
|
||||
var L0 = 280.46646 + t * (36000.76983 + t*(0.0003032))
|
||||
while(L0 > 360.0) {
|
||||
L0 -= 360.0
|
||||
}
|
||||
while(L0 < 0.0) {
|
||||
L0 += 360.0
|
||||
}
|
||||
return L0 // in degrees
|
||||
}
|
||||
|
||||
function calcSunTrueLong(t) {
|
||||
var l0 = calcGeomMeanLongSun(t);
|
||||
var c = calcSunEqOfCenter(t);
|
||||
var O = l0 + c;
|
||||
return O; // in degrees
|
||||
}
|
||||
|
||||
function calcSunApparentLong(t) {
|
||||
var o = calcSunTrueLong(t);
|
||||
var omega = 125.04 - 1934.136 * t;
|
||||
var lambda = o - 0.00569 - 0.00478 * Math.sin(toRadians(omega));
|
||||
return lambda; // in degrees
|
||||
}
|
||||
|
||||
function calcMeanObliquityOfEcliptic(t) {
|
||||
var seconds = 21.448 - t * (46.8150 + t * (0.00059 - t * (0.001813)));
|
||||
var e0 = 23.0 + (26.0 + (seconds / 60.0)) / 60.0;
|
||||
return e0; // in degrees
|
||||
}
|
||||
|
||||
function calcObliquityCorrection(t) {
|
||||
var e0 = calcMeanObliquityOfEcliptic(t);
|
||||
var omega = 125.04 - 1934.136 * t;
|
||||
var e = e0 + 0.00256 * Math.cos(toRadians(omega));
|
||||
return e; // in degrees
|
||||
}
|
||||
|
||||
function calcSunDeclination(t) {
|
||||
var e = calcObliquityCorrection(t);
|
||||
var lambda = calcSunApparentLong(t);
|
||||
|
||||
var sint = Math.sin(toRadians(e)) * Math.sin(toRadians(lambda));
|
||||
var theta = toDegrees(Math.asin(sint));
|
||||
return theta; // in degrees
|
||||
}
|
||||
|
||||
function calcEccentricityEarthOrbit(t) {
|
||||
var e = 0.016708634 - t * (0.000042037 + 0.0000001267 * t);
|
||||
return e; // unitless
|
||||
}
|
||||
|
||||
function calcEquationOfTime(t) {
|
||||
var epsilon = calcObliquityCorrection(t);
|
||||
var l0 = calcGeomMeanLongSun(t);
|
||||
var e = calcEccentricityEarthOrbit(t);
|
||||
var m = calcGeomMeanAnomalySun(t);
|
||||
|
||||
var y = Math.tan(toRadians(epsilon) / 2.0);
|
||||
y *= y;
|
||||
|
||||
var sin2l0 = Math.sin(2.0 * toRadians(l0));
|
||||
var sinm = Math.sin(toRadians(m));
|
||||
var cos2l0 = Math.cos(2.0 * toRadians(l0));
|
||||
var sin4l0 = Math.sin(4.0 * toRadians(l0));
|
||||
var sin2m = Math.sin(2.0 * toRadians(m));
|
||||
|
||||
var Etime = y * sin2l0 - 2.0 * e * sinm + 4.0 * e * y * sinm * cos2l0 - 0.5 * y * y * sin4l0 - 1.25 * e * e * sin2m;
|
||||
return toDegrees(Etime) * 4.0; // in minutes of time
|
||||
}
|
||||
|
||||
function calcSunTrueAnomaly(t) {
|
||||
var m = calcGeomMeanAnomalySun(t);
|
||||
var c = calcSunEqOfCenter(t);
|
||||
var v = m + c;
|
||||
return v; // in degrees
|
||||
}
|
||||
|
||||
function calcSunRadVector(t) {
|
||||
var v = calcSunTrueAnomaly(t);
|
||||
var e = calcEccentricityEarthOrbit(t);
|
||||
var R = (1.000001018 * (1 - e * e)) / (1 + e * Math.cos(toRadians(v)));
|
||||
return R; // in AUs
|
||||
}
|
||||
|
||||
var COMPUTATION_CYCLE = 5000; // Run every 5 seconds
|
||||
this.preload = function(entityID) { // You don't have the entityID before the preload
|
||||
Script.setInterval(
|
||||
function() {
|
||||
var dateTime = new Date();
|
||||
|
||||
var julianDay = getJulianDate(dateTime);
|
||||
var localTimeMinutes = getMinutes(dateTime);
|
||||
var timeZone = -dateTime.getTimezoneOffset() / 60;
|
||||
var totalTime = julianDay + localTimeMinutes/1440.0 - timeZone / 24.0;
|
||||
var julianCentralTime = (julianDay - 2451545.0)/36525.0;
|
||||
var eqTime = calcEquationOfTime(julianCentralTime)
|
||||
var theta_rads = toRadians(calcSunDeclination(julianCentralTime));
|
||||
var solarTimeFix = eqTime + 4.0 * longitude_degs - 60.0 * timeZone;
|
||||
var earthRadVec = calcSunRadVector(julianCentralTime);
|
||||
|
||||
var trueSolarTime = localTimeMinutes + solarTimeFix;
|
||||
while (trueSolarTime > 1440) {
|
||||
trueSolarTime -= 1440;
|
||||
}
|
||||
|
||||
var hourAngle = trueSolarTime / 4.0 - 180.0;
|
||||
if (hourAngle < -180.0) {
|
||||
hourAngle += 360.0;
|
||||
}
|
||||
var hourAngleRadians = toRadians(hourAngle);
|
||||
|
||||
var csz = Math.sin(latitude) * Math.sin(theta_rads) +
|
||||
Math.cos(latitude) * Math.cos(theta_rads) * Math.cos(hourAngleRadians);
|
||||
csz = Math.min(1.0, Math.max(-1.0, csz));
|
||||
|
||||
var zenith = toDegrees(Math.acos(csz));
|
||||
var azDenom = ( Math.cos(latitude) * Math.sin(toRadians(zenith)));
|
||||
if (Math.abs(azDenom) > 0.001) {
|
||||
azRad = (( Math.sin(latitude) * Math.cos(toRadians(zenith)) ) - Math.sin(theta_rads)) / azDenom;
|
||||
if (Math.abs(azRad) > 1.0) {
|
||||
if (azRad < 0.0) {
|
||||
azRad = -1.0;
|
||||
} else {
|
||||
azRad = 1.0;
|
||||
}
|
||||
}
|
||||
var solarAzimuth_degs = 180.0 - toDegrees(Math.acos(azRad))
|
||||
if (hourAngle > 0.0) {
|
||||
solarAzimuth_degs = -solarAzimuth_degs;
|
||||
}
|
||||
} else {
|
||||
if (latitude_degs > 0.0) {
|
||||
solarAzimuth_degs = 180.0;
|
||||
} else {
|
||||
solarAzimuth_degs = 0.0;
|
||||
}
|
||||
}
|
||||
if (solarAzimuth_degs < 0.0) {
|
||||
solarAzimuth_degs += 360.0;
|
||||
}
|
||||
|
||||
// Atmospheric Refraction correction
|
||||
var exoatmElevation = 90.0 - zenith;
|
||||
if (exoatmElevation > 85.0) {
|
||||
var refractionCorrection = 0.0;
|
||||
} else {
|
||||
var te = Math.tan(toRadians(exoatmElevation));
|
||||
if (exoatmElevation > 5.0) {
|
||||
var refractionCorrection = 58.1 / te - 0.07 / (te * te * te) + 0.000086 / (te * te * te * te * te);
|
||||
} else if (exoatmElevation > -0.575) {
|
||||
var refractionCorrection =
|
||||
1735.0 + exoatmElevation *
|
||||
(-518.2 + exoatmElevation * (103.4 + exoatmElevation * (-12.79 + exoatmElevation * 0.711)));
|
||||
} else {
|
||||
var refractionCorrection = -20.774 / te;
|
||||
}
|
||||
refractionCorrection = refractionCorrection / 3600.0;
|
||||
}
|
||||
|
||||
var solarZenith = zenith - refractionCorrection;
|
||||
var solarAltitude_degs = 90.0 - solarZenith; // aka solar elevation
|
||||
|
||||
// Convert to XYZ
|
||||
var solarAltitude = toRadians(solarAltitude_degs);
|
||||
var solarAzimuth = toRadians(solarAzimuth_degs);
|
||||
|
||||
var xPos = Math.cos(solarAltitude) * Math.sin(solarAzimuth);
|
||||
var zPos = Math.cos(solarAltitude) * Math.cos(solarAzimuth);
|
||||
var yPos = -Math.sin(solarAltitude);
|
||||
|
||||
Entities.editEntity(entityID, { keyLight : {direction: { x: xPos, y: yPos, z: zPos }}});
|
||||
},
|
||||
|
||||
COMPUTATION_CYCLE
|
||||
);
|
||||
};
|
||||
});
|
Loading…
Reference in a new issue