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> /// Set up a KeplerSeqeunce to do the three phases of the transfer as Kepler mode conics. /// /// Leave the existing ship orbit as the first /// </summary> /// <param name="transferTime"></param> private void TransferOnRails(double transferTime, Vector3 shipPos, Vector3 shipVel, float moonOmega) { // 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; } float moonPhaseDeg = moonOmega * (float)transferTime * Mathf.Rad2Deg; Quaternion moonPhaseRot = Quaternion.AngleAxis(moonPhaseDeg, Vector3.forward); // Ellipse 1: shipPos/shipvel already phased by the caller. double t = ge.GetPhysicalTime(); KeplerSequence.ElementStarted noCallback = null; kseq.AppendElementRVT(new Vector3d(shipPos), new Vector3d(shipVel), t, false, spaceship, planet, noCallback); // Hyperbola: start at t + transferTime // have targetPoint and final velocity from LambertTransfer. Need to make these wrt moon at this time // targetPoint is w.r.t current moon position, but need to rotate around SOI by amount moon will shift // as ship transits to moon Vector3 targetPos = targetPoint.ToVector3(); Vector3 moonPosAtSoi = moonPhaseRot * ge.GetPhysicsPosition(moonBody); Vector3 moonVelAtSoi = moonPhaseRot * ge.GetVelocity(moonBody); // get the relative positions (i.e. as if moon at the origin with v=0) Vector3 adjustedTarget = moonPhaseRot * targetPos - moonPosAtSoi; Vector3 adjustedVel = moonPhaseRot * lambertU.GetFinalVelocity() - moonVelAtSoi; // Create moon hyperbola at the moon position after flight to moon. This means the init cannot make reference // to the CURRENT moon position. Vector3d soiEnterR = new Vector3d(adjustedTarget); Vector3d soiEnterV = new Vector3d(adjustedVel); OrbitUniversal hyperOrbit = kseq.AppendElementRVT(soiEnterR, soiEnterV, t + transferTime, true, spaceship, moonBody, EnterMoonSoi); // Find the hyperbola exit SOI position/vel OrbitUtils.OrbitElements oe = OrbitUtils.RVtoCOE(soiEnterR, soiEnterV, moonBody, true); Vector3d soiExitR = new Vector3d(); Vector3d soiExitV = new Vector3d(); Debug.Log("oe=" + oe); // Gives position and velocity in relative position OrbitUtils.COEtoRVMirror(oe, moonBody, ref soiExitR, ref soiExitV, true); // Determine hyperbola transit time to the soiExit position double hyperTOF = hyperOrbit.TimeOfFlight(soiEnterR, soiExitR); //Debug.LogFormat("Hyper TOF={0} r0={1} r1={2} p={3}", hyperTOF, adjustedTarget, soiExitR, // hyperOrbit.p); // Ellipse 2: // Adjust phase to allow for moon travel during hyperbola transit // Need to set position and vel relative to the planet using position relative to moon at 0 moonPhaseDeg = moonOmega * (float)hyperTOF * Mathf.Rad2Deg; Quaternion moonHyperRot = Quaternion.AngleAxis(moonPhaseDeg, Vector3.forward); Vector3 moonAtExit = moonHyperRot * moonPosAtSoi; Vector3 moonVelAtExit = moonHyperRot * moonVelAtSoi; Vector3 soiExitwrtPlanet = soiExitR.ToVector3() + moonAtExit; // soiexitV is relative to moon at (0,0,0) BUT frame of hyperbola does not rotate Vector3 soiExitVelwrtPlanet = moonHyperRot * soiExitV.ToVector3() + moonVelAtExit; Debug.LogFormat("Ellipse2: soiExitV={0} moonV={1} net={2}", soiExitV, moonVelAtExit, soiExitVelwrtPlanet); kseq.AppendElementRVT(new Vector3d(soiExitwrtPlanet), new Vector3d(soiExitVelwrtPlanet), t + transferTime + hyperTOF, true, spaceship, planet, ExitMoonSoi); 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); }