| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247 |
- 'use strict';
- var ns = require('ns');
- var Utils = require('./Utils');
- var THREE = require('./Three.shim');
- var CMath = require('./Math');
- var maxIterationsForEccentricAnomaly = 10;
- var maxDE = 1e-15;
- var solveEccentricAnomaly = function(f, x0, maxIter) {
-
- var x = 0;
- var x2 = x0;
-
- for (var i = 0; i < maxIter; i++) {
- x = x2;
- x2 = f(x);
- }
-
- return x2;
- }
- var solveKepler = function(e, M) {
- return function(x) {
- return x + (M + e * Math.sin(x) - x) / (1 - e * Math.cos(x));
- };
- };
- var solveKeplerLaguerreConway = function(e, M) {
- return function(x) {
- var s = e * Math.sin(x);
- var c = e * Math.cos(x);
- var f = x - s - M;
- var f1 = 1 - c;
- var f2 = s;
- x += -5 * f / (f1 + CMath.sign(f1) * Math.sqrt(Math.abs(16 * f1 * f1 - 20 * f * f2)));
- return x;
- };
- };
- var solveKeplerLaguerreConwayHyp = function(e, M) {
- return function(x) {
- var s = e * CMath.sinh(x);
- var c = e * CMath.cosh(x);
- var f = x - s - M;
- var f1 = c - 1;
- var f2 = s;
- x += -5 * f / (f1 + CMath.sign(f1) * Math.sqrt(Math.abs(16 * f1 * f1 - 20 * f * f2)));
- return x;
- };
- };
- module.exports = {
- setDefaultOrbit : function(orbitalElements, calculator) {
- this.orbitalElements = orbitalElements;
- if(orbitalElements && orbitalElements.epoch) {
- this.epochCorrection = ns.getEpochTime(orbitalElements.epoch);
- }
- this.calculator = calculator;
- },
- setName : function(name){
- this.name = name;
- },
- calculateVelocity : function(timeEpoch, relativeTo, isFromDelta) {
- if(!this.orbitalElements) return new THREE.Vector3(0,0,0);
- var eclipticVelocity;
-
- if ( isFromDelta ) {
- var pos1 = this.calculatePosition(timeEpoch);
- var pos2 = this.calculatePosition(timeEpoch + 60);
- eclipticVelocity = pos2.sub(pos1).multiplyScalar(1/60);
- } else {
- //vis viva to calculate speed (not velocity, i.e not a vector)
- var el = this.calculateElements(timeEpoch);
- var speed = Math.sqrt(ns.G * require('./SolarSystem').getBody(relativeTo).mass * ((2 / (el.r)) - (1 / (el.a))));
- //now calculate velocity orientation, that is, a vector tangent to the orbital ellipse
- var k = el.r / el.a;
- var o = ((2 - (2 * el.e * el.e)) / (k * (2-k)))-1;
- //floating point imprecision
- o = o > 1 ? 1 : o;
- var alpha = Math.PI - Math.acos(o);
- alpha = el.v < 0 ? (2 * Math.PI) - alpha : alpha;
- var velocityAngle = el.v + (alpha / 2);
- //velocity vector in the plane of the orbit
- var orbitalVelocity = new THREE.Vector3(Math.cos(velocityAngle), Math.sin(velocityAngle)).setLength(speed);
- var velocityEls = Utils.extend({}, el, {pos:orbitalVelocity, v:null, r:null});
- eclipticVelocity = this.getPositionFromElements(velocityEls);
- }
- //var diff = eclipticVelocityFromDelta.sub(eclipticVelocity);console.log(diff.length());
- return eclipticVelocity;
-
- },
- calculatePosition : function(timeEpoch) {
- if(!this.orbitalElements) return new THREE.Vector3(0,0,0);
- var computed = this.calculateElements(timeEpoch);
- var pos = this.getPositionFromElements(computed);
- return pos;
- },
- solveEccentricAnomaly : function(e, M){
- if (e == 0.0) {
- return M;
- } else if (e < 0.9) {
- var sol = solveEccentricAnomaly(solveKepler(e, M), M, 6);
- return sol;
- } else if (e < 1.0) {
- var E = M + 0.85 * e * ((Math.sin(M) >= 0.0) ? 1 : -1);
- var sol = solveEccentricAnomaly(solveKeplerLaguerreConway(e, M), E, 8);
- return sol;
- } else if (e == 1.0) {
- return M;
- } else {
- var E = Math.log(2 * M / e + 1.85);
- var sol = solveEccentricAnomaly(solveKeplerLaguerreConwayHyp(e, M), E, 30);
- return sol;
- }
- },
- calculateElements : function(timeEpoch, forcedOrbitalElements) {
- if(!forcedOrbitalElements && !this.orbitalElements) return null;
- var orbitalElements = forcedOrbitalElements || this.orbitalElements;
- /*
- Epoch : J2000
- a Semi-major axis
- e Eccentricity
- i Inclination
- o Longitude of Ascending Node (Ω)
- w Argument of periapsis (ω)
- E Eccentric Anomaly
- T Time at perihelion
- M Mean anomaly
- l Mean Longitude
- lp longitude of periapsis
- r distance du centre
- v true anomaly
- P Sidereal period (mean value)
- Pw Argument of periapsis precession period (mean value)
- Pn Longitude of the ascending node precession period (mean value)
- */
- if (this.epochCorrection) {
- timeEpoch -= this.epochCorrection;
- }
- var tDays = timeEpoch / ns.DAY;
- var T = tDays / ns.CENTURY ;
- //console.log(T);
- var computed = {
- t : timeEpoch
- };
- if(this.calculator && !forcedOrbitalElements) {
- var realorbit = this.calculator(T);
- Utils.extend(computed, realorbit);
- } else {
- if (orbitalElements.base) {
- var variation;
- for(var el in orbitalElements.base) {
- //cy : variation by century.
- //day : variation by day.
- variation = orbitalElements.cy ? orbitalElements.cy[el] : (orbitalElements.day[el] * ns.CENTURY);
- variation = variation || 0;
- computed[el] = orbitalElements.base[el] + (variation * T);
- }
- } else {
- computed = Utils.extend({}, orbitalElements);
- }
- if (undefined === computed.w) {
- computed.w = computed.lp - computed.o;
- }
- if (undefined === computed.M) {
- computed.M = computed.l - computed.lp;
- }
- computed.a = computed.a * ns.KM;//was in km, set it in m
- }
- computed.i = ns.DEG_TO_RAD * computed.i;
- computed.o = ns.DEG_TO_RAD * computed.o;
- computed.w = ns.DEG_TO_RAD * computed.w;
- computed.M = ns.DEG_TO_RAD * computed.M;
- computed.E = this.solveEccentricAnomaly(computed.e, computed.M);
- computed.E = computed.E % ns.CIRCLE;
- computed.i = computed.i % ns.CIRCLE;
- computed.o = computed.o % ns.CIRCLE;
- computed.w = computed.w % ns.CIRCLE;
- computed.M = computed.M % ns.CIRCLE;
- //in the plane of the orbit
- computed.pos = new THREE.Vector3(computed.a * (Math.cos(computed.E) - computed.e), computed.a * (Math.sqrt(1 - (computed.e*computed.e))) * Math.sin(computed.E));
- computed.r = computed.pos.length();
- computed.v = Math.atan2(computed.pos.y, computed.pos.x);
- if(orbitalElements.relativeTo) {
- var relativeTo = require('./SolarSystem').getBody(orbitalElements.relativeTo);
- if(relativeTo.tilt) {
- computed.tilt = -relativeTo.tilt * ns.DEG_TO_RAD;
- }
- };
- return computed;
- },
- getPositionFromElements : function(computed) {
- if(!computed) return new THREE.Vector3(0,0,0);
- var a1 = new THREE.Euler(computed.tilt || 0, 0, computed.o, 'XYZ');
- var q1 = new THREE.Quaternion().setFromEuler(a1);
- var a2 = new THREE.Euler(computed.i, 0, computed.w, 'XYZ');
- var q2 = new THREE.Quaternion().setFromEuler(a2);
- var planeQuat = new THREE.Quaternion().multiplyQuaternions(q1, q2);
- computed.pos.applyQuaternion(planeQuat);
- return computed.pos;
- },
- calculatePeriod : function(elements, relativeTo) {
- var period;
- if(this.orbitalElements && this.orbitalElements.day && this.orbitalElements.day.M) {
- period = 360 / this.orbitalElements.day.M ;
- }else if(require('./SolarSystem').getBody(relativeTo) && require('./SolarSystem').getBody(relativeTo).k && elements) {
- period = 2 * Math.PI * Math.sqrt(Math.pow(elements.a/(ns.AU*1000), 3)) / require('./SolarSystem').getBody(relativeTo).k;
- }
- period *= ns.DAY;//in seconds
- return period;
- }
- };
|