void FixedUpdate() { // Better performance with bulk set of positions in LR if (ge.trajectoryPrediction && (points != null)) { float currentTime = ge.GetPhysicalTime(); // remove any points older than current time while ((points.Count > 0) && (points[0].worldTime < currentTime)) { points.RemoveAt(0); } // add/remove a time marker? if (timeMarkerPrefab != null) { // remove any old time markers while ((timeMarks.Count > 0) && (timeMarks[0].time < currentTime)) { Destroy(timeMarks[0].marker); if (timeMarks[0].textObject != null) { Destroy(timeMarks[0].textObject); } timeMarks.RemoveAt(0); } } UpdateLineRenderer(); } }
/// <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); }
// Scaling: // Setting the size of the ellipse is done via the ellipse base "a". This is // entered by the user in the units selected in the GE units chooser. Additionaly the // GE inspector may indicate a Unity Units per [km|AU] and this needs to be taken into account // in the Gizmo that draws the orbit. // /// <summary> /// Inits the N body position and velocity based on the ellipse parameters and the /// position and velocity of the parent. /// </summary> /// <param name="physicalScale">Physical scale.</param> public void InitNBody(float physicalScale, float massScale) { base.Init(); float a_phy = a_scaled / physicalScale; if (nbody == null) { nbody = GetComponent <NBody>(); } // Phase is TRUE anomoly f float f = phase * Mathf.Deg2Rad; // Murray and Dermot // (2.26) // This should really be (M+m), but assume m << M // (massScale is added in at the GE level) float n = Mathf.Sqrt((float)(centerNbody.mass * massScale) / (a_phy * a_phy * a_phy)); // (2.36) float denom = Mathf.Sqrt(1f - ecc * ecc); float xdot = -1f * n * a_phy * Mathf.Sin(f) / denom; float ydot = n * a_phy * (ecc + Mathf.Cos(f)) / denom; // Init functions are called in the engine by SetupOneBody and calls of parent vs children/grandchildren etc. // can be in arbitrary order. A child will need info from parent for position and velocity. Ensure parent // has inited. Init may get called more than once. centerNbody.InitPosition(GravityEngine.Instance()); Vector3 v_xy = new Vector3(xdot, ydot, 0); // if we're evolving, get the latest velocity if (centerNbody.engineRef != null) { centerNbody.UpdateVelocity(); } Vector3 vphy = ellipse_orientation * v_xy + centerNbody.vel_phys; nbody.vel_phys = vphy; SetInitialPosition(nbody); if (evolveMode == evolveType.KEPLERS_EQN) { if (Application.isPlaying) { // Need to force an evolve to update position and velocity so that // dependent objects get the correct values. GravityEngine ge = GravityEngine.Instance(); double[] r = new double[] { 0, 0, 0 }; PreEvolve(ge.GetLengthScale(), ge.massScale); Evolve(ge.GetPhysicalTime(), ref r); } else { // if in the editor/DrawGizmos all we care about is position and above clause // causes exceptions, since it asks GE for position/velocity position = nbody.initialPhysPosition; } } }
// Use this for initialization void Start() { GravityEngine ge = GravityEngine.Instance(); time.text = string.Format(time_format, ge.GetPhysicalTime(), ge.GetTimeZoom()); Vector3 pos = ship.initialPos; position.text = string.Format(pos_format, pos.x, pos.y, pos.z); velocity.text = string.Format(vel_format, 0f, 0f, 0f); RocketEngine rocketEngine = ship.GetComponent <RocketEngine>(); if (rocketEngine == null) { Debug.LogError("Need a rocket component"); } fuelText.text = string.Format(fuel_format, rocketEngine.GetFuel(ge.GetPhysicalTime())); attitude.text = string.Format(attitude_format, 0f, 0f, 0f); // assume earth at (0,0,0) initial_altitude = Vector3.Magnitude(ship.transform.position); altitude.text = string.Format(altitude_format, 0f); }
public CircularizeXfer(OrbitData fromOrbit) : base(fromOrbit) { name = "Circularize"; GravityEngine ge = GravityEngine.Instance(); // find velocity vector perpendicular to r for circular orbit Vector3d r_ship = ge.GetPositionDoubleV3(fromOrbit.nbody); Vector3d v_ship = ge.GetVelocityDoubleV3(fromOrbit.nbody); Vector3d r_center = ge.GetPositionDoubleV3(fromOrbit.centralMass); Vector3d v_center = ge.GetVelocityDoubleV3(fromOrbit.centralMass); Vector3d r = r_ship - r_center; // want velocity relative to central mass (it could be moving) Vector3d v = v_ship - v_center; // to get axis of orbit, can take r x v Vector3d axis = Vector3d.Cross(r, v).normalized; // vis visa for circular orbit double mu = GravityEngine.Instance().GetMass(centerBody); double v_mag = Mathd.Sqrt(mu / r.magnitude); // positive v is counter-clockwise Vector3d v_dir = Vector3d.Cross(axis, r).normalized; Vector3d v_circular = v_mag * v_dir; Maneuver m1; m1 = new Maneuver(); m1.nbody = fromOrbit.nbody; m1.mtype = Maneuver.Mtype.vector; m1.velChange = (v_circular - v).ToVector3(); m1.dV = Vector3.Magnitude(m1.velChange); // maneuver positions and info for KeplerSeq conversion and velocity directions Vector3d h_unit = fromOrbit.GetAxis(); m1.physPosition = r_ship; m1.relativePos = r_ship - r_center; m1.relativeVel = v_circular.magnitude * Vector3d.Cross(h_unit, m1.relativePos).normalized; m1.relativeTo = fromOrbit.centralMass; //Debug.LogFormat("v_ship={0} v_center={1} v_c.x={2}", vel_ship, vel_center, v_center[0]); //Debug.Log(string.Format("v_ship={0} v_circular={1} axis={2} v_dir={3} velChange={4}", // vel_ship, v_circular, axis, v_dir, m1.velChange)); m1.worldTime = ge.GetPhysicalTime(); maneuvers.Add(m1); }
// Update is called once per frame void FixedUpdate() { // monitor for engine start (not ideal, but avoids linking to LaunchUI script) if ((timeStarted < 0) && engine.engineOn) { timeStarted = ge.GetPhysicalTime(); float pitch0 = pitchCurve.Evaluate(0); Vector3 localVertical = Vector3.Normalize(ge.GetPhysicsPosition(ship) - ge.GetPhysicsPosition(earth)); lastAttitude = Vector3.Cross(localVertical, Vector3.forward); // forward = (0,0,1) lastAttitude = Quaternion.AngleAxis(pitch0, Vector3.forward) * lastAttitude; } if (timeStarted > 0) { float t = (float)(ge.GetTimeWorldSeconds() - timeStarted) / timeRangePhysical; t = Mathf.Clamp(t, 0f, 1f); // pitch in range 0..90 as curve goes 0..1 float pitch = pitchCurve.Evaluate(t) * 90.0f; // find the local vertical Vector3 localVertical = Vector3.Normalize(ge.GetPhysicsPosition(ship) - ge.GetPhysicsPosition(earth)); // First get local horizontal (this ordering of cross product assumes we want to go East) Vector3 attitude = Vector3.Cross(localVertical, Vector3.forward); // forward = (0,0,1) attitude = Quaternion.AngleAxis(pitch, Vector3.forward) * attitude; engine.SetThrustAxis(-attitude); shipModel.RotateToVector(attitude); // when attitude changes by 1 degree, re-compute trajectories if (Vector3.Angle(attitude, lastAttitude) > 1f) { ge.TrajectoryRestart(); lastAttitude = attitude; } // thrust float thrust = thrustCurve.Evaluate(t); engine.SetThrottlePercent(100f * thrust); } }
// Update is called once per fixed frame by GE public void FixedUpdate() { // need to get physics positions for everything GravityEngine ge = GravityEngine.Instance(); Vector3 shipPos = ge.GetPhysicsPosition(spaceship); Vector3 body1Pos = ge.GetPhysicsPosition(body1); Vector3 body2Pos = ge.GetPhysicsPosition(body2); float D = Vector3.Distance(body1Pos, body2Pos); NBody influencer = lastInfluencer; float d = Vector3.Distance(shipPos, body2Pos); // add a bit of hysteresis if (d < ENTER_DERATE * D * massRatio25) { influencer = body2; } else if (d > D * massRatio25) { influencer = body1; } if (influencer != lastInfluencer) { if (patchChanged != null) { patchChanged.OnNewInfluencer(influencer, lastInfluencer); } #pragma warning disable 162 // disable unreachable code warning if (GravityEngine.DEBUG) { Debug.LogFormat("Influencer changed from {0} to {1} at d={2} t={3}", lastInfluencer, influencer, d, ge.GetPhysicalTime()); } #pragma warning restore 162 lastInfluencer = influencer; } }
/// <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; }
// Update is called once per frame void Update() { timeLast = ge.GetPhysicalTime(); slider.value = timeLast; }
/// <summary> /// Execute the maneuver. Called automatically by Gravity Engine for maneuvers that /// have been added to the GE via AddManeuver(). /// /// Unusual to call this method directly. /// </summary> /// <param name="ge"></param> public void Execute(GravityEngine ge) { Vector3 vel = ge.GetVelocity(nbody); switch (mtype) { case Mtype.vector: vel += velChange; break; case Mtype.scalar: // scalar: adjust existing velocity by dV Vector3 change = Vector3.Normalize(vel) * dV; vel += change; break; case Mtype.circularize: // find velocity vector perpendicular to r for circular orbit // Since we could be mid-integration need to get exact position from GE double[] r_ship = new double[3]; double[] v_ship = new double[3]; ge.GetPositionVelocityScaled(nbody, ref r_ship, ref v_ship); double[] r_center = new double[3]; double[] v_center = new double[3]; ge.GetPositionVelocityScaled(centerBody, ref r_center, ref v_center); Vector3 pos_ship = new Vector3((float)r_ship[0], (float)r_ship[1], (float)r_ship[2]); Vector3 vel_ship = new Vector3((float)v_ship[0], (float)v_ship[1], (float)v_ship[2]); Vector3 pos_center = new Vector3((float)r_center[0], (float)r_center[1], (float)r_center[2]); Vector3 r = pos_ship - pos_center; // to get axis of orbit, can take v x r Vector3 axis = Vector3.Normalize(Vector3.Cross(vel_ship, pos_ship)); // vis visa for circular orbit float mu = nbody.mass * ge.massScale; float v_mag = Mathf.Sqrt(mu / Vector3.Magnitude(r)); // positive v is counter-clockwise Vector3 v_dir = Vector3.Normalize(Vector3.Cross(axis, r)); Vector3 v_circular = v_mag * v_dir; ge.SetVelocity(nbody, v_circular); break; } #pragma warning disable 162 // disable unreachable code warning if (GravityEngine.DEBUG) { Debug.Log("Applied manuever: " + LogString() + " engineRef.index=" + nbody.engineRef.index + " engineRef.bodyType=" + nbody.engineRef.bodyType + " timeError=" + (worldTime - ge.GetPhysicalTime())); Debug.Log("r= " + Vector3.Magnitude(nbody.transform.position)); } #pragma warning restore 162 // enable unreachable code warning ge.SetVelocity(nbody, vel); }