// Create an NBody and check it's mass public void EccentricityPrediction() { const float mass = 1000f; GameObject star = TestSetupUtils.CreateNBody(mass, new Vector3(0, 0, 0)); NBody starNbody = star.GetComponent <NBody>(); const float orbitRadius = 10f; GameObject planet = TestSetupUtils.CreatePlanetInOrbitUniversal(starNbody, 1f, orbitRadius); OrbitUniversal orbitU = planet.GetComponent <OrbitUniversal>(); OrbitPredictor op = TestSetupUtils.AddOrbitPredictor(planet, star); Assert.NotNull(op); double[] ecc_values = { 0, 0.1, 0.7, 0.9, 0.99, 1.01, 1.5, 2 }; foreach (double ecc in ecc_values) { Debug.LogFormat("#### EccentricityPrediction ecc={0}", ecc); orbitU.eccentricity = ecc; TestSetupUtils.SetupGravityEngine(star, planet); op.TestRunnerSetup(); OrbitUniversal predictedOrbit = op.GetOrbitUniversal(); Assert.NotNull(predictedOrbit); CompareOrbits(orbitU, predictedOrbit, small); } }
public override void OnInspectorGUI() { KeplerSequence keplerSeq = (KeplerSequence)target; OrbitUniversal orbitU = keplerSeq.GetComponent <OrbitUniversal>(); if (orbitU.evolveMode == OrbitUniversal.EvolveMode.GRAVITY_ENGINE) { EditorGUILayout.LabelField("Base orbit is in GRAVITY MODE. Kepler sequence will be ignored!"); return; } if (EditorApplication.isPlaying) { EditorGUILayout.LabelField("Dump of Kepler Sequence Elements"); EditorGUILayout.LabelField(string.Format("time={0} current={1}", GravityEngine.Instance().GetPhysicalTime(), keplerSeq.GetCurrentOrbitIndex())); string[] info = keplerSeq.DumpInfo().Split('\n'); foreach (string s in info) { EditorGUILayout.LabelField(s); } EditorGUILayout.LabelField("Tip: GetCurrentOrbit() returns the active element."); } else { EditorGUILayout.LabelField("Inspector will show active elements when playing"); } }
// Create an NBody and check it's mass public void OmegaUEllipsePrediction() { const float mass = 1000f; GameObject star = TestSetupUtils.CreateNBody(mass, new Vector3(0, 0, 0)); NBody starNbody = star.GetComponent <NBody>(); const float orbitRadius = 10f; GameObject planet = TestSetupUtils.CreatePlanetInOrbitUniversal(starNbody, 1f, orbitRadius); OrbitUniversal orbitU = planet.GetComponent <OrbitUniversal>(); // Need a bit of incl, otherwise omegaU comes back as omegaL. orbitU.inclination = 10; orbitU.eccentricity = 0.05; OrbitPredictor op = TestSetupUtils.AddOrbitPredictor(planet, star); Assert.NotNull(op); double[] ou_values = { 0, 1, 5, 10, 30, 60, 90, 180, 270, 355, 360 }; foreach (double ou in ou_values) { Debug.LogFormat("#### OmegaUPrediction ou={0}", ou); orbitU.omega_uc = ou; TestSetupUtils.SetupGravityEngine(star, planet); op.TestRunnerSetup(); OrbitUniversal predictedOrbit = op.GetOrbitUniversal(); Assert.NotNull(predictedOrbit); CompareOrbits(orbitU, predictedOrbit, small); } }
// Check eccentricity and inclination public void CheckTestRV() { const float mass = 1000f; GameObject star = TestSetupUtils.CreateNBody(mass, new Vector3(0, 0, 0)); NBody starNbody = star.GetComponent <NBody>(); const float orbitRadius = 10f; GameObject planet = TestSetupUtils.CreatePlanetInOrbitUniversal(starNbody, 1f, orbitRadius); OrbitUniversal orbitU = planet.GetComponent <OrbitUniversal>(); orbitU.eccentricity = .25f; orbitU.inclination = 25f; orbitU.omega_uc = 10f; orbitU.omega_lc = 20f; orbitU.phase = 190f; orbitU.SetMajorAxisInspector(orbitRadius); OrbitData od = new OrbitData(); od.a = orbitRadius; od.ecc = 0.25f; od.inclination = 25f; od.omega_uc = 10f; od.omega_lc = 20f; od.phase = 190f; od.centralMass = starNbody; GravityEngine.Instance().UnitTestAwake(); Debug.LogFormat("major-axis: {0} vs {1}", orbitU.GetMajorAxisInspector(), orbitRadius); Assert.AreEqual(orbitU.GetMajorAxisInspector(), orbitRadius); TestRV(od, planet, starNbody, orbitRadius); }
// Create an NBody and check it's mass public void InclinationPrediction() { const float mass = 1000f; GameObject star = TestSetupUtils.CreateNBody(mass, new Vector3(0, 0, 0)); NBody starNbody = star.GetComponent <NBody>(); const float orbitRadius = 10f; GameObject planet = TestSetupUtils.CreatePlanetInOrbitUniversal(starNbody, 1f, orbitRadius); OrbitUniversal orbitU = planet.GetComponent <OrbitUniversal>(); OrbitPredictor op = TestSetupUtils.AddOrbitPredictor(planet, star); Assert.NotNull(op); double[] incl_values = { 0, 1, 5, 10, 30, 45, 60, 90, 145, 179, 180 }; foreach (double incl in incl_values) { Debug.LogFormat("#### InclinationPrediction incl={0}", incl); orbitU.inclination = incl; TestSetupUtils.SetupGravityEngine(star, planet); op.TestRunnerSetup(); OrbitUniversal predictedOrbit = op.GetOrbitUniversal(); Assert.NotNull(predictedOrbit); CompareOrbits(orbitU, predictedOrbit, small); } }
/// <summary> /// Raise a circular orbit by the specified percent /// - only on-rail is implemented /// </summary> /// <param name="percentRaise"></param> private void NewCircularOrbit(float percentRaise) { if (onRails) { KeplerSequence keplerSeq = spaceship.GetComponent <KeplerSequence>(); OrbitUniversal orbitU = keplerSeq.GetCurrentOrbit(); // check orbit is circular if (orbitU.eccentricity < 1E-2) { // circular, ok to proceed OrbitData fromOrbit = new OrbitData(orbitU); OrbitData toOrbit = new OrbitData(fromOrbit); toOrbit.a = percentRaise * fromOrbit.a; const bool rendezvous = false; OrbitTransfer hohmannXfer = new HohmannXfer(fromOrbit, toOrbit, rendezvous); keplerSeq.RemoveFutureSegments(); keplerSeq.AddManeuvers(hohmannXfer.GetManeuvers()); } } else { // assume we're in orbit around the moon OrbitData orbitData = new OrbitData(); orbitData.SetOrbitForVelocity(spaceship, moonBody); OrbitData toOrbit = new OrbitData(orbitData); toOrbit.a = percentRaise * orbitData.a; const bool rendezvous = false; OrbitTransfer hohmannXfer = new HohmannXfer(orbitData, toOrbit, rendezvous); ge.AddManeuvers(hohmannXfer.GetManeuvers()); } }
/// <summary> /// The spaceship has a fixed orbit that is on rails (must be an OrbitUniversal). /// /// To allow for setting of specific times and forward/backward motion implement the transfer as a /// KeplerSequence of three OrbitUniversals: /// - initial orbit when t less then now /// - transfer ellipse when t between now and (now + transfer_time) /// - destination orbit when t greater than (now + transfer_time) /// /// </summary> private void TransferOnRails() { // initial orbit - needs to be OrbitUniversal (could morph an OrbitEllipse, but keep things simple) OrbitUniversal initialOrbit = spaceshipNBody.GetComponent <OrbitUniversal>(); if (initialOrbit == null) { Debug.LogError("script assumes ship orbit will be OrbitUniversal"); return; } KeplerSequence keplerSeq = spaceshipNBody.GetComponent <KeplerSequence>(); if (keplerSeq == null) { Debug.LogError("Cannot do on-rails transfer. Ship does not have a KeplerSequence"); return; } // Kepler sequence already has the initial orbit. // transfer orbit Vector3d xfer_r0 = lambertU.GetTransferPositionDouble(); Vector3d xfer_v0 = lambertU.GetTransferVelocityDouble(); double xfer_t = ge.GetPhysicalTimeDouble(); keplerSeq.AppendElementRVT(xfer_r0, xfer_v0, xfer_t, false, spaceshipNBody, starNBody, null); // destination orbit double dest_t = xfer_t + transferTime; Vector3d dest_v = new Vector3d(targetData.GetPhysicsVelocityForEllipse(targetData.phase)); Vector3d dest_r = new Vector3d(targetData.GetPhysicsPositionforEllipse(targetData.phase)); keplerSeq.AppendElementRVT(dest_r, dest_v, dest_t, false, spaceshipNBody, starNBody, SequenceDoneCallback); }
/// <summary> /// Add an element to the sequence that begins at time and evolves based on the orbit data provided. /// /// Orbit elements must be added in increasing time order. /// </summary> /// <param name="time"></param> /// <param name="orbitData"></param> /// <param name="body"></param> /// <param name="centerBody"></param> /// <param name="callback">(Optional) Method to call when sequence starts</param> /// <returns></returns> public OrbitUniversal AppendElementOrbitData(double time, OrbitData orbitData, NBody body, NBody centerBody, ElementStarted callback) { if (BadTime(time)) { return(null); } KeplerElement ke = new KeplerElement { timeStart = time, returnToGE = false, callback = callback }; OrbitUniversal orbit = orbitsGO.AddComponent <OrbitUniversal>(); orbit.centerNbody = centerBody; orbit.SetNBody(body); orbit.InitFromOrbitData(orbitData, time); orbit.evolveMode = OrbitUniversal.EvolveMode.KEPLERS_EQN; ke.orbit = orbit; keplerElements.Add(ke); return(orbit); }
/// <summary> /// Circularize around Moon /// - currently only onRails is implemented /// </summary> private void CircularizeAroundMoon() { // check ship is on segment where it near Moon if (onRails) { KeplerSequence keplerSeq = spaceship.GetComponent <KeplerSequence>(); OrbitUniversal orbitU = keplerSeq.GetCurrentOrbit(); if (orbitU.centerNbody == moonBody) { // in orbit around the moon - do circularization OrbitData orbitData = new OrbitData(orbitU); OrbitTransfer circularizeXfer = new CircularizeXfer(orbitData); keplerSeq.RemoveFutureSegments(); keplerSeq.AddManeuvers(circularizeXfer.GetManeuvers()); } } else { // assume we're in orbit around the moon OrbitData orbitData = new OrbitData(); orbitData.SetOrbitForVelocity(spaceship, moonBody); OrbitTransfer circularizeXfer = new CircularizeXfer(orbitData); ge.AddManeuvers(circularizeXfer.GetManeuvers()); } }
// Use this for initialization (must Awake, since start of GameLoop will set states) void Awake() { state = State.SELECT_OBJECTIVE; intercepts = null; time_to_moon_phys = TIME_TO_MOON_SEC / GravityScaler.GetGameSecondPerPhysicsSecond(); if (targets.Length == 0) { Debug.LogError("No targets configured"); } // Player is spaceship 1, others are objectives // take first ship to tbe the player target = targets[0]; // Need to configure objective chooser SetObjectiveOptions(targets); SetState(state); // add a trajectory intercepts component (it need to handle markers so it has // a monobehaviour base class). // The pair of spaceships to be checked will be selected dynamically trajIntercepts = gameObject.AddComponent <TrajectoryIntercepts>(); trajIntercepts.interceptSymbol = interceptMarker; trajIntercepts.rendezvousSymbol = rendezvousMarker; spaceshipGO = spaceshipCtrl.transform.parent.gameObject; // optional spaceshipOrbit = spaceshipGO.GetComponent <OrbitUniversal>(); // only record the elements that are active at the start of the scene orbitPredictors = new List <OrbitPredictor>(); foreach (OrbitPredictor op in (OrbitPredictor[])Object.FindObjectsOfType(typeof(OrbitPredictor))) { if (op.gameObject.activeInHierarchy) { orbitPredictors.Add(op); if (op.transform.parent == spaceshipGO.transform) { shipOrbitPredictor = op; } } } if (shipOrbitPredictor == null) { Debug.LogError("Did not find orbit predictor for ship"); } orbitRenderers = new List <OrbitRenderer>(); foreach (OrbitRenderer or in (OrbitRenderer[])Object.FindObjectsOfType(typeof(OrbitRenderer))) { if (or.gameObject.activeInHierarchy) { orbitRenderers.Add(or); } } }
/// <summary> /// Add an element to the sequence using r0/v0/t0 initial conditions. /// /// Position and velocity are with respect to the center body (NOT world/physics space!). /// /// Orbit segements must be added in increasing time order. /// </summary> /// <param name="r0"></param> /// <param name="v0"></param> /// <param name="time"></param> /// <param name="relativePos"></param> /// <param name="body"></param> /// <param name="centerBody"></param> /// <param name="callback">(Optional) Method to call when sequence starts</param> /// <returns></returns> public OrbitUniversal AppendElementRVT(Vector3d r0, Vector3d v0, double time, bool relativePos, NBody body, NBody centerBody, ElementStarted callback) { if (BadTime(time)) { return(null); } KeplerElement ke = new KeplerElement { timeStart = time, callback = callback, returnToGE = false }; OrbitUniversal orbit = orbitsGO.AddComponent <OrbitUniversal>(); orbit.centerNbody = centerBody; orbit.SetNBody(body); orbit.InitFromRVT(r0, v0, time, centerBody, relativePos); orbit.evolveMode = OrbitUniversal.EvolveMode.KEPLERS_EQN; ke.orbit = orbit; keplerElements.Add(ke); return(orbit); }
/// <summary> /// Determine the SOI radius in internal physics units. /// </summary> /// <param name="planet"></param> /// <param name="moon"></param> /// <returns></returns> public static float SoiRadius(NBody planet, NBody moon) { // to allow to run before GE is up, use Ellipse component to get radius OrbitEllipse moonEllipse = moon.gameObject.GetComponent <OrbitEllipse>(); float a; if (moonEllipse != null) { a = moonEllipse.a_scaled; } else { OrbitUniversal orbitU = moon.GetComponent <OrbitUniversal>(); if (orbitU != null) { a = (float)orbitU.GetApogee(); } else { Debug.LogWarning("Could not get moon orbit size"); return(float.NaN); } } // mass scaling will cancel in this ratio return(Mathf.Pow(moon.mass / planet.mass, 0.4f) * a); }
// Create an NBody and check it's mass public void CirclePrediction() { const float mass = 1000f; GameObject star = TestSetupUtils.CreateNBody(mass, new Vector3(0, 0, 0)); NBody starNbody = star.GetComponent <NBody>(); const float orbitRadius = 10f; GameObject planet = TestSetupUtils.CreatePlanetInOrbitUniversal(starNbody, 1f, orbitRadius); OrbitUniversal orbitU = planet.GetComponent <OrbitUniversal>(); OrbitPredictor op = TestSetupUtils.AddOrbitPredictor(planet, star); Assert.NotNull(op); double[] p_values = { 10, 100, 1000 }; foreach (double p in p_values) { Debug.LogFormat("#### CirclePrediction p={0}", p); orbitU.p = p; TestSetupUtils.SetupGravityEngine(star, planet); op.TestRunnerSetup(); OrbitUniversal predictedOrbit = op.GetOrbitUniversal(); Assert.NotNull(predictedOrbit); CompareOrbits(orbitU, predictedOrbit, small); } }
/// <summary> /// Set up a KeplerSeqeunce to do the three phases of the transfer as Kepler mode conics. /// /// Add all the ghost orbits with the required times /// </summary> /// <param name="transferTime"></param> private void TransferOnRails() { // the ship needs to have a KeplerSequence KeplerSequence kseq = spaceship.GetComponent <KeplerSequence>(); if (kseq == null) { Debug.LogError("Could not find a KeplerSequence on " + spaceship.name); return; } // Ellipse 1: shipPos/shipvel already phased by the caller. double t_start = ge.GetPhysicalTime(); double t_toSoi = timeHohmann * tflightFactor; KeplerSequence.ElementStarted noCallback = null; Vector3d r0 = new Vector3d(); Vector3d v0 = new Vector3d(); double time0 = 0; ghostShipOrbit[TO_MOON].GetRVT(ref r0, ref v0, ref time0); kseq.AppendElementRVT(r0, v0, t_start, true, spaceship, planet, noCallback); // Hyperbola: start at t + transferTime // Need to add wrt to ghostMoon (relative=true), then for actual Kepler motion want it around moon ghostShipOrbit[SOI_HYPER].GetRVT(ref r0, ref v0, ref time0); OrbitUniversal hyperObit = kseq.AppendElementRVT(r0, v0, t_start + t_toSoi, true, spaceship, ghostMoon[MOON_SOI_ENTER], EnterMoonSoi); hyperObit.centerNbody = moonBody; // Ellipse 2: ghostShipOrbit[EXIT_SOI].GetRVT(ref r0, ref v0, ref time0); kseq.AppendElementRVT(r0, v0, t_soiExit, true, spaceship, planet, ExitMoonSoi); }
private void TestRV(OrbitData od, GameObject planet, NBody starNbody, float orbitRadius) { GameObject testPlanet = TestSetupUtils.CreatePlanetInOrbitUniversal(starNbody, 1f, orbitRadius); OrbitUniversal orbitU = testPlanet.GetComponent <OrbitUniversal>(); // Run init explicitly to update transform details orbitU.InitFromOrbitData(od, 0); // Awkward but previously could not add a new object to GE when it is stopped, so re-add all three // Leave as is, since it works! GravityEngine ge = GravityEngine.Instance(); ge.Clear(); ge.AddBody(starNbody.gameObject); ge.AddBody(planet); ge.AddBody(testPlanet); ge.Setup(); ge.LogDump(); Vector3 r_od = ge.GetPhysicsPosition(testPlanet.GetComponent <NBody>()); Vector3 v_od = ge.GetVelocity(testPlanet); Vector3 r_i = ge.GetPhysicsPosition(planet.GetComponent <NBody>()); Vector3 v_i = ge.GetVelocity(planet); Debug.Log(" r_i=" + r_i + " r_od=" + r_od + " delta=" + Vector3.Distance(r_i, r_od)); Debug.Log(" v_i=" + v_i + " v_od=" + v_od + " delta=" + Vector3.Distance(v_i, v_od)); Assert.IsTrue(GEUnit.FloatEqual(Vector3.Distance(r_i, r_od), 0f, 1E-2)); Assert.IsTrue(GEUnit.FloatEqual(Vector3.Distance(v_i, v_od), 0f, 1E-2)); }
public void PositionForRadius() { const float mass = 1000f; GameObject star = TestSetupUtils.CreateNBody(mass, new Vector3(0, 0, 0)); NBody starNbody = star.GetComponent <NBody>(); const float orbitRadius = 10f; GameObject planet = TestSetupUtils.CreatePlanetInOrbitUniversal(starNbody, 1f, orbitRadius); OrbitUniversal orbitU = planet.GetComponent <OrbitUniversal>(); orbitU.inclination = 5; orbitU.SetMajorAxisInspector(orbitRadius); float r = 10.0f; float[] eccValues = { 0f, 0.1f, 0.9f, 1.1f }; foreach (float ecc in eccValues) { Debug.LogFormat("======= ecc={0} =======", ecc); orbitU.eccentricity = ecc; orbitU.SetMajorAxisInspector(orbitRadius); // updates p TestSetupUtils.SetupGravityEngine(star, planet); Vector3[] positions = orbitU.GetPositionsForRadius(r, new Vector3(0, 0, 0)); Debug.LogFormat("pos[0]={0} pos[1]={1}", positions[0], positions[1]); foreach (Vector3 p in positions) { Debug.LogFormat("Position error={0}", Mathf.Abs(p.magnitude - r)); Assert.IsTrue(GEUnit.FloatEqual(p.magnitude, r, 1E-2)); } } }
public void KeplerVsTimeOfFlight() { // Need to make sure TOF < 1 period const float mass = 100f; GameObject star = TestSetupUtils.CreateNBody(mass, new Vector3(0, 0, 0)); NBody starNbody = star.GetComponent <NBody>(); const float orbitRadius = 10f; GameObject planet = TestSetupUtils.CreatePlanetInOrbitUniversal(starNbody, 1f, orbitRadius); OrbitUniversal orbitU = planet.GetComponent <OrbitUniversal>(); // Parabola (ecc=1.0 fails, need to investigate) float[] ecc_values = { 0.0f, 0.1f, 0.5f, 0.9f, 1.2f, 1.5f }; foreach (float ecc in ecc_values) { Debug.LogFormat("======= ecc={0} =======", ecc); orbitU.eccentricity = ecc; orbitU.p = 10f; orbitU.evolveMode = OrbitUniversal.EvolveMode.KEPLERS_EQN; // Evolve to position r1 double time = 5.0; TestSetupUtils.SetupGravityEngine(star, planet); double[] r1 = new double[] { 0, 0, 0 }; // orbitU.PreEvolve(pscale, mscale); // Ugh. Need to do this before call evolve, since it caches the value. Vector3d r0_vec = GravityEngine.Instance().GetPositionDoubleV3(planet.GetComponent <NBody>()); orbitU.Evolve(time, ref r1); Vector3d r1_vec = new Vector3d(ref r1); // check time to r1 double time_test = orbitU.TimeOfFlight(r0_vec, r1_vec); Debug.LogFormat("check r0={0} to r1={1} p ={2} after t={3} TOF => {4}", r0_vec, r1_vec, orbitU.p, time, time_test); Assert.IsTrue(GEUnit.DoubleEqual(time, time_test, 1E-4)); } }
public void OmegaUCircleInclination() { const float mass = 1000f; GameObject star = TestSetupUtils.CreateNBody(mass, new Vector3(0, 0, 0)); NBody starNbody = star.GetComponent <NBody>(); const float orbitRadius = 10f; GameObject planet = TestSetupUtils.CreatePlanetInOrbitUniversal(starNbody, 1f, orbitRadius); OrbitUniversal orbitU = planet.GetComponent <OrbitUniversal>(); orbitU.eccentricity = 0.0f; orbitU.inclination = 5; orbitU.SetMajorAxisInspector(orbitRadius); // Try some values of om float[] omegaValues = { 0f, 30f, 45f, 60f, 90f, 135f, 180f, 210f, 320f }; foreach (float omega in omegaValues) { orbitU.omega_uc = omega; TestSetupUtils.SetupGravityEngine(star, planet); OrbitData od = new OrbitData(); od.SetOrbitForVelocity(planet.GetComponent <NBody>(), star.GetComponent <NBody>()); Debug.Log("Omega = " + omega + " od.omega_lc=" + od.omega_lc + " od:" + od.LogString()); Assert.IsTrue(GEUnit.FloatEqual(omega, od.omega_uc, 0.1)); } }
// Use this for initialization void Start() { ge = GravityEngine.Instance(); x_axis = new Vector3d(1, 0, 0); // mass scaling will cancel in this ratio soiRadius = OrbitUtils.SoiRadius(planet, moonBody); // TODO: allow moon to be OrbitUniversal as well. OrbitUniversal moonOrbit = moonBody.gameObject.GetComponent <OrbitUniversal>(); if (moonOrbit == null) { Debug.LogError("Moon is required to have OrbitUniversal"); } moonRadius = moonOrbit.GetMajorAxis(); shipOrbit = spaceship.GetComponent <OrbitUniversal>(); if (shipOrbit == null) { Debug.LogError("Require that the ship have an OrbitU"); } if (shipOrbit.evolveMode != OrbitUniversal.EvolveMode.KEPLERS_EQN) { Debug.LogError("Controller requires ship on-rails but spaceship is off-rails"); } // assuming circular orbit for ship shipRadius = shipOrbit.GetApogee(); shipOrbitPredictor = spaceship.GetComponentInChildren <OrbitPredictor>(); }
// Use this for initialization void Start() { shipOrbit = spaceshipNBody.GetComponent <OrbitUniversal>(); if (shipOrbit == null) { Debug.LogError("spaceship needs an OrbitUniversal"); } }
/// <summary> /// Do hand off from one center to a new center in the OrbitUniversal class. /// </summary> /// <param name="newObject"></param> /// <param name="oldObject"></param> public void OnNewInfluencer(NBody newObject, NBody oldObject) { if (keplerSeq != null) { orbitU = keplerSeq.GetCurrentOrbit(); } orbitU.SetNewCenter(newObject); if (orbitPredictor != null) { orbitPredictor.SetCenterObject(newObject.gameObject); } }
// Use this for initialization void Start() { soiRenderer = GetComponent <LineRenderer>(); soiRadius = OrbitUtils.SoiRadius(planetBody, moonBody); OrbitUniversal orbitU = moonBody.GetComponent <OrbitUniversal>(); if (orbitU != null) { inclination = (float)orbitU.inclination; } }
/// <summary> /// New center. Update the Kepler depth and any children holding orbit predictors or segments /// </summary> /// <param name="orbitU"></param> private void NewCenter(OrbitUniversal orbitU) { GravityEngine.Instance().UpdateKeplerDepth(nbody, orbitU); foreach (OrbitPredictor op in gameObject.GetComponentsInChildren <OrbitPredictor>()) { op.SetCenterObject(orbitU.centerNbody.gameObject); } foreach (OrbitSegment os in gameObject.GetComponentsInChildren <OrbitSegment>()) { os.SetCenterObject(orbitU.centerNbody.gameObject); } }
// Create a planet in orbit around center object with semi-major axis a public static GameObject CreatePlanetInOrbitUniversal(NBody center, float mass, float a) { // position will be trumped by orbit GameObject planet = CreateNBody(mass, new Vector3(1, 0, 0)); OrbitUniversal orbitU = planet.AddComponent <OrbitUniversal>(); orbitU.centerNbody = center; orbitU.SetNBody(planet.GetComponent <NBody>()); orbitU.SetMajorAxisInspector(a); return(planet); }
private void DoTestForPhase(double fromPhase, double toPhase) { const float mass = 1000f; const bool reverse = false; GameObject star = TestSetupUtils.CreateNBody(mass, new Vector3(0, 0, 0)); NBody starNbody = star.GetComponent <NBody>(); float orbitRadius = 20f; GameObject planet = TestSetupUtils.CreatePlanetInOrbitUniversal(starNbody, 0f, orbitRadius); OrbitUniversal orbitU = planet.GetComponent <OrbitUniversal>(); orbitU.phase = fromPhase; orbitU.SetMajorAxisInspector(orbitRadius); orbitRadius = 30.0f; GameObject planet2 = TestSetupUtils.CreatePlanetInOrbitUniversal(starNbody, 0f, orbitRadius); OrbitUniversal orbitU2 = planet2.GetComponent <OrbitUniversal>(); orbitU2.phase = toPhase; orbitU2.SetMajorAxisInspector(orbitRadius); GravityEngine.Instance().UnitTestAwake(); GravityEngine.Instance().AddBody(star); GravityEngine.Instance().AddBody(planet); GravityEngine.Instance().AddBody(planet2); GravityEngine.Instance().Setup(); Debug.Log("Find transfers"); OrbitData fromOrbit = new OrbitData(orbitU); OrbitData toOrbit = new OrbitData(orbitU2); LambertUniversal lambertU = new LambertUniversal(fromOrbit, toOrbit, true); Assert.AreNotEqual(lambertU, null); double time = 0.8f * lambertU.GetTMin(); lambertU.ComputeXfer(reverse, false, 0, time); LambertBattin lambertB = new LambertBattin(fromOrbit, toOrbit); int error = lambertB.ComputeXfer(reverse, false, 0, time); Assert.AreEqual(error, 0); Assert.AreNotEqual(lambertB, null); Assert.AreNotEqual(lambertB.GetTransferVelocity(), null); Debug.LogFormat("initial velocity {0} vs {1}", lambertU.GetTransferVelocity(), lambertB.GetTransferVelocity()); Debug.LogFormat("initial velocity mag {0} vs {1}", lambertU.GetTransferVelocity().magnitude, lambertB.GetTransferVelocity().magnitude); Debug.LogFormat("final velocity {0} vs {1}", lambertU.GetFinalVelocity(), lambertB.GetFinalVelocity()); Debug.LogFormat("final velocity mag {0} vs {1}", lambertU.GetFinalVelocity().magnitude, lambertB.GetFinalVelocity().magnitude); // best can do for 180 degree case is E-2 accuracy on the magnitude. Not sure why...seems too big Assert.IsTrue(GEUnit.DoubleEqual(lambertU.GetTransferVelocity().magnitude, lambertB.GetTransferVelocity().magnitude, 1E-2)); }
/// <summary> /// Construct an orbit data routine from an existing orbit universal by copying the orbital elements /// </summary> /// <param name="orbitU"></param> public OrbitData(OrbitUniversal orbitU) { a = (float)orbitU.GetMajorAxis(); omega_lc = (float)orbitU.omega_lc; omega_uc = (float)orbitU.omega_uc; inclination = (float)orbitU.inclination; ecc = (float)orbitU.eccentricity; phase = (float)orbitU.phase; nbody = orbitU.GetNBody(); centralMass = orbitU.centerNbody; mu = GravityEngine.Instance().GetPhysicsMass(centralMass); period = CalcPeriod(); }
/// <summary> /// SetOrbit /// Determine orbit params from an attached orbit component (if Kepler) otherwise use the velocity to /// determine the orbit /// </summary> /// <param name="forNbody"></param> /// <param name="aroundNBody"></param> public void SetOrbit(NBody forNbody, NBody aroundNBody) { nbody = forNbody; centralMass = aroundNBody; // is this a Kepler body if (nbody.engineRef.fixedBody != null) { OrbitEllipse orbitEllipse = nbody.GetComponent <OrbitEllipse>(); if (orbitEllipse != null) { ecc = orbitEllipse.ecc; a = orbitEllipse.a * GravityEngine.Instance().GetLengthScale(); omega_lc = orbitEllipse.omega_lc; omega_uc = orbitEllipse.omega_uc; inclination = orbitEllipse.inclination; mu = GravityEngine.Instance().GetPhysicsMass(aroundNBody); period = CalcPeriod(); // TODO: tau phase = orbitEllipse.phase; return; } OrbitUniversal orbitU = nbody.GetComponent <OrbitUniversal>(); if (orbitU != null) { ecc = (float)orbitU.eccentricity; // Might need to make a > 0 for hyperbola since OrbitData got this wrong?? a = (float)orbitU.p / (1 - ecc * ecc); omega_lc = (float)orbitU.omega_lc; omega_uc = (float)orbitU.omega_uc; inclination = (float)orbitU.inclination; mu = GravityEngine.Instance().GetPhysicsMass(aroundNBody); period = CalcPeriod(); // TODO: tau phase = (float)orbitU.phase; return; } OrbitHyper orbitHyper = nbody.GetComponent <OrbitHyper>(); if (orbitHyper != null) { ecc = orbitHyper.ecc; perihelion = orbitHyper.perihelion * GravityEngine.Instance().GetLengthScale(); omega_lc = orbitHyper.omega_lc; omega_uc = orbitHyper.omega_uc; inclination = orbitHyper.inclination; // need phase, tau, period return; } } SetOrbitForVelocity(forNbody, aroundNBody); }
// Use this for initialization void Start() { ge = GravityEngine.Instance(); shipAngle = shipAngleDeg * Mathf.Deg2Rad; soiAngle = soiAngleDeg * Mathf.Deg2Rad; // disable maneuver predictor until things settle (can get Invalid local AABB otherwise) SetOrbitDisplays(false); // mass scaling will cancel in this ratio soiRadius = OrbitUtils.SoiRadius(planet, moonBody); toMoonOrbit.hyperDisplayRadius = soiRadius; // TODO: allow moon to be OrbitUniversal as well. OrbitEllipse moonEllipse = moonBody.gameObject.GetComponent <OrbitEllipse>(); moonRadius = moonEllipse.a_scaled; targetPoint = new Vector3d(moonRadius, soiRadius, 0); float inclination = 0; OrbitEllipse shipEllipse = spaceship.gameObject.GetComponent <OrbitEllipse>(); if (shipEllipse != null) { shipRadius = shipEllipse.a_scaled; inclination = shipEllipse.inclination; } else { OrbitUniversal orbitU = spaceship.GetComponent <OrbitUniversal>(); if (orbitU != null) { // assuming circular orbit shipRadius = (float)orbitU.GetApogee(); inclination = (float)orbitU.inclination; } } // check moon and ship orbit are co-planar if (Mathf.Abs(inclination - moonEllipse.inclination) > 1E-3) { Debug.LogWarning("Ship inclination and moon inclination are not equal."); } startPoint = new Vector3d(0, -shipRadius, 0); UpdateSoiPosition(); UpdateStartPosition(); }
void Start() { // calculate positions for the LineRenderer (cannot assume Editor script has been invoked to do this) GameObject parent = transform.parent.gameObject; if (parent != null) { EllipseBase ellipseBase = parent.GetComponent <EllipseBase>(); if (ellipseBase != null) { centerNBody = ellipseBase.centerObject.GetComponent <NBody>(); orbitP = ellipseBase; } else { OrbitUniversal orbitU = parent.GetComponent <OrbitUniversal>(); if (orbitU != null) { centerNBody = orbitU.GetCenterNBody(); orbitP = orbitU; } else { OrbitHyper orbitHyper = parent.GetComponent <OrbitHyper>(); if (orbitHyper != null) { centerNBody = orbitHyper.centerObject.GetComponent <NBody>(); orbitP = orbitHyper; } else { Debug.LogWarning("Parent object must have OrbitEllipse or OrbitHyper - cannot compute positions for line"); } } } } else { Debug.LogWarning("No parent object - cannot compute positions for line"); } if (centerNBody == null) { Debug.LogError("Parent must have an NBody"); } lineR = GetComponent <LineRenderer>(); lineR.positionCount = numPoints; }
/// <summary> /// Determine if and how many objects are orbital parents. /// e.g. Sun = 0, planet=1, moon=2 /// </summary> public void CalcOrbitDepth() { GameObject go = gameObject; do { OrbitEllipse ellipse = go.GetComponent <OrbitEllipse>(); if (ellipse != null) { go = ellipse.centerObject; orbitDepth++; continue; } OrbitUniversal orbitU = go.GetComponent <OrbitUniversal>(); if (orbitU != null) { go = orbitU.centerNbody.gameObject; orbitDepth++; continue; } OrbitHyper hyper = go.GetComponent <OrbitHyper>(); if (hyper != null) { go = hyper.centerObject; orbitDepth++; continue; } if (go.transform.parent != null) { BinaryPair bp = go.transform.parent.gameObject.GetComponent <BinaryPair>(); if (bp != null) { go = bp.gameObject; orbitDepth++; continue; } // If parent has an NBody, then it's an orbital parent, since need to inherit its velocity NBody nbody_parent = go.transform.parent.gameObject.GetComponent <NBody>(); if (nbody_parent != null) { go = nbody_parent.gameObject; orbitDepth++; continue; } } go = null; } while (go != null); }