private void ComputeTransfer() { Vector3d r_from = GravityEngine.Instance().GetPositionDoubleV3(spaceship); Vector3d r_to = new Vector3d(targetPoint.transform.position); OrbitData shipOrbit = new OrbitData(); shipOrbit.SetOrbitForVelocity(spaceship, centralMass); // compute the min energy path (this will be in the short path direction) lambertU = new LambertUniversal(shipOrbit, r_from, r_to, shortPath); // apply any time of flight change double t_flight = tflightFactor * lambertU.GetTMin(); bool reverse = !shortPath; const bool df = false; const int nrev = 0; int error = lambertU.ComputeXfer(reverse, df, nrev, t_flight); if (error != 0) { Debug.LogWarning("Lambert failed to find solution."); maneuverSegment.gameObject.SetActive(false); return; } Vector3 dv = lambertU.GetTransferVelocity() - GravityEngine.Instance().GetVelocity(spaceship); dvText.text = string.Format("dV = {0:00.00} Time={1:00.00}", dv.magnitude, t_flight); maneuverOrbitPredictor.SetVelocity(lambertU.GetTransferVelocity()); maneuverSegment.gameObject.SetActive(true); maneuverSegment.SetDestination(r_to.ToVector3()); maneuverSegment.SetVelocity(lambertU.GetTransferVelocity()); }
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)); }
private void ComputeTransfer() { shipData = new OrbitData(); shipData.centralMass = starNBody; shipData.SetOrbitForVelocity(spaceshipNBody, starNBody); targetData = new OrbitData(targetEllipses[selectedEllipse].orbitData); targetData.phase = targetEllipses[selectedEllipse].manueverPhase; // compute the min energy path (this will be in the short path direction) lambertU = new LambertUniversal(shipData, targetData, shortPath); // apply any time of flight change transferTime = tflightFactor * lambertU.GetTMin(); bool reverse = !shortPath; // recompute with updated time const bool df = false; const int nrev = 0; int error = lambertU.ComputeXfer(reverse, df, nrev, transferTime); if (error != 0) { Debug.LogWarning("Lambert failed to find solution."); maneuverSegment.gameObject.SetActive(false); return; } Vector3 vel = lambertU.GetTransferVelocity(); maneuverOrbitPredictor.SetVelocity(vel); maneuverSegment.SetVelocity(vel); maneuverOrbitPredictor.gameObject.SetActive(true); maneuverSegment.gameObject.SetActive(true); }
//============================================================================================ // Console commands: If there is a GEConsole in the scene, these commands will be available //============================================================================================ // In-class console method // Quick and Dirty implementation for testing LambertUniversal code. private string LambertUniversal(float time) { OrbitData shipData = new OrbitData(); shipData.SetOrbitForVelocity(spaceshipNBody, starNBody); OrbitData targetData = targetEllipses[selectedEllipse].orbitData; targetData.phase = targetEllipses[selectedEllipse].manueverPhase; // get time and try universal LambertUniversal lu = new LambertUniversal(shipData, targetData, true); const bool reverse = false; const bool df = false; const int nrev = 0; int error = lu.ComputeXfer(reverse, df, nrev, time); if (error != 0) { return(string.Format("Error: LambertUniversal rc=" + error)); } spaceshipNBody.vel_phys = lu.GetTransferVelocity(); return(string.Format("time={0} univ={1}", time, lu.GetTransferVelocity())); }
// Update is called once per frame void Update() { if (!GravityEngine.Instance().IsSetup()) { return; } // Awkward - if allow maneuverOrbit active at the start get a pair of Invalid AABB exceptions // then it settles down. Do this as a work around - but look for a better fix! if (!maneuverOrbitPredictor.gameObject.activeInHierarchy) { maneuverOrbitPredictor.gameObject.SetActive(true); maneuverSegment.gameObject.SetActive(true); } MoveTarget(); if (Input.GetKeyDown(KeyCode.Space)) { // toggle evolution GravityEngine.Instance().SetEvolve(!GravityEngine.Instance().GetEvolve()); } else if (Input.GetKeyDown(KeyCode.M)) { // perform the maneuver // clobber the existing ship velocity and do the adjustment directly GravityEngine.Instance().SetVelocity(spaceship, lambertU.GetTransferVelocity()); } else if (Input.GetKeyDown(KeyCode.F)) { // flip shortPath toggle shortPath = !shortPath; maneuverSegment.shortPath = shortPath; } AdjustTimeOfFlight(); // Recompute every frame, since in general the ship is moving ComputeTransfer(); if ((maneuverRenderer != null) && (lambertU != null)) { maneuverRenderer.ShowManeuvers(lambertU.GetManeuvers()); } }
private void ExecuteTransfer() { // Need to account for phasing, rotate ship forward to correct launch point and // rotate TLI vector. (This assumes circular orbit in the XY plane with the planet at the origin!) // Should set as a maneuver, but just jump there for demonstration code double transferTime = tflightFactor * lambertU.GetTMin(); float moonOmega = (float)System.Math.Sqrt(ge.GetMass(planet)) / Mathf.Sqrt(moonRadius * moonRadius * moonRadius); float shipThetaDeg = (float)(transferTime * moonOmega) * Mathf.Rad2Deg; Debug.LogFormat("t={0} theta={1} deg. omega={2} rad", transferTime, shipThetaDeg, moonOmega); // Inclination support. Recompute the transfer using inclination // @TODO: HACK XY only Vector3 shipPos = ge.GetPhysicsPosition(spaceship); Vector3 shipPosPhased = Quaternion.AngleAxis(shipThetaDeg, Vector3.forward) * shipPos; Vector3 shipVelPhased = Quaternion.AngleAxis(shipThetaDeg, Vector3.forward) * lambertU.GetTransferVelocity(); if (onRails) { TransferOnRails(transferTime, shipPosPhased, shipVelPhased, moonOmega); } else { Debug.LogFormat("tli NBody mode r={0} v={1}", shipPosPhased, shipVelPhased); ge.UpdatePositionAndVelocity(spaceship, shipPosPhased, shipVelPhased); } // remove placeholder ships/orbit visualizers ge.RemoveBody(shipExitSOI.gameObject); shipExitSOI.gameObject.SetActive(false); ge.RemoveBody(shipEnterSOI.gameObject); shipEnterSOI.gameObject.SetActive(false); SetOrbitDisplays(false); ge.SetEvolve(true); running = true; }
/// <summary> /// Computes the transfer with the moon on the +X axis without accounting for the moon motion during /// transit. (That is accounted for in the ExecuteTransfer routine). /// /// This allows a co-rotating visualization of the orbit. /// </summary> /// <returns></returns> private Vector3 ComputeTransfer() { OrbitData shipOrbit = new OrbitData(); shipOrbit.SetOrbitForVelocity(spaceship, planet); // compute the min energy path (this will be in the short path direction) lambertU = new LambertUniversal(shipOrbit, startPoint, targetPoint, shortPath); // apply any time of flight change double t_flight = tflightFactor * lambertU.GetTMin(); bool reverse = !shortPath; const bool df = false; const int nrev = 0; int error = lambertU.ComputeXfer(reverse, df, nrev, t_flight); if (error != 0) { Debug.LogWarning("Lambert failed to find solution."); aroundMoonSegment.gameObject.SetActive(false); return(Vector3.zero); } // Check Lambert is going in the correct direction Vector3 shipOrbitAxis = Vector3.Cross(ge.GetVelocity(spaceship), ge.GetPhysicsPosition(spaceship)).normalized; Vector3 tliOrbitAxis = Vector3.Cross(lambertU.GetTransferVelocity(), startPoint.ToVector3()); if (Vector3.Dot(shipOrbitAxis, tliOrbitAxis) < 0) { error = lambertU.ComputeXfer(!reverse, df, nrev, t_flight); if (error != 0) { Debug.LogWarning("Lambert failed to find solution for reverse path. error=" + error); return(Vector3.zero); } } Vector3 tliVelocity = lambertU.GetTransferVelocity(); toMoonOrbit.SetVelocity(tliVelocity); toMoonSegment.SetVelocity(tliVelocity); aroundMoonSegment.gameObject.SetActive(true); // Set velocity for orbit around moon Vector3 soiEnterVel = lambertU.GetFinalVelocity(); aroundMoonSegment.SetVelocity(soiEnterVel); // update shipEnterSOI object ge.UpdatePositionAndVelocity(shipEnterSOI, targetPoint.ToVector3(), soiEnterVel); // Find the orbit around the moon. By using the mirror position we're assuming it's // a hyperbola (since there is no course correction at SOI this is true). // (Moon is in correct position for these calcs so can use world positions, relativePos=false) Vector3d soiEnterV = new Vector3d(lambertU.GetFinalVelocity()); OrbitUtils.OrbitElements oe = OrbitUtils.RVtoCOE(targetPoint, soiEnterV, moonBody, false); Vector3d soiExitR = new Vector3d(); Vector3d soiExitV = new Vector3d(); OrbitUtils.COEtoRVMirror(oe, moonBody, ref soiExitR, ref soiExitV, false); // Set position and vel for exit ship, so exit orbit predictor can run. Moon offset/vel already added. ge.SetPositionDoubleV3(shipExitSOI, soiExitR); ge.SetVelocityDoubleV3(shipExitSOI, soiExitV); aroundMoonSegment.UpdateOrbit(); return(tliVelocity); }