/// <summary> /// Calculates the velocities of this vessel at some future universal timestamp, /// taking into account all currently predicted SOI transition patches, and also /// assuming that all the planned maneuver nodes will actually be executed precisely /// as planned. Note that this cannot "see" into the future any farther than the /// KSP orbit patches setting allows for. /// </summary> /// <param name="timeStamp">The time to predict for. Although the intention is to /// predict for a future time, it could be used to predict for a past time.</param> /// <returns>The orbit/surface velocity pair as a user-readable Vector in raw rotation coordinates.</returns> override public OrbitableVelocity GetVelocitiesAtUT(TimeSpan timeStamp) { string blockingTech; if (!Career.CanMakeNodes(out blockingTech)) { throw new KOSLowTechException("use VELOCITYAT on a vessel", blockingTech); } double desiredUT = timeStamp.ToUnixStyleTime(); Orbit patch = GetOrbitAtUT(desiredUT); Vector3d orbVel = patch.getOrbitalVelocityAtUT(desiredUT); // This is an ugly workaround to fix what is probably a bug in KSP's API: // If looking at a future orbit patch around a child body of the current body, then // the various get{Thingy}AtUT() methods return numbers calculated incorrectly as // if the child body was going to remain stationary where it is now, rather than // taking into account where it will be later when the intercept happens. // This corrects for that case: if (Utils.BodyOrbitsBody(patch.referenceBody, Vessel.orbit.referenceBody)) { Vector3d futureBodyVel = patch.referenceBody.orbit.getOrbitalVelocityAtUT(desiredUT); orbVel = orbVel + futureBodyVel; } // For some weird reason orbital velocities are returned by the KSP API // with Y and Z swapped, so swap them back: orbVel = new Vector3d(orbVel.x, orbVel.z, orbVel.y); CelestialBody parent = patch.referenceBody; Vector surfVel; if (parent != null) { Vector3d pos = GetPositionAtUT(timeStamp); surfVel = new Vector(orbVel - parent.getRFrmVel(pos + Shared.Vessel.findWorldCenterOfMass())); } else { surfVel = new Vector(orbVel.x, orbVel.y, orbVel.z); } return(new OrbitableVelocity(new Vector(orbVel), surfVel)); }
private ListValue BuildPatchList() { var list = new ListValue(); var orb = Orbit; int index = 0; int highestAllowedIndex = Career.PatchLimit(); while (index <= highestAllowedIndex) { if (orb == null || (!orb.activePatch)) { break; } list.Add(new OrbitInfo(orb, Shared)); orb = orb.nextPatch; ++index; } return(list); }
public void Remove() { if (nodeRef == null) { return; } string careerReason; if (!Career.CanMakeNodes(out careerReason)) { throw new KOSLowTechException("use maneuver nodes", careerReason); } nodeLookup.Remove(nodeRef); vesselRef.patchedConicSolver.RemoveManeuverNode(nodeRef); nodeRef = null; vesselRef = null; }
public void AddToVessel(Vessel v) { if (nodeRef != null) { throw new Exception("Node has already been added"); } string careerReason; if (!Career.CanMakeNodes(out careerReason)) { throw new KOSLowTechException("use maneuver nodes", careerReason); } vesselRef = v; nodeRef = v.patchedConicSolver.AddManeuverNode(time); UpdateNodeDeltaV(); v.patchedConicSolver.UpdateFlightPlan(); nodeLookup.Add(nodeRef, this); }
public override void Execute(SharedObjects shared) { AssertArgBottomAndConsume(shared); // no args ReturnValue = new Career(); }