/// <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); }
/// <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> /// 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()); } }
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"); } }
/// <summary> /// Used to determine the initial physics position of an NBody (initialPhysPosition). /// /// Used in two contexts: /// (1) When a body is added to GE (either at setup or when a body is dynamically added at run-time). /// (2) In the editor DrawGizmo calls when the orbit path is being show in a scene that is not running. /// In the case of orbit gizmos the orbit parameters will MOVE the object to the correct position in the /// orbit based on the position calculated here. /// /// If the NBody game object has an INBodyInit component (e.g from an OrbitEllipse) then /// this is used to determine it's position. There is a potential for recursion here, since that /// orbit ellipse may be on a NBody that is in turn positioned by an orbit ellipse e.g. moon/planet/sun. /// /// If the NBody has an engine ref (i.e. GE has taken charge) then update with the position from GE. /// /// </summary> /// <param name="ge"></param> public void InitPosition(GravityEngine ge) { // Not ideal that NBody knows so much about methods to run setup. Be better to delegate this eventually. // check for initial condition setup (e.g. initial conditions for elliptical orbit/binary pair) if (engineRef != null) { initialPhysPosition = ge.GetPhysicsPosition(this); } else { // If there is a Kepler sequence, use that instead of e.g. the first OrbitU INbodyInit initNbody; KeplerSequence keplerSeq = GetComponent <KeplerSequence>(); if (keplerSeq != null) { initNbody = (INbodyInit)keplerSeq; } else { initNbody = gameObject.GetComponent <INbodyInit>(); } if (initNbody != null) { initNbody.InitNBody(ge.physToWorldFactor, ge.massScale); } else { // binary pair if (transform.parent != null) { BinaryPair bp = transform.parent.GetComponent <BinaryPair>(); if (bp != null) { bp.SetupBodies(); return; } } if (ge.units != GravityScaler.Units.DIMENSIONLESS) { // value in scaled systems is taken from the NBody scaled position and not the transform initialPhysPosition = initialPos; } else { // value is taken from the transform object initialPhysPosition = transform.position; } } } }
private void WarnAboutKeplerSeq(OrbitUniversal orbitU) { // when playing warn user if OrbitU attached to NBody is being used or not if (EditorApplication.isPlaying) { KeplerSequence ks = orbitU.GetComponent <KeplerSequence>(); if (ks != null) { if (ks.GetCurrentOrbit() != orbitU) { EditorGUILayout.LabelField("OrbitUniversal is not current orbit in Kepler sequence!", EditorStyles.boldLabel); } } } }
/// <summary> /// Raise a circular orbit by the specified percent /// - only on-rail is implemented /// </summary> /// <param name="percentRaise"></param> private void NewCircularOrbit(float percentRaise) { 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()); } }
public void Awake() { orbitU = GetComponent <OrbitUniversal>(); keplerSeq = GetComponent <KeplerSequence>(); }
/// <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; }
// Use this for initialization void Start() { keplerSeq = shipNbody.GetComponent <KeplerSequence>(); markers = new List <GameObject>(); }
// Use this for initialization void Start() { keplerSeq = shipNbody.GetComponent <KeplerSequence>(); }