Inheritance: MonoBehaviour
Beispiel #1
0
 // Doesn't work, just learning to use github
 /// <summary>
 /// Find the Intersections of two orbits
 /// </summary>
 /// <returns>
 /// 0 for no intersections found, 1 for 1, 2 for 2
 /// True anomaly of intersections in out intersect1 and intersect2
 /// </returns>
 /// <param name='orbit'>
 /// Orbit.
 /// </param>
 /// <param name='tgtorbit'>
 /// Tgtorbit.
 /// </param>
 /// <param name='intersect1'>
 /// Intsect1.
 /// </param>
 /// <param name='intersect2'>
 /// Intsect2.
 /// </param>
 public static int FindIntersectSimple(this Orbit orbit, Orbit tgtorbit, out double intersect1, out double intersect2)
 {
     double anomaly = 0;
     intersect1 = 361;
     intersect2 = 361;
     int div = 50;
     double range = 360;
     double lowest = 1e10;
     int count = 0;
     while (lowest>100) {
         for (int i=0; i<div; i++) {
             double j;
             anomaly += (i / div) * range;
             j = Math.Abs (orbit.f (tgtorbit, anomaly));
             if (i == 0) {
                 lowest = j;
                 intersect1 = anomaly;
             }
             if (j < lowest) {
                 lowest = j;
                 intersect1 = anomaly;
             }
         }
         range = range / 2;
         anomaly = intersect1 - range / 2;
         count++;
         if (count > 30)
             return 2;
     }
     return 0;
 }
  /// <summary>
  /// Calculates position of the orbiting body for given time. It also updates <see cref="CurrentPosition"/> property.
  /// </summary>
  /// <param name="time">time from the creation of the start system (time 0)</param>
  /// <returns>Position as spherical coordinates</returns>
  public static SphericalCoordinates CalculatePosition(float time, Orbit orbitData)
  {
    time = Mathf.Repeat(time, orbitData.Period);
    //mean anomaly
    float n = 2f * Mathf.PI / orbitData.Period;
    float M = n * time;

    //eccentric anomaly
    float deltaMax = Mathf.Pow(10, anomalyPrecision * -1);
    float E = M;
    float error = E - orbitData.Eccentricity * Mathf.Sin(E) - M;
    int i = 0;
    while (Mathf.Abs(error) > deltaMax && i < 5)
    {
      E = E - error / (1f - orbitData.Eccentricity * Mathf.Cos(E));
      error = E - orbitData.Eccentricity * Mathf.Sin(E) - M;
      i++;
    }

    //true anomaly
    var S = Mathf.Sin(E);
    var C = Mathf.Cos(E);
    var fak = Mathf.Sqrt(1f - orbitData.Eccentricity * orbitData.Eccentricity);
    float phi = Mathf.Atan2(fak * S, C - orbitData.Eccentricity);

    //distance
    // float r = MeanDistance * (1 - Eccentricity * Eccentricity) / (1 + Eccentricity * Mathf.Cos(phi));
    float r = orbitData.MeanDistance * (1 - orbitData.Eccentricity * Mathf.Cos(E));
    phi = phi + orbitData.PeriapsisArgumentRadians;
    float elevation = orbitData.InclinationRadians * Mathf.Cos(phi);
    return new SphericalCoordinates(r, phi, elevation);
  }
        public static ManeuverNode PlaceManeuverNode(this Vessel vessel, Orbit patch, Vector3d dV, double UT)
        {
            //placing a maneuver node with bad dV values can really mess up the game, so try to protect against that
            //and log an exception if we get a bad dV vector:
            for (int i = 0; i < 3; i++)
            {
                if (double.IsNaN(dV[i]) || double.IsInfinity(dV[i]))
                {
                    throw new Exception("VesselExtensions.PlaceManeuverNode: bad dV: " + dV);
                }
            }

            if (double.IsNaN(UT) || double.IsInfinity(UT))
            {
                throw new Exception("VesselExtensions.PlaceManeuverNode: bad UT: " + UT);
            }

            //It seems that sometimes the game can freak out if you place a maneuver node in the past, so this
            //protects against that.
            UT = Math.Max(UT, Planetarium.GetUniversalTime());

            //convert a dV in world coordinates into the coordinate system of the maneuver node,
            //which uses (x, y, z) = (radial+, normal-, prograde)
            Vector3d nodeDV = patch.DeltaVToManeuverNodeCoordinates(UT, dV);
            ManeuverNode mn = vessel.patchedConicSolver.AddManeuverNode(UT);
            mn.OnGizmoUpdated(nodeDV, UT);
            return mn;
        }
        public override ManeuverParameters MakeNodeImpl(Orbit o, double universalTime, MechJebModuleTargetController target)
        {
            double UT = timeSelector.ComputeManeuverTime(o, universalTime, target);
            var dV = OrbitalManeuverCalculator.DeltaVToResonantOrbit(o, UT, (double)resonanceNumerator.val / resonanceDenominator.val);

            return new ManeuverParameters(dV, UT);
        }
Beispiel #5
0
        /// <summary>
        /// Orbit foo, this finds the nodes of two orbits
        /// </summary>
        /// <returns>
        /// The true anomaly of the ascending node(descing node is 180degrees off)
        /// </returns>
        /// <param name='orbit'>
        /// Orbit.
        /// </param>
        /// <param name='tgtorbit'>
        /// Target Orbit
        /// </param>
        public static double FindAN(Orbit orbit, Orbit tgtorbit)
        {
            double rad = Math.PI/180;
            double Lan1 = orbit.LAN;
            double inc1 = orbit.inclination;
            double Lan2 = tgtorbit.LAN;
            double inc2 = tgtorbit.inclination;

            //see braeunig.us/space... cross product of two orbital planes gives the node location
            var a = new Vector3d(Math.Sin(inc1*rad)*Math.Cos(Lan1*rad), Math.Sin(inc1*rad)*Math.Sin(Lan1*rad),
                                 Math.Cos(inc1*rad));
            var b = new Vector3d(Math.Sin(inc2*rad)*Math.Cos(Lan2*rad), Math.Sin(inc2*rad)*Math.Sin(Lan2*rad),
                                 Math.Cos(inc2*rad));
            var c = new Vector3d(0, 0, 0);
            c = Vector3d.Cross(a, b);
            var coord = new double[] {0, 0};
            coord = LatLonofVector(c); //get the coordinates lat/lon of the ascending node
            double lat = coord[0];
            double lon = coord[1];

            //go look at the diagrams at braeunig.us/space
            double α = lon - Lan1; //its all greek to me
            if (α < 0) α += 360;
            double λ = Math.Atan(Math.Tan(α*rad)/Math.Cos(inc1*rad))/rad;
            double x = 180 + (λ - orbit.argumentOfPeriapsis);
            if (x > 360) return 360 - x;
            else return x;
        }
		private static void DrawOrbit(Orbit o, CelestialBody referenceBody, Matrix4x4 screenTransform, int numSegments)
		{
			if (!o.activePatch) {
				return;
			}

			double startTA;
			double endTA;
			double now = Planetarium.GetUniversalTime();
			if (o.patchEndTransition != Orbit.PatchTransitionType.FINAL) {
				startTA = o.TrueAnomalyAtUT(o.StartUT);
				endTA = o.TrueAnomalyAtUT(o.EndUT);
				if (endTA < startTA) {
					endTA += 2.0 * Math.PI;
				}
			} else {
				startTA = o.GetUTforTrueAnomaly(0.0, now);
				endTA = startTA + 2.0 * Math.PI;
			}
			double dTheta = (endTA - startTA) / (double)numSegments;
			double theta = startTA;
			double timeAtTA = o.GetUTforTrueAnomaly(theta, now);
			Vector3 lastVertex = screenTransform.MultiplyPoint3x4(o.getRelativePositionFromTrueAnomaly(theta).xzy + (o.referenceBody.getTruePositionAtUT(timeAtTA)) - (referenceBody.getTruePositionAtUT(timeAtTA)));
			for (int i = 0; i < numSegments; ++i) {
				GL.Vertex3(lastVertex.x, lastVertex.y, 0.0f);
				theta += dTheta;
				timeAtTA = o.GetUTforTrueAnomaly(theta, now);

				Vector3 newVertex = screenTransform.MultiplyPoint3x4(o.getRelativePositionFromTrueAnomaly(theta).xzy + (o.referenceBody.getTruePositionAtUT(timeAtTA)) - (referenceBody.getTruePositionAtUT(timeAtTA)));
				GL.Vertex3(newVertex.x, newVertex.y, 0.0f);

				lastVertex = newVertex;
			}
		}
        public static Vector3d DeltaVAndTimeForCheapestCourseCorrection(Orbit o, double UT, Orbit target, CelestialBody targetBody, double finalPeR, out double burnUT)
        {
            Vector3d collisionDV = DeltaVAndTimeForCheapestCourseCorrection(o, UT, target, out burnUT);
            Orbit collisionOrbit = o.PerturbedOrbit(burnUT, collisionDV);
            double collisionUT = collisionOrbit.NextClosestApproachTime(target, burnUT);
            Vector3d collisionPosition = target.SwappedAbsolutePositionAtUT(collisionUT);
            Vector3d collisionRelVel = collisionOrbit.SwappedOrbitalVelocityAtUT(collisionUT) - target.SwappedOrbitalVelocityAtUT(collisionUT);

            double soiEnterUT = collisionUT - targetBody.sphereOfInfluence / collisionRelVel.magnitude;
            Vector3d soiEnterRelVel = collisionOrbit.SwappedOrbitalVelocityAtUT(soiEnterUT) - target.SwappedOrbitalVelocityAtUT(soiEnterUT);

            double E = 0.5 * soiEnterRelVel.sqrMagnitude - targetBody.gravParameter / targetBody.sphereOfInfluence; //total orbital energy on SoI enter
            double finalPeSpeed = Math.Sqrt(2 * (E + targetBody.gravParameter / finalPeR)); //conservation of energy gives the orbital speed at finalPeR.
            double desiredImpactParameter = finalPeR * finalPeSpeed / soiEnterRelVel.magnitude; //conservation of angular momentum gives the required impact parameter

            Vector3d displacementDir = Vector3d.Cross(collisionRelVel, o.SwappedOrbitNormal()).normalized;
            Vector3d interceptTarget = collisionPosition + desiredImpactParameter * displacementDir;

            Vector3d velAfterBurn;
            Vector3d arrivalVel;
            LambertSolver.Solve(o.SwappedRelativePositionAtUT(burnUT), interceptTarget - o.referenceBody.position, collisionUT - burnUT, o.referenceBody, true, out velAfterBurn, out arrivalVel);

            Vector3d deltaV = velAfterBurn - o.SwappedOrbitalVelocityAtUT(burnUT);
            return deltaV;
        }
Beispiel #8
0
 public OrbitInfo(Orbitable orb, SharedObjects sharedObj)
 {
     orbit = orb.Orbit;
     shared = sharedObj;
     name = orb.GetName();
     InitializeSuffixes();
 }
Beispiel #9
0
 public OrbitInfo( Orbit orb, SharedObjects sharedObj )
 {
     shared = sharedObj;
     orbit = orb;
     name = "<unnamed>";
     InitializeSuffixes();
 }
        public override ManeuverParameters MakeNodeImpl(Orbit o, double UT, MechJebModuleTargetController target)
        {
            if (!target.NormalTargetExists)
                throw new OperationException("must select a target for the course correction.");

            Orbit correctionPatch = o;
            while (correctionPatch != null)
            {
                if (correctionPatch.referenceBody == target.TargetOrbit.referenceBody)
                {
                    o = correctionPatch;
                    UT = correctionPatch.StartUT;
                    break;
                }
                correctionPatch = target.core.vessel.GetNextPatch(correctionPatch);
            }

            if (correctionPatch == null || correctionPatch.referenceBody != target.TargetOrbit.referenceBody)
                throw new OperationException("target for course correction must be in the same sphere of influence");

            if (o.NextClosestApproachTime(target.TargetOrbit, UT) < UT + 1 ||
                    o.NextClosestApproachDistance(target.TargetOrbit, UT) > target.TargetOrbit.semiMajorAxis * 0.2)
            {
                errorMessage = "Warning: orbit before course correction doesn't seem to approach target very closely. Planned course correction may be extreme. Recommend plotting an approximate intercept orbit and then plotting a course correction.";
            }

            CelestialBody targetBody = target.Target as CelestialBody;
            Vector3d dV = targetBody != null ?
                OrbitalManeuverCalculator.DeltaVAndTimeForCheapestCourseCorrection(o, UT, target.TargetOrbit, targetBody, targetBody.Radius + courseCorrectFinalPeA, out UT):
                OrbitalManeuverCalculator.DeltaVAndTimeForCheapestCourseCorrection(o, UT, target.TargetOrbit, interceptDistance, out UT);


            return new ManeuverParameters(dV, UT);
        }
        /// <summary>
        /// Find the point on the orbit that includes the initial time where the ejection angle is closest to the suplied one
        /// </summary>
        /// <param name="oObject">Orbit of the vessel/body</param>
        /// <param name="timeInitial">The UT you want to search around for the angle - will search 1/2 an orbit back and 1/2 forward</param>
        /// <param name="numDivisions">Higher thisnumber the more precise the answer - and the longer it will take</param>
        /// <param name="closestAngle">The output of the closest angle the method could find</param>
        /// <param name="targetAngle">The ejection angle we are looking for</param>
        /// <returns></returns>
        internal static double timeOfEjectionAngle(Orbit oObject, double timeInitial, double targetAngle, double numDivisions, out double closestAngle)
        {
            double timeStart = timeInitial - oObject.period/2;
            double periodtoscan = oObject.period;
            
            double closestAngleTime = timeStart;
            double closestAngleValue = Double.MaxValue;
            double minTime = timeStart;
            double maxTime = timeStart + periodtoscan;

            //work out iterations for precision - we only really need to within a second - so how many iterations do we actually need
            //Each iteration gets us 1/10th of the period to scan

            for (int iter = 0; iter < 8; iter++) {
                double dt = (maxTime - minTime) / numDivisions;
                for (int i = 0; i < numDivisions; i++) {
                    double t = minTime + i * dt;
                    double angle = oObject.getEjectionAngleAtUT(t);
                    if (Math.Abs(angle - targetAngle) < closestAngleValue) {
                        closestAngleValue = Math.Abs(angle - targetAngle);
                        closestAngleTime = t;
                    }
                }
                minTime = (closestAngleTime - dt).Clamp(timeStart, timeStart + periodtoscan);
                maxTime = (closestAngleTime + dt).Clamp(timeStart, timeStart + periodtoscan); 
            }

            closestAngle = closestAngleValue + targetAngle;
            return closestAngleTime;
        }
		protected TransferCalculator(
			Orbit o, Orbit target,
			double min_departure_time,
			double max_departure_time,
			double min_transfer_time,
			double max_transfer_time,
			int width,
			int height)
		{
			originOrbit = o;
			destinationOrbit = target;

			origin = new Orbit();
			origin.UpdateFromOrbitAtUT(o, min_departure_time, o.referenceBody);
			destination = new Orbit();
			destination.UpdateFromOrbitAtUT(target, min_departure_time, target.referenceBody);
			maxDurationSamples = height;
			dateSamples = width;
			nextDateIndex = dateSamples;
			this.minDepartureTime = min_departure_time;
			this.maxDepartureTime = max_departure_time;
			this.minTransferTime = min_transfer_time;
			this.maxTransferTime = max_transfer_time;
			computed = new ManeuverParameters[dateSamples, maxDurationSamples];
			pendingJobs = 0;

#if DEBUG
			log = new string[dateSamples, maxDurationSamples];
#endif
		}
Beispiel #13
0
        static void WarpShip(Vessel vessel, Orbit newOrbit)
        {
            if (newOrbit.getRelativePositionAtUT (Planetarium.GetUniversalTime ()).magnitude > newOrbit.referenceBody.sphereOfInfluence)
                throw new ArgumentException ("Destination position was above the sphere of influence");

            vessel.Landed = false;
            vessel.Splashed = false;
            vessel.landedAt = string.Empty;
            var parts = vessel.parts;
            if (parts != null) {
                var clamps = parts.Where (p => p.Modules != null && p.Modules.OfType<LaunchClamp> ().Any ()).ToList ();
                foreach (var clamp in clamps)
                    clamp.Die ();
            }

            try {
                OrbitPhysicsManager.HoldVesselUnpack (60);
            } catch (NullReferenceException) {
            }

            foreach (var v in (FlightGlobals.fetch == null ? (IEnumerable<Vessel>)new[] { vessel } : FlightGlobals.Vessels).Where(v => !v.packed))
                v.GoOnRails ();

            HardsetOrbit (vessel.orbit, newOrbit);

            vessel.orbitDriver.pos = vessel.orbit.pos.xzy;
            vessel.orbitDriver.vel = vessel.orbit.vel;
        }
    /// <summary>
    /// Initializes the script.
    /// </summary>
    void Start()
    {
        // Store the central object original position
        originalCentralBodyPosition = CentralObject.transform.position;

        // Calculate the up vector if not entered
        if (Up == Vector3.zero)
            Up = CentralObject.transform.up;

        orbits = new Orbit[OrbitingObjects.Length];

        // for each orbiting object, calculate the normal vector to its orbital plane
        for (int i=0; i<OrbitingObjects.Length; i++) {

            // Get the normalized direction vector between the two objects
            Vector3 direction = (OrbitingObjects[i].orbitingObject.transform.position - CentralObject.transform.position).normalized;

            // Calculate a perpendicular vector to the orbital plane
            Vector3 normal = Vector3.Cross (direction, Up);

            normal = Vector3.Cross (normal, direction);

            // Add a new Orbit containing all the information needed for the orbit to the array of orbits
            orbits[i] = new Orbit (OrbitingObjects[i].orbitingObject, OrbitingObjects[i].revolutionsPerMinute, normal);
        }
    }
            public VesselData(VesselData vd)
            {
                name = vd.name;
                id = vd.id;
                craftURL = vd.craftURL;
                craftPart = vd.craftPart;
                flagURL = vd.flagURL;
                vesselType = vd.vesselType;
                body = vd.body;
                orbit = vd.orbit;
                latitude = vd.latitude;
                longitude = vd.longitude;
                altitude = vd.altitude;
                height = vd.height;
                orbiting = vd.orbiting;
                owned = vd.owned;
                pqsCity = vd.pqsCity;
                pqsOffset = vd.pqsOffset;
                heading = vd.heading;
                pitch = vd.pitch;
                roll = vd.roll;

                foreach (CrewData cd in vd.crew)
                {
                    crew.Add(new CrewData(cd));
                }
            }
Beispiel #16
0
		public void EllipticSector()
		{
			var o = new Orbit { SemiMajorAxis = 2, SemiMinorAxis = 1, TransformAngle = 0 };
			AssertAreClose(o.S(Math.PI), 0);
			AssertAreClose(o.S(0), Math.PI);
			AssertAreClose(o.S(1, -Math.PI), 2 * Math.PI);
		}
        public override ManeuverParameters MakeNodeImpl(Orbit o, double universalTime, MechJebModuleTargetController target)
        {
            double UT = timeSelector.ComputeManeuverTime(o, universalTime, target);

            if (!target.NormalTargetExists)
            {
                throw new OperationException("must select a target to match planes with.");
            }
            else if (o.referenceBody != target.TargetOrbit.referenceBody)
            {
                throw new OperationException("can only match planes with an object in the same sphere of influence.");
            }
            else if (timeSelector.timeReference == TimeReference.REL_ASCENDING)
            {
                if (!o.AscendingNodeExists(target.TargetOrbit))
                {
                    throw new OperationException("ascending node with target doesn't exist.");
                }
            }
            else
            {
                if (!o.DescendingNodeExists(target.TargetOrbit))
                {
                    throw new OperationException("descending node with target doesn't exist.");
                }
            }

            Vector3d dV = (timeSelector.timeReference == TimeReference.REL_ASCENDING) ?
                OrbitalManeuverCalculator.DeltaVAndTimeToMatchPlanesAscending(o, target.TargetOrbit, UT, out UT):
                OrbitalManeuverCalculator.DeltaVAndTimeToMatchPlanesDescending(o, target.TargetOrbit, UT, out UT);

            return new ManeuverParameters(dV, UT);
        }
        double tauP; //normalized parabolic transfer time

        #endregion Fields

        #region Constructors

        /// <summary>
        /// Initializes a new instance of the <see cref="ThrottleControlledAvionics.LambertSolver"/> class.
        /// </summary>
        /// <param name="orb">Starting orbit.</param>
        /// <param name="destination">Destination radius-vector.</param>
        /// <param name="UT">Starting UT.</param>
        public LambertSolver(Orbit orb, Vector3d destination, double UT)
        {
            orbit = orb;
            body = orbit.referenceBody;
            StartUT = UT;
            mu = body.gravParameter;

            r1 = orb.getRelativePositionAtUT(UT);
            var h  = Vector3d.Cross(r1, destination);
            if(h.sqrMagnitude < 0.01) h = orb.GetOrbitNormal();
            c  = destination-r1;

            cm  = c.magnitude;
            var r1m = r1.magnitude;
            var r2m = destination.magnitude;
            var rrm = r1m+r2m;
            m  = rrm+cm;
            n  = rrm-cm;
            m3 = m*m*m;

            var transfer_angle = Vector3d.Angle(r1, destination)*Mathf.Deg2Rad;
            if(h.z < 0) transfer_angle = Utils.TwoPI-transfer_angle;
            sigma = Math.Sqrt(n/m);
            if(transfer_angle > Math.PI) sigma = -sigma;
            sigma2 = sigma*sigma;
            sigma3 = sigma2*sigma;
            sigma5 = sigma2*sigma3;

            tauP = 2/3.0*(1-sigma3);
            tauME = Math.Acos(sigma)+sigma*Math.Sqrt(1-sigma2);
        }
        public override ManeuverParameters MakeNodeImpl(Orbit o, double universalTime, MechJebModuleTargetController target)
        {
            double UT = timeSelector.ComputeManeuverTime(o, universalTime, target);
            var dV = OrbitalManeuverCalculator.DeltaVToShiftNodeLongitude(o, UT, target.targetLongitude);

            return new ManeuverParameters(dV, UT);
        }
        //Computes the time until the phase angle between the launchpad and the target equals the given angle.
        //The convention used is that phase angle is the angle measured starting at the target and going east until
        //you get to the launchpad.
        //The time returned will not be exactly accurate unless the target is in an exactly circular orbit. However,
        //the time returned will go to exactly zero when the desired phase angle is reached.
        public static double TimeToPhaseAngle(double phaseAngle, CelestialBody launchBody, double launchLongitude, Orbit target)
        {
            double launchpadAngularRate = 360 / launchBody.rotationPeriod;
            double targetAngularRate = 360.0 / target.period;
            if (Vector3d.Dot(target.SwappedOrbitNormal(), launchBody.angularVelocity) < 0) targetAngularRate *= -1; //retrograde target

            Vector3d currentLaunchpadDirection = launchBody.GetSurfaceNVector(0, launchLongitude);
            Vector3d currentTargetDirection = target.SwappedRelativePositionAtUT(Planetarium.GetUniversalTime());
            currentTargetDirection = Vector3d.Exclude(launchBody.angularVelocity, currentTargetDirection);

            double currentPhaseAngle = Math.Abs(Vector3d.Angle(currentLaunchpadDirection, currentTargetDirection));
            if (Vector3d.Dot(Vector3d.Cross(currentTargetDirection, currentLaunchpadDirection), launchBody.angularVelocity) < 0)
            {
                currentPhaseAngle = 360 - currentPhaseAngle;
            }

            double phaseAngleRate = launchpadAngularRate - targetAngularRate;

            double phaseAngleDifference = MuUtils.ClampDegrees360(phaseAngle - currentPhaseAngle);

            if (phaseAngleRate < 0)
            {
                phaseAngleRate *= -1;
                phaseAngleDifference = 360 - phaseAngleDifference;
            }

            return phaseAngleDifference / phaseAngleRate;
        }
Beispiel #21
0
 public OrbitInfo(Orbitable orb, SharedObjects sharedObj)
     : this()
 {
     orbit = orb.Orbit;
     Shared = sharedObj;
     name = orb.GetName();
 }
        public override ManeuverParameters MakeNodeImpl(Orbit o, double UT, MechJebModuleTargetController target)
        {
            if (!target.NormalTargetExists)
            {
                throw new OperationException("must select a target for the Hohmann transfer.");
            }
            else if (o.referenceBody != target.TargetOrbit.referenceBody)
            {
                throw new OperationException("target for Hohmann transfer must be in the same sphere of influence.");
            }
            else if (o.eccentricity > 1)
            {
                throw new OperationException("starting orbit for Hohmann transfer must not be hyperbolic.");
            }
            else if (target.TargetOrbit.eccentricity > 1)
            {
                throw new OperationException("target orbit for Hohmann transfer must not be hyperbolic.");
            }
            else if (o.RelativeInclination(target.TargetOrbit) > 30 && o.RelativeInclination(target.TargetOrbit) < 150)
            {
                errorMessage = "Warning: target's orbital plane is at a " + o.RelativeInclination(target.TargetOrbit).ToString("F0") + "º angle to starting orbit's plane (recommend at most 30º). Planned transfer may not intercept target properly.";
            }
            else if (o.eccentricity > 0.2)
            {
                errorMessage = "Warning: Recommend starting Hohmann transfers from a near-circular orbit (eccentricity < 0.2). Planned transfer is starting from an orbit with eccentricity " + o.eccentricity.ToString("F2") + " and so may not intercept target properly.";
            }

            Vector3d dV = OrbitalManeuverCalculator.DeltaVAndTimeForHohmannTransfer(o, target.TargetOrbit, UT, out UT);

            return new ManeuverParameters(dV, UT);
        }
Beispiel #23
0
 public OrbitInfo( Orbit orb, SharedObjects sharedObj)
     : this()
 {
     Shared = sharedObj;
     orbit = orb;
     name = "<unnamed>";
 }
        public ReentrySimulation(Orbit _initialOrbit, double _UT, SimulatedVessel _vessel, SimCurves _simcurves, IDescentSpeedPolicy _descentSpeedPolicy, double _decelEndAltitudeASL, double _maxThrustAccel, double _parachuteSemiDeployMultiplier, double _probableLandingSiteASL, bool _multiplierHasError, double _dt, double _min_dt)
        {
            // Store all the input values as they were given
            input_initialOrbit = _initialOrbit;
            input_UT = _UT;
            
            vessel = _vessel;
            input_descentSpeedPolicy = _descentSpeedPolicy;
            input_decelEndAltitudeASL = _decelEndAltitudeASL;
            input_maxThrustAccel = _maxThrustAccel;
            input_parachuteSemiDeployMultiplier = _parachuteSemiDeployMultiplier;
            input_probableLandingSiteASL = _probableLandingSiteASL;
            input_multiplierHasError = _multiplierHasError;
            input_dt = _dt;

            // the vessel attitude relative to the surface vel. Fixed for now
            attitude = Quaternion.Euler(180,0,0);

            min_dt = _min_dt;
            max_dt = _dt;
            dt = max_dt;

            // Get a copy of the original orbit, to be more thread safe
            initialOrbit = new Orbit();
            initialOrbit.UpdateFromOrbitAtUT(_initialOrbit, _UT, _initialOrbit.referenceBody);

            CelestialBody body = _initialOrbit.referenceBody;
            bodyHasAtmosphere = body.atmosphere;
            bodyRadius = body.Radius;
            gravParameter = body.gravParameter;

            this.parachuteSemiDeployMultiplier = _parachuteSemiDeployMultiplier;
            this.multiplierHasError = _multiplierHasError;

            bodyAngularVelocity = body.angularVelocity;
            this.descentSpeedPolicy = _descentSpeedPolicy;
            decelRadius = bodyRadius + _decelEndAltitudeASL; 
            aerobrakedRadius = bodyRadius + body.RealMaxAtmosphereAltitude();
            mainBody = body;
            this.maxThrustAccel = _maxThrustAccel;
            this.probableLandingSiteASL = _probableLandingSiteASL;
            this.probableLandingSiteRadius = _probableLandingSiteASL + bodyRadius;

            referenceFrame = ReferenceFrame.CreateAtCurrentTime(_initialOrbit.referenceBody);

            orbitReenters = OrbitReenters(_initialOrbit);

            if (orbitReenters)
                startUT = _UT;

            maxDragGees = 0;
            deltaVExpended = 0;
            trajectory = new List<AbsoluteVector>();

            simCurves = _simcurves;

            once = true;

        }
 // Use this for initialization
 void Start()
 {
     cameraScript = cameraObject.GetComponent<CameraMovement>();
     kmCameraScript = kmCameraObject.GetComponent<CameraMovement>();
     orbitScript = rotateObject.GetComponent<Orbit>();
     timerText.text = timeLeft.ToString("0.00");
     timerScreen.SetActive(false);
 }
 public void CircularOrbitAtZeroHasZeroAnglesAndMeanDistance()
 {
   Orbit orbit = new Orbit { Period = 1, MeanDistance = 1, Eccentricity = 0, Inclination = 0, PeriapsisArgument = 0 };
   var position = OrbitMechanics.CalculatePosition(0, orbit);
   Assert.AreEqual(0, position.Polar);
   Assert.AreEqual(0, position.Elevation);
   Assert.AreEqual(1, position.Radius);
 }
 public void CircularOrbitAtThreeQyartersYearHas270PolarAngleAndMeanDistance()
 {
   Orbit orbit = new Orbit { Period = 1, MeanDistance = 1, Eccentricity = 0, Inclination = 0, PeriapsisArgument = 0 };
   var position = OrbitMechanics.CalculatePosition(0.75f, orbit);
   Assert.AreEqual(Math.PI + Math.PI / 2, position.Polar, 0.00001);
   Assert.AreEqual(0, position.Elevation);
   Assert.AreEqual(1, position.Radius);
 }
Beispiel #28
0
            public Orbit stockPatch { get; set; } // tells wether the patch starting from this state is superimposed on a stock KSP patch, or null if something makes it diverge (atmospheric entry for example)

            public VesselState(Vessel vessel)
            {
                referenceBody = vessel.orbit.referenceBody;
                time = Planetarium.GetUniversalTime();
                position = vessel.GetWorldPos3D() - referenceBody.position;
                velocity = vessel.obt_velocity;
                stockPatch = vessel.orbit;
            }
Beispiel #29
0
		public void CircularSector()
		{
			var o = new Orbit {SemiMajorAxis = 1, SemiMinorAxis = 1, TransformAngle = 0};
			AssertAreClose(o.S(1, 0), Math.PI / 2);
			AssertAreClose(o.S(1, Math.PI), 0);
			AssertAreClose(o.S(1, -Math.PI/2), 3*Math.PI/4);
			AssertAreClose(o.S(1, -Math.PI), Math.PI);
		}
 public override void DoParametersGUI(Orbit o, double universalTime, MechJebModuleTargetController target)
 {
     if (target.Target is CelestialBody)
         GuiUtils.SimpleTextBox("Approximate final periapsis", courseCorrectFinalPeA, "km");
     else
         GuiUtils.SimpleTextBox("Closest approach distance", interceptDistance, "m");
     GUILayout.Label("Schedule the burn to minimize the required ΔV.");
 }
 public override void UpdateOrbit(Orbit current)
 {
     base.UpdateOrbit(current);
     update(false, false);
 }
 public void UpdateOrbit(Orbit current, bool with_brake, bool brake_at_fly_above)
 {
     base.UpdateOrbit(current);
     update(with_brake, brake_at_fly_above);
 }
 public LandingPath(VesselWrapper vsl, Orbit orb, double target_altitude, double startUT, double dt,
                    double start_mass, double fuel = 0, double brake_vel = 0)
 {
     VSL            = vsl;
     Orbit          = orb;
     TargetAltitude = target_altitude;
     StartUT        = startUT;
     UT0            = VSL.Physics.UT;
     if (Orbit.referenceBody.atmosphere || brake_vel > 0 && fuel > 0)
     {
         EndUT      = startUT + orb.timeToPe;
         HavePoints = brake_vel > 0 && fuel > 0;
         var p         = newP(StartUT);
         var m         = start_mass;
         var s         = Math.Max(VSL.Geometry.MinArea, VSL.Geometry.AreaWithBrakes);
         var ascending = p.Ascending;
         p.Duration = dt;
         while ((ascending || p.Altitude > TargetAltitude) && p.UT < EndUT)
         {
             if (!ascending && dt > 0.01)
             {
                 var dAlt = p.Altitude - TargetAltitude;
                 if (dAlt / p.SrfSpeed < dt)
                 {
                     dt         = dAlt / p.SrfSpeed * 0.9;
                     p.Duration = dt;
                 }
             }
             var drag_dv  = p.SpecificDrag * s / m * dt;
             var prev_alt = p.Altitude;
             Atmosphere |= drag_dv > 0;
             HavePoints |= Atmosphere;
             if (HavePoints)
             {
                 if (Points.Count == 0)
                 {
                     FirstPointUT = p.UT;
                     if (Atmosphere)
                     {
                         AtmoStartUT = p.UT;
                     }
                 }
                 Points.Add(p);
                 //                    VSL.Log("drag dV {}, m {}, fm {}, brake_vel {}, p {}",
                 //                            drag_dv, m, fuel, brake_vel, p);//debug
                 var r = p.pos.magnitude;
                 if (brake_vel > 0 && fuel > 0)
                 {
                     //compute thrust direction
                     var vV    = Utils.ClampL(Vector3d.Dot(p.vel, p.pos / r), 1e-5);
                     var b_dir = LandingTrajectoryAutopilot.CorrectedBrakeVelocity(VSL, p.vel, p.pos,
                                                                                   p.DynamicPressure / 1000 / LandingTrajectoryAutopilot.C.MinDPressure,
                                                                                   (p.Altitude - TargetAltitude) / vV).normalized;
                     //compute thrust and mass flow
                     float mflow;
                     var   thrust = VSL.Engines.ThrustAtAlt((float)p.SrfSpeed, (float)p.Altitude, out mflow);
                     var   Ve     = thrust / mflow;
                     var   dm     = mflow * dt;
                     if (dm > fuel)
                     {
                         dm = fuel;
                     }
                     var bV = (double)VSL.Engines.DeltaV(Ve, (float)dm);
                     if (bV > brake_vel)
                     {
                         bV = brake_vel;
                         dm = EnginesProps.FuelNeeded((float)bV, Ve, (float)m);
                     }
                     p.vel     -= b_dir * bV;
                     brake_vel -= bV;
                     //                        VSL.Log("vV {}, vB {}, thrust {}, mflow {}, Ve {}, dm {}\nb_dir {}\nvel {}\npos {}",
                     //                                vV, bV, thrust, mflow, Ve, dm, b_dir, p.vel, p.pos);//debug
                     //spend fuel
                     fuel -= dm;
                     m    -= dm;
                 }
                 if (Atmosphere)
                 {
                     p.vel -= p.srf_vel / p.SrfSpeed * Math.Min(drag_dv, p.SrfSpeed);
                 }
                 p.vel -= p.pos * p.Body.gMagnitudeAtCenter / r / r / r * dt;
                 p.pos += p.vel * dt;
                 p.UT  += dt;
                 p.Update();
                 if (Atmosphere && AtmoStopUT < 0 && p.SrfSpeed < 10)
                 {
                     AtmoStopUT = p.UT;
                 }
             }
             else
             {
                 p.Update(p.UT + dt);
             }
             ascending &= p.Altitude > prev_alt;
         }
         if (HavePoints)
         {
             Points.Add(p);
             if (Atmosphere && AtmoStopUT < 0)
             {
                 AtmoStopUT = p.UT;
             }
         }
         EndUT     = p.UT;
         LastPoint = p;
     }
     else
     {
         EndUT     = TrajectoryCalculator.NearestRadiusUT(Orbit, Orbit.referenceBody.Radius + TargetAltitude, StartUT);
         LastPoint = newP(EndUT);
     }
 }
Beispiel #34
0
 /// Dublicate an orbit
 public static Orbit Clone(this Orbit orbit0)
 {
     return(new Orbit(orbit0.inclination, orbit0.eccentricity, orbit0.semiMajorAxis, orbit0.LAN, orbit0.argumentOfPeriapsis, orbit0.meanAnomalyAtEpoch, orbit0.epoch, orbit0.referenceBody));
 }
 public override void UpdateOrbit(Orbit current)
 {
     base.UpdateOrbit(current);
     TransferTime = -1;
     update();
 }
Beispiel #36
0
 internal static double timeOfClosestApproach(Orbit oOrig, Orbit oTgt, double timeStart, out double closestdistance)
 {
     return(timeOfClosestApproach(oOrig, oTgt, timeStart, oOrig.period, 20, out closestdistance));
 }
Beispiel #37
0
 internal static double timeOfTargetAltitude(Orbit oOrig, double timeStart, out double closestdistance, double targetDistance)
 {
     //return timeOfClosestApproach(a, b, time + ((orbit - 1) * a.period), (orbit * a.period), 20, out closestdistance);
     return(timeOfTargetAltitude(oOrig, timeStart, 20, out closestdistance, targetDistance));
 }
 public Vector3d GetOrbitVelocityAtSurface()
 {
     return(Orbit.getOrbitalVelocityAtUT(AtTargetUT));
 }
Beispiel #39
0
    protected override void Collide(Collision2D other)
    {
        Rigidbody2D rb = other.gameObject.GetComponent <Rigidbody2D>();

        if (rb)
        {
            if (frozenObjects.Contains(rb))
            {
                rb.isKinematic     = false;
                rb.velocity        = Vector2.zero;
                rb.angularVelocity = 0;
                rb.constraints     = RigidbodyConstraints2D.None;
                frozenObjects.Remove(rb);
            }
            else
            {
                //scaled.TimeScale = 0;
                rb.isKinematic     = true;
                rb.velocity        = Vector2.zero;
                rb.angularVelocity = 0;
                rb.constraints     = RigidbodyConstraints2D.FreezeAll;
                frozenObjects.Add(rb);
                GameObject.FindWithTag("Player").GetComponentInChildren <TimeGun>().StartUnFreeze(rb, freezeTime);
            }

            return;
        }

        Movingplatform platform = other.gameObject.GetComponent <Movingplatform>();

        if (platform)
        {
            FrozenPlatform frozen = frozenPlatforms.FirstOrDefault(p => p.platform == platform);

            if (frozen.platform != null)
            {
                frozen.platform.TimeScale = frozen.unfrozenTimeScale;
                frozenPlatforms.Remove(frozen);
            }
            else
            {
                frozenPlatforms.Add(new FrozenPlatform {
                    platform = platform, unfrozenTimeScale = platform.TimeScale
                });
                platform.TimeScale = 0;
                GameObject.FindWithTag("Player").GetComponentInChildren <TimeGun>().StartUnFreeze(platform, freezeTime);
            }

            return;
        }

        Orbit o = other.gameObject.GetComponent <Orbit>();

        if (o)
        {
            if (frozenOrbits.Contains(o))
            {
                o.enabled = true;
                frozenOrbits.Remove(o);
            }
            else
            {
                frozenOrbits.Add(o);
                o.enabled = false;
                GameObject.FindWithTag("Player").GetComponentInChildren <TimeGun>().StartUnFreeze(o, freezeTime);
            }
        }
    }
Beispiel #40
0
 public Planet(GameObject prefab, Orbit orbit)
 {
     this.prefab = prefab;
     this.orbit  = orbit;
 }
        private static Vector3d CalculateDragVector(Vessel vessel, VesselData vesselData, Vector3d orbitalVector, Orbit vesselOrbit)
        {
            var normalizedOrbitalVector        = orbitalVector.normalized;
            var cosOrbitRaw                    = Vector3d.Dot(vessel.transform.up, normalizedOrbitalVector);
            var cosOrbitalDrag                 = Math.Abs(cosOrbitRaw);
            var squaredCosOrbitalDrag          = cosOrbitalDrag * cosOrbitalDrag;
            var atmosphericGasKgPerSquareMeter = AtmosphericFloatCurves.GetAtmosphericGasDensityKgPerCubicMeter(vesselOrbit.referenceBody, vessel.altitude);

            var effectiveSpeedForDrag   = Math.Max(0, orbitalVector.magnitude);
            var dragForcePerSquareMeter = atmosphericGasKgPerSquareMeter * 0.5 * effectiveSpeedForDrag * effectiveSpeedForDrag;
            var effectiveSurfaceArea    = cosOrbitalDrag * vesselData.ModulePhotonSail.surfaceArea;

            // calculate normal
            Vector3d vesselNormal = vessel.transform.up;

            if (cosOrbitRaw < 0)
            {
                vesselNormal = -vesselNormal;
            }

            // calculate specular drag
            var      specularDragCoefficient    = squaredCosOrbitalDrag + 3 * squaredCosOrbitalDrag;
            var      specularDragPerSquareMeter = specularDragCoefficient * dragForcePerSquareMeter * 0.1;
            var      specularDragInNewton       = specularDragPerSquareMeter * effectiveSurfaceArea;
            Vector3d specularDragForce          = specularDragInNewton * vesselNormal;

            // calculate Diffuse Drag
            var      diffuseDragCoefficient    = 2 + squaredCosOrbitalDrag * 1.3;
            var      diffuseDragPerSquareMeter = diffuseDragCoefficient * dragForcePerSquareMeter * 0.9;
            var      diffuseDragInNewton       = diffuseDragPerSquareMeter * effectiveSurfaceArea;
            Vector3d diffuseDragForceVector    = diffuseDragInNewton * normalizedOrbitalVector * -1;

            Vector3d combinedDragDecelerationVector = vesselData.TotalVesselMassInKg > 0
                ? (specularDragForce + diffuseDragForceVector) / vesselData.TotalVesselMassInKg
                : Vector3d.zero;

            return(combinedDragDecelerationVector);
        }
Beispiel #42
0
 private static void SetOrbit(OrbitDriver currentlyEditing, Orbit orbit)
 {
     Log.Info("Setorbit");
     currentlyEditing.DynamicSetOrbit(orbit);
 }
Beispiel #43
0
 public static Vector3d Node2OrbitalDeltaV(ManeuverNode node, Orbit o = null) =>
 Node2OrbitalDeltaV(o ?? node.patch, node.DeltaV, node.UT);
Beispiel #44
0
        private void checkOrbit()
        {
            if (_manager.SelectedManeuverNode == null || _snapTab == null)
            {
                return;
            }

            if (_patch == null)
            {
                SetFields();
            }

            double UT = Planetarium.GetUniversalTime();

            //_snapTab.CurrentTime.OnTextUpdate.Invoke(string.Format("Maneuver Node #{0}: T {1}", _index + 1, KSPUtil.PrintTime(UT - _manager.SelectedManeuverNode.UT, 3, true)));
            _snapTab.ResetTime.OnTextUpdate.Invoke(string.Format("{0}", KSPUtil.PrintTime(_startUT - UT, 3, false)));

            if (_patch.eccentricity >= 1)
            {
                if (_manager.SelectedManeuverNode.attachedGizmo != null)
                {
                    _manager.SelectedManeuverNode.attachedGizmo.orbitsAdded = 0;
                }

                _orbitsAdded = 0;

                _snapTab.NextOrbitButton.gameObject.SetActive(false);
                _snapTab.PreviousOrbitButton.gameObject.SetActive(false);

                _snapTab.ApoButton.gameObject.SetActive(false);

                if (_patch.timeToPe < 0)
                {
                    _snapTab.PeriButton.gameObject.SetActive(false);
                }
                else if (_patch.PeR < 0)
                {
                    _snapTab.PeriButton.gameObject.SetActive(false);
                }
                else if (_patch.UTsoi > 0 && _patch.timeToPe + _patch.StartUT > _patch.UTsoi)
                {
                    _snapTab.PeriButton.gameObject.SetActive(false);
                }
                else
                {
                    _snapTab.PeriButton.gameObject.SetActive(true);
                    periUT = _patch.StartUT + _patch.timeToPe;
                }

                if ((_patch.patchEndTransition == Orbit.PatchTransitionType.ENCOUNTER || _patch.patchEndTransition == Orbit.PatchTransitionType.ESCAPE || _patch.patchEndTransition == Orbit.PatchTransitionType.MANEUVER) &&
                    (_patch.nextPatch.patchEndTransition == Orbit.PatchTransitionType.ENCOUNTER || _patch.nextPatch.patchEndTransition == Orbit.PatchTransitionType.ESCAPE))
                {
                    _snapTab.NextPatchButton.gameObject.SetActive(true);

                    if (_patch.nextPatch.nextPatch.UTsoi > 0)
                    {
                        nextPUT = _patch.nextPatch.nextPatch.StartUT + ((_patch.nextPatch.nextPatch.UTsoi - _patch.nextPatch.nextPatch.StartUT) / 2);
                    }
                    else if (_patch.nextPatch.nextPatch.eccentricity < 1 && !double.IsNaN(_patch.nextPatch.nextPatch.period) && !double.IsInfinity(_patch.nextPatch.nextPatch.period))
                    {
                        nextPUT = _patch.nextPatch.nextPatch.StartUT + (_patch.nextPatch.nextPatch.period / 2);
                    }
                    else
                    {
                        nextPUT = _patch.nextPatch.nextPatch.StartUT + ((_patch.nextPatch.nextPatch.EndUT - _patch.nextPatch.nextPatch.StartUT) / 2);
                    }
                }
                else
                {
                    _snapTab.NextPatchButton.gameObject.SetActive(false);
                }

                if (_patch.patchStartTransition == Orbit.PatchTransitionType.INITIAL || _patch.patchStartTransition == Orbit.PatchTransitionType.MANEUVER)
                {
                    _snapTab.PreviousPatchButton.gameObject.SetActive(false);
                }
                else
                {
                    _snapTab.PreviousPatchButton.gameObject.SetActive(true);

                    if (_patch.previousPatch.UTsoi > 0)
                    {
                        prevPUT = _patch.previousPatch.StartUT + ((_patch.previousPatch.UTsoi - _patch.previousPatch.StartUT) / 2);
                    }
                    else if (_patch.previousPatch.eccentricity < 1 && !double.IsNaN(_patch.previousPatch.period) && !double.IsInfinity(_patch.previousPatch.period))
                    {
                        prevPUT = _patch.previousPatch.StartUT + (_patch.previousPatch.period / 2);
                    }
                    else
                    {
                        prevPUT = _patch.previousPatch.StartUT + ((_patch.previousPatch.EndUT - _patch.previousPatch.StartUT) / 2);
                    }
                }

                eqAscUT = ManeuverUtilities.EqAscTime(_patch);

                if (_patch.UTsoi > 0 && eqAscUT > _patch.UTsoi)
                {
                    _snapTab.EqAscButton.gameObject.SetActive(false);
                }
                else if (eqAscUT < UT)
                {
                    _snapTab.EqAscButton.gameObject.SetActive(false);
                }
                else
                {
                    _snapTab.EqAscButton.gameObject.SetActive(true);
                }

                eqDescUT = ManeuverUtilities.EqDescTime(_patch);

                if (_patch.UTsoi > 0 && eqDescUT > _patch.UTsoi)
                {
                    _snapTab.EqDescButton.gameObject.SetActive(false);
                }
                else if (eqDescUT < UT)
                {
                    _snapTab.EqDescButton.gameObject.SetActive(false);
                }
                else
                {
                    _snapTab.EqDescButton.gameObject.SetActive(true);
                }

                ITargetable target = FlightGlobals.fetch.VesselTarget;

                if (target == null)
                {
                    _snapTab.RelAscButton.gameObject.SetActive(false);
                    _snapTab.RelDescButton.gameObject.SetActive(false);
                    _snapTab.ClAppButton.gameObject.SetActive(false);
                }
                else
                {
                    Orbit tgtPatch = target.GetOrbit();

                    if (tgtPatch.referenceBody != _patch.referenceBody)
                    {
                        _snapTab.RelAscButton.gameObject.SetActive(false);
                        _snapTab.RelDescButton.gameObject.SetActive(false);
                        _snapTab.ClAppButton.gameObject.SetActive(false);
                    }
                    else
                    {
                        relAscUT = ManeuverUtilities.RelAscTime(_patch, target);

                        if (_patch.UTsoi > 0 && relAscUT > _patch.UTsoi)
                        {
                            _snapTab.RelAscButton.gameObject.SetActive(false);
                        }
                        else if (relAscUT < UT)
                        {
                            _snapTab.RelAscButton.gameObject.SetActive(false);
                        }
                        else
                        {
                            _snapTab.RelAscButton.gameObject.SetActive(true);
                        }

                        relDescUT = ManeuverUtilities.RelDescTime(_patch, target);

                        if (_patch.UTsoi > 0 && relDescUT > _patch.UTsoi)
                        {
                            _snapTab.RelDescButton.gameObject.SetActive(false);
                        }
                        else if (relDescUT < UT)
                        {
                            _snapTab.RelDescButton.gameObject.SetActive(false);
                        }
                        else
                        {
                            _snapTab.RelDescButton.gameObject.SetActive(true);
                        }

                        if (target.GetVessel() == null)
                        {
                            clAppUT = _patch.closestTgtApprUT;
                        }
                        else
                        {
                            clAppUT = ManeuverUtilities.closestVessel(0, _patch, tgtPatch, true, 0, 0);
                        }

                        if (clAppUT <= 0)
                        {
                            _snapTab.ClAppButton.gameObject.SetActive(false);
                        }
                        else if (_patch.UTsoi > 0 && clAppUT > _patch.UTsoi)
                        {
                            _snapTab.ClAppButton.gameObject.SetActive(false);
                        }
                        else if (clAppUT < UT)
                        {
                            _snapTab.ClAppButton.gameObject.SetActive(false);
                        }
                        else
                        {
                            _snapTab.ClAppButton.gameObject.SetActive(true);
                        }
                    }
                }
            }
            else
            {
                if (_patch.patchEndTransition == Orbit.PatchTransitionType.FINAL)
                {
                    if (!double.IsNaN(_patch.period) && !double.IsInfinity(_patch.period))
                    {
                        _snapTab.NextOrbitButton.gameObject.SetActive(true);
                        nextOUT = _manager.SelectedManeuverNode.UT + _patch.period;
                    }
                    else
                    {
                        _snapTab.NextOrbitButton.gameObject.SetActive(false);
                    }

                    if (double.IsNaN(_patch.period) || double.IsInfinity(_patch.period) || _manager.SelectedManeuverNode.UT - _patch.period < UT)
                    {
                        _snapTab.PreviousOrbitButton.gameObject.SetActive(false);
                    }
                    else
                    {
                        _snapTab.PreviousOrbitButton.gameObject.SetActive(true);
                        prevOUT = _manager.SelectedManeuverNode.UT - _patch.period;
                    }

                    _snapTab.ApoButton.gameObject.SetActive(true);
                    apoUT = _patch.StartUT + _patch.timeToAp;

                    _snapTab.PeriButton.gameObject.SetActive(true);
                    periUT = _patch.StartUT + _patch.timeToPe;

                    _snapTab.NextPatchButton.gameObject.SetActive(false);

                    if (_patch.patchStartTransition == Orbit.PatchTransitionType.INITIAL || _patch.patchStartTransition == Orbit.PatchTransitionType.MANEUVER)
                    {
                        _snapTab.PreviousPatchButton.gameObject.SetActive(false);
                    }
                    else
                    {
                        _snapTab.PreviousPatchButton.gameObject.SetActive(true);

                        if (_patch.previousPatch.UTsoi > 0)
                        {
                            prevPUT = _patch.previousPatch.StartUT + ((_patch.previousPatch.UTsoi - _patch.previousPatch.StartUT) / 2);
                        }
                        else if (_patch.previousPatch.eccentricity < 1 && !double.IsNaN(_patch.previousPatch.period) && !double.IsInfinity(_patch.previousPatch.period))
                        {
                            prevPUT = _patch.previousPatch.StartUT + (_patch.previousPatch.period / 2);
                        }
                        else
                        {
                            prevPUT = _patch.previousPatch.StartUT + ((_patch.previousPatch.EndUT - _patch.previousPatch.StartUT) / 2);
                        }
                    }

                    _snapTab.EqAscButton.gameObject.SetActive(true);
                    eqAscUT = ManeuverUtilities.EqAscTime(_patch);

                    _snapTab.EqDescButton.gameObject.SetActive(true);
                    eqDescUT = ManeuverUtilities.EqDescTime(_patch);

                    ITargetable target = FlightGlobals.fetch.VesselTarget;

                    if (target == null)
                    {
                        _snapTab.RelAscButton.gameObject.SetActive(false);
                        _snapTab.RelDescButton.gameObject.SetActive(false);
                        _snapTab.ClAppButton.gameObject.SetActive(false);
                    }
                    else
                    {
                        Orbit tgtPatch = target.GetOrbit();

                        if (tgtPatch.referenceBody != _patch.referenceBody)
                        {
                            _snapTab.RelAscButton.gameObject.SetActive(false);
                            _snapTab.RelDescButton.gameObject.SetActive(false);
                            _snapTab.ClAppButton.gameObject.SetActive(false);
                        }
                        else
                        {
                            _snapTab.RelAscButton.gameObject.SetActive(true);
                            relAscUT = ManeuverUtilities.RelAscTime(_patch, target);

                            _snapTab.RelDescButton.gameObject.SetActive(true);
                            relDescUT = ManeuverUtilities.RelDescTime(_patch, target);

                            if (target.GetVessel() == null)
                            {
                                clAppUT = _patch.closestTgtApprUT;
                            }
                            else
                            {
                                clAppUT = ManeuverUtilities.closestVessel(0, _patch, tgtPatch, true, 0, 0);
                            }

                            if (clAppUT <= 0)
                            {
                                _snapTab.ClAppButton.gameObject.SetActive(false);
                            }
                            else
                            {
                                _snapTab.ClAppButton.gameObject.SetActive(true);
                            }
                        }
                    }
                }
                else
                {
                    if (_manager.SelectedManeuverNode.attachedGizmo != null)
                    {
                        _manager.SelectedManeuverNode.attachedGizmo.orbitsAdded = 0;
                    }

                    _orbitsAdded = 0;

                    _snapTab.NextOrbitButton.gameObject.SetActive(false);
                    _snapTab.PreviousOrbitButton.gameObject.SetActive(false);

                    if (_patch.timeToAp < 0)
                    {
                        _snapTab.ApoButton.gameObject.SetActive(false);
                    }
                    if (_patch.UTsoi > 0 && _patch.timeToAp + _patch.StartUT > _patch.UTsoi)
                    {
                        _snapTab.ApoButton.gameObject.SetActive(false);
                    }
                    if (_patch.ApA > _patch.referenceBody.sphereOfInfluence)
                    {
                        _snapTab.ApoButton.gameObject.SetActive(false);
                    }
                    else
                    {
                        _snapTab.ApoButton.gameObject.SetActive(true);
                        apoUT = _patch.StartUT + _patch.timeToAp;
                    }

                    if (_patch.timeToPe < 0)
                    {
                        _snapTab.PeriButton.gameObject.SetActive(false);
                    }
                    else if (_patch.PeR < 0)
                    {
                        _snapTab.PeriButton.gameObject.SetActive(false);
                    }
                    else if (_patch.UTsoi > 0 && _patch.timeToPe + _patch.StartUT > _patch.UTsoi)
                    {
                        _snapTab.PeriButton.gameObject.SetActive(false);
                    }
                    else
                    {
                        _snapTab.PeriButton.gameObject.SetActive(true);
                        periUT = _patch.StartUT + _patch.timeToPe;
                    }

                    if ((_patch.patchEndTransition == Orbit.PatchTransitionType.ENCOUNTER || _patch.patchEndTransition == Orbit.PatchTransitionType.ESCAPE || _patch.patchEndTransition == Orbit.PatchTransitionType.MANEUVER) &&
                        (_patch.nextPatch.patchEndTransition == Orbit.PatchTransitionType.ENCOUNTER || _patch.nextPatch.patchEndTransition == Orbit.PatchTransitionType.ESCAPE))
                    {
                        _snapTab.NextPatchButton.gameObject.SetActive(true);

                        if (_patch.nextPatch.nextPatch.UTsoi > 0)
                        {
                            nextPUT = _patch.nextPatch.nextPatch.StartUT + ((_patch.nextPatch.nextPatch.UTsoi - _patch.nextPatch.nextPatch.StartUT) / 2);
                        }
                        else if (_patch.nextPatch.nextPatch.eccentricity < 1 && !double.IsNaN(_patch.nextPatch.nextPatch.period) && !double.IsInfinity(_patch.nextPatch.nextPatch.period))
                        {
                            nextPUT = _patch.nextPatch.nextPatch.StartUT + (_patch.nextPatch.nextPatch.period / 2);
                        }
                        else
                        {
                            nextPUT = _patch.nextPatch.nextPatch.StartUT + ((_patch.nextPatch.nextPatch.EndUT - _patch.nextPatch.nextPatch.StartUT) / 2);
                        }
                    }
                    else
                    {
                        _snapTab.NextPatchButton.gameObject.SetActive(false);
                    }

                    if (_patch.patchStartTransition == Orbit.PatchTransitionType.INITIAL || _patch.patchStartTransition == Orbit.PatchTransitionType.MANEUVER)
                    {
                        _snapTab.PreviousPatchButton.gameObject.SetActive(false);
                    }
                    else
                    {
                        _snapTab.PreviousPatchButton.gameObject.SetActive(true);

                        if (_patch.previousPatch.UTsoi > 0)
                        {
                            prevPUT = _patch.previousPatch.StartUT + ((_patch.previousPatch.UTsoi - _patch.previousPatch.StartUT) / 2);
                        }
                        else if (_patch.previousPatch.eccentricity < 1 && !double.IsNaN(_patch.previousPatch.period) && !double.IsInfinity(_patch.previousPatch.period))
                        {
                            prevPUT = _patch.previousPatch.StartUT + (_patch.previousPatch.period / 2);
                        }
                        else
                        {
                            prevPUT = _patch.previousPatch.StartUT + ((_patch.previousPatch.EndUT - _patch.previousPatch.StartUT) / 2);
                        }
                    }

                    eqAscUT = ManeuverUtilities.EqAscTime(_patch);

                    if (_patch.UTsoi > 0 && eqAscUT > _patch.UTsoi)
                    {
                        _snapTab.EqAscButton.gameObject.SetActive(false);
                    }
                    else if (eqAscUT < UT)
                    {
                        _snapTab.EqAscButton.gameObject.SetActive(false);
                    }
                    else
                    {
                        _snapTab.EqAscButton.gameObject.SetActive(true);
                    }

                    eqDescUT = ManeuverUtilities.EqDescTime(_patch);

                    if (_patch.UTsoi > 0 && eqDescUT > _patch.UTsoi)
                    {
                        _snapTab.EqDescButton.gameObject.SetActive(false);
                    }
                    else if (eqDescUT < UT)
                    {
                        _snapTab.EqDescButton.gameObject.SetActive(false);
                    }
                    else
                    {
                        _snapTab.EqDescButton.gameObject.SetActive(true);
                    }

                    ITargetable target = FlightGlobals.fetch.VesselTarget;

                    if (target == null)
                    {
                        _snapTab.RelAscButton.gameObject.SetActive(false);
                        _snapTab.RelDescButton.gameObject.SetActive(false);
                        _snapTab.ClAppButton.gameObject.SetActive(false);
                    }
                    else
                    {
                        Orbit tgtPatch = target.GetOrbit();

                        if (tgtPatch.referenceBody != _patch.referenceBody)
                        {
                            _snapTab.RelAscButton.gameObject.SetActive(false);
                            _snapTab.RelDescButton.gameObject.SetActive(false);
                            _snapTab.ClAppButton.gameObject.SetActive(false);
                        }
                        else
                        {
                            relAscUT = ManeuverUtilities.RelAscTime(_patch, target);

                            if (_patch.UTsoi > 0 && relAscUT > _patch.UTsoi)
                            {
                                _snapTab.RelAscButton.gameObject.SetActive(false);
                            }
                            else if (relAscUT < UT)
                            {
                                _snapTab.RelAscButton.gameObject.SetActive(false);
                            }
                            else
                            {
                                _snapTab.RelAscButton.gameObject.SetActive(true);
                            }

                            relDescUT = ManeuverUtilities.RelDescTime(_patch, target);

                            if (_patch.UTsoi > 0 && relDescUT > _patch.UTsoi)
                            {
                                _snapTab.RelDescButton.gameObject.SetActive(false);
                            }
                            else if (relDescUT < UT)
                            {
                                _snapTab.RelDescButton.gameObject.SetActive(false);
                            }
                            else
                            {
                                _snapTab.RelDescButton.gameObject.SetActive(true);
                            }

                            if (target.GetVessel() == null)
                            {
                                clAppUT = _patch.closestTgtApprUT;
                            }
                            else
                            {
                                clAppUT = ManeuverUtilities.closestVessel(0, _patch, tgtPatch, true, 0, 0);
                            }

                            if (clAppUT <= 0)
                            {
                                _snapTab.ClAppButton.gameObject.SetActive(false);
                            }
                            else if (_patch.UTsoi > 0 && clAppUT > _patch.UTsoi)
                            {
                                _snapTab.ClAppButton.gameObject.SetActive(false);
                            }
                            else if (clAppUT < UT)
                            {
                                _snapTab.ClAppButton.gameObject.SetActive(false);
                            }
                            else
                            {
                                _snapTab.ClAppButton.gameObject.SetActive(true);
                            }
                        }
                    }
                }
            }
        }
        protected void MaintainAerobrakeNode()
        {
            if (makeAerobrakeNodes)
            {
                //Remove node after finishing aerobraking:
                if (aerobrakeNode != null && vessel.patchedConicSolver.maneuverNodes.Contains(aerobrakeNode))
                {
                    if (aerobrakeNode.UT < vesselState.time && vesselState.altitudeASL > mainBody.RealMaxAtmosphereAltitude())
                    {
                        vessel.patchedConicSolver.RemoveManeuverNode(aerobrakeNode);
                        aerobrakeNode = null;
                    }
                }

                //Update or create node if necessary:
                ReentrySimulation.Result r = GetResult();
                if (r != null && r.outcome == ReentrySimulation.Outcome.AEROBRAKED)
                {
                    //Compute the node dV:
                    Orbit preAerobrakeOrbit = GetReenteringPatch();

                    //Put the node at periapsis, unless we're past periapsis. In that case put the node at the current time.
                    double UT;
                    if (preAerobrakeOrbit == orbit &&
                        vesselState.altitudeASL < mainBody.RealMaxAtmosphereAltitude() && vesselState.speedVertical > 0)
                    {
                        UT = vesselState.time;
                    }
                    else
                    {
                        UT = preAerobrakeOrbit.NextPeriapsisTime(preAerobrakeOrbit.StartUT);
                    }

                    Orbit postAerobrakeOrbit = MuUtils.OrbitFromStateVectors(r.WorldEndPosition(), r.WorldEndVelocity(), r.body, r.endUT);

                    Vector3d dV = OrbitalManeuverCalculator.DeltaVToChangeApoapsis(preAerobrakeOrbit, UT, postAerobrakeOrbit.ApR);

                    if (aerobrakeNode != null && vessel.patchedConicSolver.maneuverNodes.Contains(aerobrakeNode))
                    {
                        //update the existing node
                        Vector3d nodeDV = preAerobrakeOrbit.DeltaVToManeuverNodeCoordinates(UT, dV);
                        aerobrakeNode.OnGizmoUpdated(nodeDV, UT);
                    }
                    else
                    {
                        //place a new node
                        aerobrakeNode = vessel.PlaceManeuverNode(preAerobrakeOrbit, dV, UT);
                    }
                }
                else
                {
                    //no aerobraking, remove the node:
                    if (aerobrakeNode != null && vessel.patchedConicSolver.maneuverNodes.Contains(aerobrakeNode))
                    {
                        vessel.patchedConicSolver.RemoveManeuverNode(aerobrakeNode);
                    }
                }
            }
            else
            {
                //Remove aerobrake node when it is turned off:
                if (aerobrakeNode != null && vessel.patchedConicSolver.maneuverNodes.Contains(aerobrakeNode))
                {
                    vessel.patchedConicSolver.RemoveManeuverNode(aerobrakeNode);
                }
            }
        }
Beispiel #46
0
 internal static double timeOfTargetDistance(Orbit oOrig, Orbit oTgt, double timeStart, int orbit, out double closestdistance, double targetDistance)
 {
     //return timeOfClosestApproach(a, b, time + ((orbit - 1) * a.period), (orbit * a.period), 20, out closestdistance);
     return(timeOfTargetDistance(oOrig, oTgt, timeStart + ((orbit - 1) * oOrig.period), oOrig.period, 20, out closestdistance, targetDistance));
 }
        void update(bool with_brake, bool brake_at_fly_above)
        {
            reset();
            //update everything
            update_from_orbit();
            update_landing_steepness();
            ActualLandingAngle = 90 - Utils.Angle2(AtTargetPos, -AtTargetVel);
            var AerobrakeStartUT = Path.Atmosphere ? Path.AtmoStartUT : AtTargetUT - 1;

            //correct for brake maneuver
            if (with_brake)
            {
                //estimate time needed to rotate the ship downwards
                var rotation_time = VSL.Torque.NoEngines ?
                                    VSL.Torque.NoEngines.RotationTime2Phase(90) :
                                    VSL.Torque.MaxPossible.RotationTime2Phase(90, 0.1f);
                //estimate amount of fuel needed for the maneuver
                var vertical_vel = Vector3d.Project(AtTargetVel, AtTargetPos);
                SetBrakeEndUT(Math.Max(AtTargetUT - LandingTrajectoryAutopilot.C.CorrectionOffset + rotation_time, StartUT));
                SetBrakeDeltaV(vertical_vel);
                if (BrakeFuel > 0)
                {
                    //calculate braking maneuver
                    BrakeDuration = VSL.Engines.OnPlanetTTB(BrakeDeltaV,
                                                            Orbit.getRelativePositionAtUT(BrakeEndPoint.UT),
                                                            (float)(BrakeEndPointDeltaAlt + TargetAltitude));
                    BrakeDuration += rotation_time;
                    if (FullBrake)
                    {
                        if (brake_at_fly_above)
                        {
                            FlyAbovePoint = Path.FlyAbovePoint(Target.OrbPos(Body));
                            if (WillOverheat)
                            {
                                SetBrakeEndPoint(Path.PointAtShipTemp(VSL.Physics.MinMaxTemperature - 100));
                            }
                            else
                            {
                                SetBrakeEndPoint(FlyAbovePoint);
                            }
                        }
                        else
                        {
                            //find appropriate point to perform the maneuver
                            var brake_end_UT = Math.Max(AtTargetUT - Mathf.Max(LandingTrajectoryAutopilot.C.CorrectionOffset, BrakeDuration * 1.1f), StartUT);
                            var fly_over_alt = TargetAltitude + LandingTrajectoryAutopilot.C.FlyOverAlt;
                            if (WillOverheat)
                            {
                                SetBrakeEndPoint(Path.PointAtShipTemp(VSL.Physics.MinMaxTemperature - 100));
                            }
                            else if (Path.UT2Altitude(brake_end_UT) < fly_over_alt)
                            {
                                SetBrakeEndPoint(Path.PointAtAltitude(fly_over_alt));
                            }
                            else
                            {
                                SetBrakeEndUT(brake_end_UT);
                            }
                        }
                    }
                    else
                    {
                        SetBrakeEndUT(AerobrakeStartUT);
                    }
                    //update landing site
                    update_landing_site_after_brake();
                }
                else //no brake maneuver
                {
                    SetBrakeEndUT(AerobrakeStartUT);
                    BrakeStartPoint = BrakeEndPoint;
                    BrakeDuration   = 0;
                }
            }
            else
            {
                FlyAbovePoint = Path.FlyAbovePoint(Target.OrbPos(Body));
                if (WillOverheat)
                {
                    SetBrakeEndPoint(Path.PointAtShipTemp(VSL.Physics.MinMaxTemperature - 100));
                }
                else
                {
                    SetBrakeEndPoint(FlyAbovePoint);
                }
                SetBrakeDeltaV(-AtTargetVel - Vector3d.Cross(Body.zUpAngularVelocity, AtTargetPos));
                if (BrakeFuel > 0)
                {
                    var offset = MatchVelocityAutopilot.BrakingOffset((float)BrakeDeltaV.magnitude, VSL, out BrakeDuration);
                    BrakeStartPoint = Path.PointAtUT(Math.Max(BrakeEndPoint.UT - offset, StartUT));
                }
                else
                {
                    SetBrakeEndUT(AerobrakeStartUT);
                    BrakeStartPoint = BrakeStartPoint;
                    BrakeDuration   = 0;
                }
            }
            BrakeOffset = (float)Utils.ClampL(BrakeEndPoint.UT - BrakeStartPoint.UT, 0);
            //compute vessel coordinates at maneuver start
            if (VSL.LandedOrSplashed)
            {
                VslStartLat = Utils.ClampAngle(VSL.vessel.latitude);
                VslStartLon = Utils.ClampAngle(VSL.vessel.longitude);
            }
            else
            {
                var start_pos = (TrajectoryCalculator.BodyRotationAtdT(Body, -TimeToStart) * StartPos).xzy + Body.position;
                VslStartLat = Utils.ClampAngle(Body.GetLatitude(start_pos));
                VslStartLon = Utils.ClampAngle(Body.GetLongitude(start_pos));
            }
            //compute distance to target
            DistanceToTarget   = Target.AngleTo(SurfacePoint) * Body.Radius;
            SurfacePoint.Name += string.Format("\n{0} from target", Utils.formatBigValue((float)DistanceToTarget, "m"));
            //compute distance in lat-lon coordinates
            DeltaLat = Utils.AngleDelta(SurfacePoint.Pos.Lat, Target.Pos.Lat) *
                       Math.Sign(Utils.AngleDelta(approach.Lat, SurfacePoint.Pos.Lat));
            DeltaLon = Utils.AngleDelta(SurfacePoint.Pos.Lon, Target.Pos.Lon) *
                       Math.Sign(Utils.AngleDelta(approach.Lon, SurfacePoint.Pos.Lon));
            //compute distance in radial coordinates
            DeltaFi = 90 - Utils.Angle2(Orbit.GetOrbitNormal(),
                                        TrajectoryCalculator.BodyRotationAtdT(Body, TimeToTarget) * Target.OrbPos(Body));
            DeltaR = Utils.RadDelta(SurfacePoint.AngleTo(VslStartLat, VslStartLon), Target.AngleTo(VslStartLat, VslStartLon)) * Mathf.Rad2Deg;
//            Utils.Log("{}", this);//debug
        }
        protected override void WindowGUI(int windowID)
        {
            GUILayout.BeginVertical();

            List <ManeuverNode> maneuverNodes = GetManeuverNodes();
            bool anyNodeExists = GetManeuverNodes().Any();

            if (anyNodeExists)
            {
                GUILayout.BeginHorizontal();
                if (GUILayout.Button(createNode ? "Create a new" : "Change the last"))
                {
                    createNode = !createNode;
                }
                GUILayout.Label("maneuver node to:");
                GUILayout.EndHorizontal();
            }
            else
            {
                GUILayout.Label("Create a new maneuver node to:");
                createNode = true;
            }

            operationId = GuiUtils.ComboBox.Box(operationId, operationNames, this);

            // Compute orbit and universal time parameters for next maneuver
            double UT = vesselState.time;
            Orbit  o  = orbit;

            if (anyNodeExists)
            {
                if (createNode)
                {
                    ManeuverNode last = maneuverNodes.Last();
                    UT = last.UT;
                    o  = last.nextPatch;
                }
                else if (maneuverNodes.Count() > 1)
                {
                    ManeuverNode last = maneuverNodes[maneuverNodes.Count() - 1];
                    UT = last.UT;
                    o  = last.nextPatch;
                }
            }

            try
            {
                operation[operationId].DoParametersGUI(o, UT, core.target);
            }
            catch (Exception) { } // TODO: Would be better to fix the problem but this will do for now

            if (anyNodeExists)
            {
                GUILayout.Label("after the last maneuver node.");
            }

            bool makingNode    = false;
            bool executingNode = false;

            GUILayout.BeginHorizontal();
            if (GUILayout.Button("Create node"))
            {
                makingNode    = true;
                executingNode = false;
            }
            if (core.node != null && GUILayout.Button("Create and execute"))
            {
                makingNode    = true;
                executingNode = true;
            }
            GUILayout.EndHorizontal();

            if (makingNode)
            {
                var computedNode = operation[operationId].MakeNode(o, UT, core.target);
                if (computedNode != null)
                {
                    if (!createNode)
                    {
                        vessel.patchedConicSolver.RemoveManeuverNode(maneuverNodes.Last());
                    }
                    vessel.PlaceManeuverNode(o, computedNode.dV, computedNode.UT);
                }

                if (executingNode && core.node != null)
                {
                    core.node.ExecuteOneNode(this);
                }
            }

            if (operation[operationId].getErrorMessage().Length > 0)
            {
                GUIStyle s = new GUIStyle(GUI.skin.label);
                s.normal.textColor = Color.yellow;
                GUILayout.Label(operation[operationId].getErrorMessage(), s);
            }

            if (GUILayout.Button("Remove ALL nodes"))
            {
                vessel.RemoveAllManeuverNodes();
            }

            if (core.node != null)
            {
                if (anyNodeExists && !core.node.enabled)
                {
                    if (GUILayout.Button("Execute next node"))
                    {
                        core.node.ExecuteOneNode(this);
                    }

                    if (vessel.patchedConicSolver.maneuverNodes.Count > 1)
                    {
                        if (GUILayout.Button("Execute all nodes"))
                        {
                            core.node.ExecuteAllNodes(this);
                        }
                    }
                }
                else if (core.node.enabled)
                {
                    if (GUILayout.Button("Abort node execution"))
                    {
                        core.node.Abort();
                    }
                }

                GUILayout.BeginHorizontal();
                core.node.autowarp = GUILayout.Toggle(core.node.autowarp, "Auto-warp", GUILayout.ExpandWidth(true));
                GUILayout.Label("Tolerance:", GUILayout.ExpandWidth(false));
                core.node.tolerance.text = GUILayout.TextField(core.node.tolerance.text, GUILayout.Width(35), GUILayout.ExpandWidth(false));
                if (GUILayout.Button("+", GUILayout.ExpandWidth(false)))
                {
                    core.node.tolerance.val += 0.1;
                }
                if (GUILayout.Button("-", GUILayout.ExpandWidth(false)))
                {
                    core.node.tolerance.val -= core.node.tolerance.val > 0.1 ? 0.1 : 0.0;
                }
                if (GUILayout.Button("R", GUILayout.ExpandWidth(false)))
                {
                    core.node.tolerance.val = 0.1;
                }
                GUILayout.Label("m/s", GUILayout.ExpandWidth(false));
                GUILayout.EndHorizontal();
            }

            GUILayout.EndVertical();

            base.WindowGUI(windowID, operation[operationId].draggable);
        }
Beispiel #49
0
 void Start()
 {
     orbit = transform.GetComponent <Orbit>();
 }
        //Estimate the delta-V of the correction burn that would be required to put us on
        //course for the target
        public Vector3d ComputeCourseCorrection(bool allowPrograde)
        {
            //actualLandingPosition is the predicted actual landing position
            Vector3d actualLandingPosition = RotatedLandingSite - mainBody.position;

            //orbitLandingPosition is the point where our current orbit intersects the planet
            double   endRadius            = mainBody.Radius + DecelerationEndAltitude() - 100;
            Vector3d orbitLandingPosition = orbit.SwappedRelativePositionAtUT(orbit.NextTimeOfRadius(vesselState.time, endRadius));

            //convertOrbitToActual is a rotation that rotates orbitLandingPosition on actualLandingPosition
            Quaternion convertOrbitToActual = Quaternion.FromToRotation(orbitLandingPosition, actualLandingPosition);

            //Consider the effect small changes in the velocity in each of these three directions
            Vector3d[] perturbationDirections = { vesselState.velocityVesselSurfaceUnit, vesselState.radialPlusSurface, vesselState.normalPlusSurface };

            //Compute the effect burns in these directions would
            //have on the landing position, where we approximate the landing position as the place
            //the perturbed orbit would intersect the planet.
            Vector3d[] deltas = new Vector3d[3];
            for (int i = 0; i < 3; i++)
            {
                double perturbationDeltaV = 1;                                                                                      //warning: hard experience shows that setting this too low leads to bewildering bugs due to finite precision of Orbit functions
                Orbit  perturbedOrbit     = orbit.PerturbedOrbit(vesselState.time, perturbationDeltaV * perturbationDirections[i]); //compute the perturbed orbit
                double perturbedLandingTime;
                if (perturbedOrbit.PeR < endRadius)
                {
                    perturbedLandingTime = perturbedOrbit.NextTimeOfRadius(vesselState.time, endRadius);
                }
                else
                {
                    perturbedLandingTime = perturbedOrbit.NextPeriapsisTime(vesselState.time);
                }
                Vector3d perturbedLandingPosition = perturbedOrbit.SwappedRelativePositionAtUT(perturbedLandingTime); //find where it hits the planet
                Vector3d landingDelta             = perturbedLandingPosition - orbitLandingPosition;                  //find the difference between that and the original orbit's intersection point
                landingDelta = convertOrbitToActual * landingDelta;                                                   //rotate that difference vector so that we can now think of it as starting at the actual landing position
                landingDelta = Vector3d.Exclude(actualLandingPosition, landingDelta);                                 //project the difference vector onto the plane tangent to the actual landing position
                deltas[i]    = landingDelta / perturbationDeltaV;                                                     //normalize by the delta-V considered, so that deltas now has units of meters per (meter/second) [i.e., seconds]
            }

            //Now deltas stores the predicted offsets in landing position produced by each of the three perturbations.
            //We now figure out the offset we actually want

            //First we compute the target landing position. We have to convert the latitude and longitude of the target
            //into a position. We can't just get the current position of those coordinates, because the planet will
            //rotate during the descent, so we have to account for that.
            Vector3d   desiredLandingPosition         = mainBody.GetRelSurfacePosition(core.target.targetLatitude, core.target.targetLongitude, 0);
            float      bodyRotationAngleDuringDescent = (float)(360 * (prediction.endUT - vesselState.time) / mainBody.rotationPeriod);
            Quaternion bodyRotationDuringFall         = Quaternion.AngleAxis(bodyRotationAngleDuringDescent, mainBody.angularVelocity.normalized);

            desiredLandingPosition = bodyRotationDuringFall * desiredLandingPosition;

            Vector3d desiredDelta = desiredLandingPosition - actualLandingPosition;

            desiredDelta = Vector3d.Exclude(actualLandingPosition, desiredDelta);

            //Now desiredDelta gives the desired change in our actual landing position (projected onto a plane
            //tangent to the actual landing position).

            Vector3d downrangeDirection;
            Vector3d downrangeDelta;

            if (allowPrograde)
            {
                //Construct the linear combination of the prograde and radial+ perturbations
                //that produces the largest effect on the landing position. The Math.Sign is to
                //detect and handle the case where radial+ burns actually bring the landing sign closer
                //(e.g. when we are traveling close to straight up)
                downrangeDirection = (deltas[0].magnitude * perturbationDirections[0]
                                      + Math.Sign(Vector3d.Dot(deltas[0], deltas[1])) * deltas[1].magnitude * perturbationDirections[1]).normalized;

                downrangeDelta = Vector3d.Dot(downrangeDirection, perturbationDirections[0]) * deltas[0]
                                 + Vector3d.Dot(downrangeDirection, perturbationDirections[1]) * deltas[1];
            }
            else
            {
                //If we aren't allowed to burn prograde, downrange component of the landing
                //position has to be controlled by radial+/- burns:
                downrangeDirection = perturbationDirections[1];
                downrangeDelta     = deltas[1];
            }

            //Now solve a 2x2 system of linear equations to determine the linear combination
            //of perturbationDirection01 and normal+ that will give the desired offset in the
            //predicted landing position.
            Matrix2x2 A = new Matrix2x2(
                downrangeDelta.sqrMagnitude, Vector3d.Dot(downrangeDelta, deltas[2]),
                Vector3d.Dot(downrangeDelta, deltas[2]), deltas[2].sqrMagnitude
                );

            Vector2d b = new Vector2d(Vector3d.Dot(desiredDelta, downrangeDelta), Vector3d.Dot(desiredDelta, deltas[2]));

            Vector2d coeffs = A.inverse() * b;

            Vector3d courseCorrection = coeffs.x * downrangeDirection + coeffs.y * perturbationDirections[2];

            return(courseCorrection);
        }
Beispiel #51
0
 /// <summary>
 /// Draws the orbit.
 /// </summary>
 /// <param name="orbit">The orbit.</param>
 /// <param name="color">The color of the created line.</param>
 public static void DrawOrbit(Orbit orbit, Color color)
 {
     DrawOrbit(orbit, color, Style.SOLID);
 }
Beispiel #52
0
 bool OrbitReenters(Orbit initialOrbit)
 {
     return(initialOrbit.PeR < decelRadius || initialOrbit.PeR < aerobrakedRadius);
 }
Beispiel #53
0
        public override void Drive(FlightCtrlState s)
        {
            if (!core.target.NormalTargetExists)
            {
                users.Clear();
                return;
            }

            core.node.autowarp = core.node.autowarp && core.target.Distance > 1000;

            //If we get within the target distance and then next maneuver node is still
            //far in the future, delete it and we will create a new one to match velocities immediately.
            //This can often happen because the target vessel's orbit shifts slightly when it is unpacked.
            if (core.target.Distance < desiredDistance &&
                vessel.patchedConicSolver.maneuverNodes.Count > 0 &&
                vessel.patchedConicSolver.maneuverNodes[0].UT > vesselState.time + 1)
            {
                vessel.RemoveAllManeuverNodes();
            }

            if (vessel.patchedConicSolver.maneuverNodes.Count > 0)
            {
                //If we have plotted a maneuver, execute it.
                if (!core.node.enabled)
                {
                    core.node.ExecuteAllNodes(this);
                }
            }
            else if (core.target.Distance < desiredDistance * 1.05 + 2 &&
                     core.target.RelativeVelocity.magnitude < 1)
            {
                //finished
                users.Clear();
                core.thrust.ThrustOff();
                status = Localizer.Format("#MechJeb_RZauto_statu1");//"Successful rendezvous"
            }
            else if (core.target.Distance < desiredDistance * 1.05 + 2)
            {
                //We are within the target distance: match velocities
                double   UT = vesselState.time;
                Vector3d dV = OrbitalManeuverCalculator.DeltaVToMatchVelocities(orbit, UT, core.target.TargetOrbit);
                vessel.PlaceManeuverNode(orbit, dV, UT);
                status = Localizer.Format("#MechJeb_RZauto_statu2", desiredDistance.ToString());//"Within " +  + "m: matching velocities."
            }
            else if (core.target.Distance < vesselState.radius / 25)
            {
                if (orbit.NextClosestApproachDistance(core.target.TargetOrbit, vesselState.time) < desiredDistance &&
                    orbit.NextClosestApproachTime(core.target.TargetOrbit, vesselState.time) < vesselState.time + 150)
                {
                    //We're close to the target, and on a course that will take us closer. Kill relvel at closest approach
                    double   UT = orbit.NextClosestApproachTime(core.target.TargetOrbit, vesselState.time);
                    Vector3d dV = OrbitalManeuverCalculator.DeltaVToMatchVelocities(orbit, UT, core.target.TargetOrbit);

                    //adjust burn time so as to come to rest at the desired distance from the target:
                    double approachDistance = orbit.Separation(core.target.TargetOrbit, UT);
                    double approachSpeed    = (orbit.SwappedOrbitalVelocityAtUT(UT) - core.target.TargetOrbit.SwappedOrbitalVelocityAtUT(UT)).magnitude;
                    if (approachDistance < desiredDistance)
                    {
                        UT -= Math.Sqrt(Math.Abs(desiredDistance * desiredDistance - approachDistance * approachDistance)) / approachSpeed;
                    }

                    //if coming in hot, stop early to avoid crashing:
                    if (approachSpeed > 10)
                    {
                        UT -= 1;
                    }

                    vessel.PlaceManeuverNode(orbit, dV, UT);

                    status = Localizer.Format("#MechJeb_RZauto_statu3");//"Planning to match velocities at closest approach."
                }
                else
                {
                    //We're not far from the target. Close the distance
                    double closingSpeed = core.target.Distance / 100;
                    if (closingSpeed > maxClosingSpeed)
                    {
                        closingSpeed = maxClosingSpeed;
                    }
                    closingSpeed = Math.Max(0.01, closingSpeed);
                    double closingTime = core.target.Distance / closingSpeed;
                    double UT          = vesselState.time + 15;

                    Vector3d dV = OrbitalManeuverCalculator.DeltaVToInterceptAtTime(orbit, UT, core.target.TargetOrbit, closingTime);
                    vessel.PlaceManeuverNode(orbit, dV, UT);

                    status = Localizer.Format("#MechJeb_RZauto_statu4");//"Close to target: plotting intercept"
                }
            }
            else if (orbit.NextClosestApproachDistance(core.target.TargetOrbit, vesselState.time) < core.target.TargetOrbit.semiMajorAxis / 25)
            {
                //We're not close to the target, but we're on an approximate intercept course.
                //Kill relative velocities at closest approach
                double   UT = orbit.NextClosestApproachTime(core.target.TargetOrbit, vesselState.time);
                Vector3d dV = OrbitalManeuverCalculator.DeltaVToMatchVelocities(orbit, UT, core.target.TargetOrbit);

                //adjust burn time so as to come to rest at the desired distance from the target:
                double approachDistance = (orbit.SwappedAbsolutePositionAtUT(UT) - core.target.TargetOrbit.SwappedAbsolutePositionAtUT(UT)).magnitude;
                double approachSpeed    = (orbit.SwappedOrbitalVelocityAtUT(UT) - core.target.TargetOrbit.SwappedOrbitalVelocityAtUT(UT)).magnitude;
                if (approachDistance < desiredDistance)
                {
                    UT -= Math.Sqrt(Math.Abs(desiredDistance * desiredDistance - approachDistance * approachDistance)) / approachSpeed;
                }

                //if coming in hot, stop early to avoid crashing:
                if (approachSpeed > 10)
                {
                    UT -= 1;
                }

                vessel.PlaceManeuverNode(orbit, dV, UT);

                status = Localizer.Format("#MechJeb_RZauto_statu5");//"On intercept course. Planning to match velocities at closest approach."
            }
            else if (orbit.RelativeInclination(core.target.TargetOrbit) < 0.05 && orbit.eccentricity < 0.05)
            {
                //We're not on an intercept course, but we have a circular orbit in the right plane.

                double   hohmannUT;
                Vector3d hohmannDV = OrbitalManeuverCalculator.DeltaVAndTimeForHohmannTransfer(orbit, core.target.TargetOrbit, vesselState.time, out hohmannUT);

                double numPhasingOrbits = (hohmannUT - vesselState.time) / orbit.period;

                double actualMaxPhasingOrbits = Math.Max(maxPhasingOrbits, 5); // ignore input values that are unreasonably small

                if (numPhasingOrbits < actualMaxPhasingOrbits)
                {
                    //It won't be too long until the intercept window. Plot a Hohmann transfer intercept.
                    vessel.PlaceManeuverNode(orbit, hohmannDV, hohmannUT);

                    status = Localizer.Format("#MechJeb_RZauto_statu6", numPhasingOrbits.ToString("F2"));//"Planning Hohmann transfer for intercept after " +  + " phasing orbits."
                }
                else
                {
                    //We are in a circular orbit in the right plane, but we aren't phasing quickly enough. Move to a better phasing orbit
                    double axisRatio         = Math.Pow(1 + 1.25 / actualMaxPhasingOrbits, 2.0 / 3.0);
                    double lowPhasingRadius  = core.target.TargetOrbit.semiMajorAxis / axisRatio;
                    double highPhasingRadius = core.target.TargetOrbit.semiMajorAxis * axisRatio;

                    bool   useLowPhasingRadius = (lowPhasingRadius > mainBody.Radius + mainBody.RealMaxAtmosphereAltitude() + 3000) && (orbit.semiMajorAxis < core.target.TargetOrbit.semiMajorAxis);
                    double phasingOrbitRadius  = (useLowPhasingRadius ? lowPhasingRadius : highPhasingRadius);

                    if (orbit.ApR < phasingOrbitRadius)
                    {
                        double   UT1 = vesselState.time + 15;
                        Vector3d dV1 = OrbitalManeuverCalculator.DeltaVToChangeApoapsis(orbit, UT1, phasingOrbitRadius);
                        vessel.PlaceManeuverNode(orbit, dV1, UT1);
                        Orbit    transferOrbit = vessel.patchedConicSolver.maneuverNodes[0].nextPatch;
                        double   UT2           = transferOrbit.NextApoapsisTime(UT1);
                        Vector3d dV2           = OrbitalManeuverCalculator.DeltaVToCircularize(transferOrbit, UT2);
                        vessel.PlaceManeuverNode(transferOrbit, dV2, UT2);
                    }
                    else if (orbit.PeR > phasingOrbitRadius)
                    {
                        double   UT1 = vesselState.time + 15;
                        Vector3d dV1 = OrbitalManeuverCalculator.DeltaVToChangePeriapsis(orbit, UT1, phasingOrbitRadius);
                        vessel.PlaceManeuverNode(orbit, dV1, UT1);
                        Orbit    transferOrbit = vessel.patchedConicSolver.maneuverNodes[0].nextPatch;
                        double   UT2           = transferOrbit.NextPeriapsisTime(UT1);
                        Vector3d dV2           = OrbitalManeuverCalculator.DeltaVToCircularize(transferOrbit, UT2);
                        vessel.PlaceManeuverNode(transferOrbit, dV2, UT2);
                    }
                    else
                    {
                        double   UT = orbit.NextTimeOfRadius(vesselState.time, phasingOrbitRadius);
                        Vector3d dV = OrbitalManeuverCalculator.DeltaVToCircularize(orbit, UT);
                        vessel.PlaceManeuverNode(orbit, dV, UT);
                    }

                    status = Localizer.Format("#MechJeb_RZauto_statu7", numPhasingOrbits.ToString("F1"), maxPhasingOrbits.text, MuUtils.ToSI(phasingOrbitRadius - mainBody.Radius, 0));//"Next intercept window would be <<1>> orbits away, which is more than the maximum of <<2>> phasing orbits. Increasing phasing rate by establishing new phasing orbit at <<3>>m
                }
            }
            else if (orbit.RelativeInclination(core.target.TargetOrbit) < 0.05)
            {
                //We're not on an intercept course. We're in the right plane, but our orbit isn't circular. Circularize.

                bool circularizeAtPe;
                if (orbit.eccentricity > 1)
                {
                    circularizeAtPe = true;
                }
                else
                {
                    circularizeAtPe = Math.Abs(orbit.PeR - core.target.TargetOrbit.semiMajorAxis) < Math.Abs(orbit.ApR - core.target.TargetOrbit.semiMajorAxis);
                }

                double UT;
                if (circularizeAtPe)
                {
                    UT = Math.Max(vesselState.time, orbit.NextPeriapsisTime(vesselState.time));
                }
                else
                {
                    UT = orbit.NextApoapsisTime(vesselState.time);
                }

                Vector3d dV = OrbitalManeuverCalculator.DeltaVToCircularize(orbit, UT);
                vessel.PlaceManeuverNode(orbit, dV, UT);

                status = Localizer.Format("#MechJeb_RZauto_statu8");//"Circularizing."
            }
            else
            {
                //We're not on an intercept course, and we're not in the right plane. Match planes
                bool ascending;
                if (orbit.eccentricity < 1)
                {
                    if (orbit.TimeOfAscendingNode(core.target.TargetOrbit, vesselState.time) < orbit.TimeOfDescendingNode(core.target.TargetOrbit, vesselState.time))
                    {
                        ascending = true;
                    }
                    else
                    {
                        ascending = false;
                    }
                }
                else
                {
                    if (orbit.AscendingNodeExists(core.target.TargetOrbit))
                    {
                        ascending = true;
                    }
                    else
                    {
                        ascending = false;
                    }
                }

                double   UT;
                Vector3d dV;
                if (ascending)
                {
                    dV = OrbitalManeuverCalculator.DeltaVAndTimeToMatchPlanesAscending(orbit, core.target.TargetOrbit, vesselState.time, out UT);
                }
                else
                {
                    dV = OrbitalManeuverCalculator.DeltaVAndTimeToMatchPlanesDescending(orbit, core.target.TargetOrbit, vesselState.time, out UT);
                }

                vessel.PlaceManeuverNode(orbit, dV, UT);

                status = Localizer.Format("#MechJeb_RZauto_statu9");//"Matching planes."
            }
        }
Beispiel #54
0
 /// <summary>
 /// Draws the orbit.
 /// </summary>
 /// <param name="orbit">The orbit.</param>
 public static void DrawOrbit(Orbit orbit)
 {
     DrawOrbit(orbit, Color.white, Style.SOLID);
 }
        public static ManeuverParameters ComputeEjectionManeuver(Vector3d exit_velocity, Orbit initial_orbit, double UT_0)
        {
            double GM  = initial_orbit.referenceBody.gravParameter;
            double C3  = exit_velocity.sqrMagnitude;
            double Mh  = initial_orbit.referenceBody.sphereOfInfluence;
            double Rpe = initial_orbit.semiMajorAxis;

            double isma = 2 / Mh - C3 / GM; //inverted Semi-major Axis, will work for parabolic orbit
            double ecc  = 1.0 - Rpe * isma;

            //double vstart = Math.Sqrt(GM * (2 / Rpe - isma)); //{ total start boost}
            //double slat = Rpe * Rpe * vstart * vstart / GM;

            //the problem here should be R for circular orbit instead of Rpe
            double slat = 2 * Rpe - isma * Rpe * Rpe; //but we don't know start point (yet) in elliptic orbit

            double theta = Math.Acos((slat / Mh - 1) / ecc);


            /*
             * //old way infinity hyperbolic:
             * //problems: it's not necessary hyperbolic (in case of low speed exit_velocity),
             * //and exit_velocity appears not infinite far from celestial body, but only sphereOfInfluence far
             * //i.e. Mh in previous statements(theta, isma) is not infinity!
             *
             *          double sma = -GM / C3;
             *
             *          double ecc = 1 - Rpe / sma;
             *          double theta = Math.Acos(-1 / ecc);
             *
             */
            Vector3d intersect_1;
            Vector3d intersect_2;

            // intersect_1 is the optimal position on the orbit assuming the orbit is circular and the sphere of influence is infinite
            IntersectConePlane(exit_velocity, theta, initial_orbit.h, out intersect_1, out intersect_2);

            Vector3d eccvec = initial_orbit.GetEccVector();

            double true_anomaly = AngleAboutAxis(eccvec, intersect_1, initial_orbit.h);
            // GetMeanAnomalyAtTrueAnomaly expects degrees and returns radians
            double mean_anomaly = initial_orbit.GetMeanAnomalyAtTrueAnomaly(true_anomaly * 180 / Math.PI);

            double delta_mean_anomaly = MuUtils.ClampRadiansPi(mean_anomaly - initial_orbit.MeanAnomalyAtUT(UT_0));

            double UT = UT_0 + delta_mean_anomaly / initial_orbit.MeanMotion();

            Vector3d V_0 = initial_orbit.getOrbitalVelocityAtUT(UT);
            Vector3d pos = initial_orbit.getRelativePositionAtUT(UT);

            double final_vel = Math.Sqrt(C3 + 2 * GM / pos.magnitude);

            Vector3d x = pos.normalized;
            Vector3d z = Vector3d.Cross(x, exit_velocity).normalized;
            Vector3d y = Vector3d.Cross(z, x);

            theta = Math.PI / 2;
            double dtheta = 0.001;
            Orbit  sample = new Orbit();

            double theta_err = Double.MaxValue;

            for (int iteration = 0; iteration < 50; ++iteration)
            {
                Vector3d V_1 = final_vel * (Math.Cos(theta) * x + Math.Sin(theta) * y);
                sample.UpdateFromStateVectors(pos, V_1, initial_orbit.referenceBody, UT);
                theta_err = AngleAboutAxis(exit_velocity, sample.getOrbitalVelocityAtUT(OrbitExtensions.NextTimeOfRadius(sample, UT, sample.referenceBody.sphereOfInfluence)), z);
                if (double.IsNaN(theta_err))
                {
                    return(null);
                }
                if (Math.Abs(theta_err) <= Math.PI / 1800)
                {
                    return(new ManeuverParameters((V_1 - V_0).xzy, UT));
                }

                V_1 = final_vel * (Math.Cos(theta + dtheta) * x + Math.Sin(theta + dtheta) * y);
                sample.UpdateFromStateVectors(pos, V_1, initial_orbit.referenceBody, UT);
                double theta_err_2 = AngleAboutAxis(exit_velocity, sample.getOrbitalVelocityAtUT(OrbitExtensions.NextTimeOfRadius(sample, UT, sample.referenceBody.sphereOfInfluence)), z);

                V_1 = final_vel * (Math.Cos(theta - dtheta) * x + Math.Sin(theta - dtheta) * y);
                sample.UpdateFromStateVectors(pos, V_1, initial_orbit.referenceBody, UT);
                double theta_err_3 = AngleAboutAxis(exit_velocity, sample.getOrbitalVelocityAtUT(OrbitExtensions.NextTimeOfRadius(sample, UT, sample.referenceBody.sphereOfInfluence)), z);

                double derr = MuUtils.ClampRadiansPi(theta_err_2 - theta_err_3) / (2 * dtheta);

                theta = MuUtils.ClampRadiansTwoPi(theta - theta_err / derr);

                // if theta > pi, replace with 2pi - theta, the function ejection_angle=f(theta) is symmetrc wrt theta=pi
                if (theta > Math.PI)
                {
                    theta = 2 * Math.PI - theta;
                }
            }

            return(null);
        }
        public static ManeuverParameters OptimizeEjection(ManeuverParameters original_maneuver, Orbit initial_orbit, Orbit target, double UT_arrival, double earliest_UT)
        {
            while (true)
            {
                alglib.minlmstate  state;
                alglib.minlmreport rep;

                double[] x     = new double[4];
                double[] scale = new double[4];

                x[0] = original_maneuver.dV.x;
                x[1] = original_maneuver.dV.y;
                x[2] = original_maneuver.dV.z;
                x[3] = 0;

                scale[0] = scale[1] = scale[2] = original_maneuver.dV.magnitude;
                scale[3] = initial_orbit.period;

                OptimizerData data = new OptimizerData();
                data.initial_orbit = initial_orbit;
                data.original_UT   = original_maneuver.UT;
                data.UT_arrival    = UT_arrival;
                data.pos_arrival   = target.getTruePositionAtUT(UT_arrival);

                alglib.minlmcreatev(4, x, 0.01, out state);
                double epsx = 1e-4;                 // stop if |(x(k+1)-x(k)) ./ scale| <= EpsX
                double epsf = 0.01;                 // stop if |F(k+1)-F(k)| <= EpsF*max{|F(k)|,|F(k+1)|,1}
                alglib.minlmsetcond(state, 0, epsf, epsx, 50);
                alglib.minlmsetscale(state, scale);
                alglib.minlmoptimize(state, DistanceToTarget, null, data);
                alglib.minlmresults(state, out x, out rep);

                Debug.Log("Transfer calculator: termination type=" + rep.terminationtype);
                Debug.Log("Transfer calculator: iteration count=" + rep.iterationscount);

                // try again in one orbit if the maneuver node is in the past
                if (original_maneuver.UT + x[3] < earliest_UT)
                {
                    Debug.Log("Transfer calculator: maneuver is " + (earliest_UT - original_maneuver.UT - x[3]) + " s too early, trying again in " + initial_orbit.period + " s");
                    original_maneuver.UT += initial_orbit.period;
                }
                else
                {
                    return(new ManeuverParameters(new Vector3d(x[0], x[1], x[2]), original_maneuver.UT + x[3]));
                }
            }
        }
Beispiel #57
0
        // Creates a new ship with the given parameters for this mission. The code however seems unnecessarily convoluted and
        // error-prone, but there are no better examples available on the internet.
        private void CreateShip()
        {
            try
            {
                // The ShipConstruct-object can only savely exist while not in flight, otherwise it will spam Null-Pointer Exceptions every tick:
                if (HighLogic.LoadedScene == GameScenes.FLIGHT)
                {
                    throw new Exception("unable to run CreateShip while in flight");
                }

                // Load the parts form the saved vessel:
                if (!File.Exists(shipTemplateFilename))
                {
                    throw new Exception("file '" + shipTemplateFilename + "' not found");
                }
                ShipConstruct shipConstruct = ShipConstruction.LoadShip(shipTemplateFilename);
                ProtoVessel   dummyProto    = new ProtoVessel(new ConfigNode(), null);
                Vessel        dummyVessel   = new Vessel();
                dummyProto.vesselRef = dummyVessel;

                // Maybe adjust the orbit:
                float vesselHeight = Math.Max(Math.Max(shipConstruct.shipSize.x, shipConstruct.shipSize.y), shipConstruct.shipSize.z);
                if (missionType == MissionType.DEPLOY)
                {
                    // Make sure that there won't be any collisions, when the vessel is created at the given orbit:
                    orbit = GUIOrbitEditor.ApplySafetyDistance(orbit, vesselHeight);
                }
                else if (missionType == MissionType.CONSTRUCT)
                {
                    // Deploy the new ship next to the space-dock:
                    Vessel spaceDock = TargetVessel.GetVesselById((Guid)targetVesselId);
                    orbit = GUIOrbitEditor.CreateFollowingOrbit(spaceDock.orbit, TargetVessel.GetVesselSize(spaceDock) + vesselHeight);
                    orbit = GUIOrbitEditor.ApplySafetyDistance(orbit, vesselHeight);
                }
                else
                {
                    throw new Exception("invalid mission-type '" + missionType.ToString() + "'");
                }

                // Instead of loading and constructing the ship ourselfs ShipConstruction.AssembleForLaunch() seems like the better
                // option, this however just seems to work while in flight and even then I was unable to get it working correctly
                // (it switches to the newly created ship and setting an orbit afterwards does not work correctly).

                // In theory it should be enough to simply copy the parts from the ShipConstruct to the ProtoVessel, but
                // this only seems to work when the saved vessel starts with the root-part and is designed top down from there.
                // It seems that the root part has to be the first part in the ProtoVessel's parts-list and all other parts have
                // to be listed in sequence radiating from the root part (eg 1=>2=>R<=3<=4 should be R,2,1,3,4). If the parts
                // are not in the correct order, their rotation seems to get messed up or they are attached to the wrong
                // attachmet-nodes, which is why we have to re-sort the parts with our own logic here.
                // This part of the code is experimental however and only based on my own theories and observations about KSP's vessels.
                Part rootPart = null;
                foreach (Part p in shipConstruct.parts)
                {
                    if (p.parent == null)
                    {
                        rootPart = p; break;
                    }
                }
                List <Part> pList = null;
                dummyVessel.parts = FindAndAddAttachedParts(rootPart, ref pList); // Find all parts which are directly attached to the root-part and add them in order.

                // Handle Subassemblies which are attached by surface attachment-nodes:
                bool handleSurfaceAttachments = true;
                while (dummyVessel.parts.Count < shipConstruct.parts.Count)
                {
                    int processedParts = 0;
                    foreach (Part p in shipConstruct.parts)
                    {
                        if (dummyVessel.parts.Contains(p))
                        {
                            continue;
                        }
                        if (handleSurfaceAttachments)
                        {
                            // Check if the part is attached by a surface-node:
                            if (p.srfAttachNode != null && dummyVessel.parts.Contains(p.srfAttachNode.attachedPart))
                            {
                                // Add this surface attached part and all the sub-parts:
                                dummyVessel.parts = FindAndAddAttachedParts(p, ref dummyVessel.parts);
                                processedParts++;
                            }
                        }
                        else
                        {
                            // Simply copy this part:
                            dummyVessel.parts.Add(p);
                        }
                    }
                    if (processedParts == 0)
                    {
                        // If there are still unprocessed parts, just throw them in the list during the next iteration,
                        // this should not happen but we don't want to end up in an endless loop:
                        handleSurfaceAttachments = false;
                    }
                }

                // Initialize all parts:
                uint missionID      = (uint)Guid.NewGuid().GetHashCode();
                uint launchID       = HighLogic.CurrentGame.launchID++;
                int  maxStageOffset = -1;
                foreach (Part p in dummyVessel.parts)
                {
                    p.flagURL      = flagURL == null ? HighLogic.CurrentGame.flagURL : flagURL;
                    p.missionID    = missionID;
                    p.launchID     = launchID;
                    p.temperature  = 1.0;
                    maxStageOffset = Math.Max(p.stageOffset, maxStageOffset); // stageOffset is offset of this part in the staging-order (0..n with -1 meaning not staged)

                    // Apparently the part's ID from the saved craft is stored in craftID and has to get copied by hand into flightID, which is 0 by default.
                    // If it is not set, docking won't work and since it is referenced by surface-attachments like struts and fuel lines, it should always
                    // be the same as in the stored craft:
                    p.flightID = p.craftID;

                    // If the KRnD-Mod is installed, make sure that all parts of this newly created ship are set to the lates version:
                    foreach (PartModule module in p.Modules)
                    {
                        if (module.moduleName != "KRnDModule")
                        {
                            continue;
                        }
                        Debug.Log("[KSTS] found KRnD on '" + p.name.ToString() + "', setting to latest stats");
                        foreach (BaseField field in module.Fields)
                        {
                            if (field.name.ToString() == "upgradeToLatest")
                            {
                                field.SetValue(1, module); // Newer versions of KRnD use this flag to upgrade all attributes of the given part to the latest levels, when the vessel is activated.
                                if (field.GetValue(module).ToString() != "1")
                                {
                                    Debug.LogError("[KSTS] unable to modify '" + field.name.ToString() + "'");
                                }
                            }
                        }
                    }

                    dummyProto.protoPartSnapshots.Add(new ProtoPartSnapshot(p, dummyProto));
                }

                // Store the parts in Config-Nodes:
                foreach (ProtoPartSnapshot p in dummyProto.protoPartSnapshots)
                {
                    p.storePartRefs();
                }
                List <ConfigNode> partNodesL = new List <ConfigNode>();
                foreach (ProtoPartSnapshot snapShot in dummyProto.protoPartSnapshots)
                {
                    ConfigNode node = new ConfigNode("PART");
                    snapShot.Save(node);
                    partNodesL.Add(node);
                }
                ConfigNode[] partNodes       = partNodesL.ToArray();
                ConfigNode[] additionalNodes = new ConfigNode[0];

                // This will actually create the ship and add it to the global list of flights:
                ConfigNode  protoVesselNode = ProtoVessel.CreateVesselNode(shipName, VesselType.Ship, orbit, 0, partNodes, additionalNodes);
                ProtoVessel pv = HighLogic.CurrentGame.AddVessel(protoVesselNode);
                Debug.Log("[KSTS] deployed new ship '" + shipName.ToString() + "' as '" + pv.vesselRef.id.ToString() + "'");
                ScreenMessages.PostScreenMessage("Vessel '" + shipName.ToString() + "' deployed"); // Popup message to notify the player
                Vessel newVessel = FlightGlobals.Vessels.Find(x => x.id == pv.vesselID);

                // While each part knows in which stage they are, the vessel has to know how many stages there are in total:
                newVessel.protoVessel.stage = maxStageOffset + 1; // an offest of 0 would mean that there is only one stage

                // Maybe add the initial crew to the vessel:
                if (crewToDeliver != null && crewToDeliver.Count > 0 && newVessel != null)
                {
                    foreach (string kerbonautName in crewToDeliver)
                    {
                        TargetVessel.AddCrewMember(newVessel, kerbonautName);
                    }
                }

                // Notify other mods about the new vessel:
                GameEvents.onVesselCreate.Fire(newVessel);
            }
            catch (Exception e)
            {
                Debug.LogError("[KSTS] Mission.CreateShip(): " + e.ToString());
            }
        }
Beispiel #58
0
        public static Mission CreateDeployment(string shipName, ShipTemplate template, Orbit orbit, MissionProfile profile, List <string> crew, string flagURL)
        {
            Mission mission = new Mission();

            mission.missionType          = MissionType.DEPLOY;
            mission.shipTemplateFilename = SanitizePath(template.filename); // The filename contains silly portions like "KSP_x64_Data/..//saves", which break savegames because "//" starts a comment in the savegame ...
            mission.orbit         = orbit;
            mission.shipName      = shipName;
            mission.profileName   = profile.profileName;
            mission.eta           = Planetarium.GetUniversalTime() + profile.missionDuration;
            mission.crewToDeliver = crew; // The crew we want the new vessel to start with.
            mission.flagURL       = flagURL;

            return(mission);
        }
        public Quaternion attitudeGetReferenceRotation(AttitudeReference reference)
        {
            Vector3    fwd, up;
            Quaternion rotRef = Quaternion.identity;

            if (core.target.Target == null && (reference == AttitudeReference.TARGET || reference == AttitudeReference.TARGET_ORIENTATION || reference == AttitudeReference.RELATIVE_VELOCITY))
            {
                attitudeDeactivate();
                return(rotRef);
            }

            if ((reference == AttitudeReference.MANEUVER_NODE) && (vessel.patchedConicSolver.maneuverNodes.Count == 0))
            {
                attitudeDeactivate();
                return(rotRef);
            }

            switch (reference)
            {
            case AttitudeReference.ORBIT:
                rotRef = Quaternion.LookRotation(vesselState.orbitalVelocity.normalized, vesselState.up);
                break;

            case AttitudeReference.ORBIT_HORIZONTAL:
                rotRef = Quaternion.LookRotation(Vector3d.Exclude(vesselState.up, vesselState.orbitalVelocity.normalized), vesselState.up);
                break;

            case AttitudeReference.SURFACE_NORTH:
                rotRef = vesselState.rotationSurface;
                break;

            case AttitudeReference.SURFACE_VELOCITY:
                rotRef = Quaternion.LookRotation(vesselState.surfaceVelocity.normalized, vesselState.up);
                break;

            case AttitudeReference.TARGET:
                fwd = (core.target.Position - vessel.GetTransform().position).normalized;
                up  = Vector3d.Cross(fwd, vesselState.normalPlus);
                Vector3.OrthoNormalize(ref fwd, ref up);
                rotRef = Quaternion.LookRotation(fwd, up);
                break;

            case AttitudeReference.RELATIVE_VELOCITY:
                fwd = core.target.RelativeVelocity.normalized;
                up  = Vector3d.Cross(fwd, vesselState.normalPlus);
                Vector3.OrthoNormalize(ref fwd, ref up);
                rotRef = Quaternion.LookRotation(fwd, up);
                break;

            case AttitudeReference.TARGET_ORIENTATION:
                Transform targetTransform = core.target.Transform;
                if (core.target.CanAlign)
                {
                    rotRef = Quaternion.LookRotation(targetTransform.forward, targetTransform.up);
                }
                else
                {
                    rotRef = Quaternion.LookRotation(targetTransform.up, targetTransform.right);
                }
                break;

            case AttitudeReference.MANEUVER_NODE:
                fwd = vessel.patchedConicSolver.maneuverNodes[0].GetBurnVector(orbit);
                up  = Vector3d.Cross(fwd, vesselState.normalPlus);
                Vector3.OrthoNormalize(ref fwd, ref up);
                rotRef = Quaternion.LookRotation(fwd, up);
                break;

            case AttitudeReference.SUN:
                Orbit baseOrbit = vessel.mainBody == Planetarium.fetch.Sun ? vessel.orbit : orbit.TopParentOrbit();
                up     = vesselState.CoM - Planetarium.fetch.Sun.transform.position;
                fwd    = Vector3d.Cross(-baseOrbit.GetOrbitNormal().xzy.normalized, up);
                rotRef = Quaternion.LookRotation(fwd, up);
                break;

            case AttitudeReference.SURFACE_HORIZONTAL:
                rotRef = Quaternion.LookRotation(Vector3d.Exclude(vesselState.up, vesselState.surfaceVelocity.normalized), vesselState.up);
                break;
            }
            return(rotRef);
        }
Beispiel #60
0
            public override AutopilotStep OnFixedUpdate()
            {
                //if we don't want to deorbit but we're already on a reentry trajectory, we can't wait until the ideal point
                //in the orbit to deorbt; we already have deorbited.
                if (orbit.ApA < mainBody.RealMaxAtmosphereAltitude())
                {
                    core.thrust.targetThrottle = 0;
                    return(new CourseCorrection(core));
                }

                //We aim for a trajectory that
                // a) has the same vertical speed as our current trajectory
                // b) has a horizontal speed that will give it a periapsis of -10% of the body's radius
                // c) has a heading that points toward where the target will be at the end of free-fall, accounting for planetary rotation
                Vector3d   horizontalDV                  = OrbitalManeuverCalculator.DeltaVToChangePeriapsis(orbit, vesselState.time, 0.9 * mainBody.Radius);                //Imagine we are going to deorbit now. Find the burn that would lower our periapsis to -10% of the planet's radius
                Orbit      forwardDeorbitTrajectory      = orbit.PerturbedOrbit(vesselState.time, horizontalDV);                                                             //Compute the orbit that would put us on
                double     freefallTime                  = forwardDeorbitTrajectory.NextTimeOfRadius(vesselState.time, mainBody.Radius) - vesselState.time;                  //Find how long that orbit would take to impact the ground
                double     planetRotationDuringFreefall  = 360 * freefallTime / mainBody.rotationPeriod;                                                                     //Find how many degrees the planet will rotate during that time
                Vector3d   currentTargetRadialVector     = mainBody.GetWorldSurfacePosition(core.target.targetLatitude, core.target.targetLongitude, 0) - mainBody.position; //Find the current vector from the planet center to the target landing site
                Quaternion freefallPlanetRotation        = Quaternion.AngleAxis((float)planetRotationDuringFreefall, mainBody.angularVelocity);                              //Construct a quaternion representing the rotation of the planet found above
                Vector3d   freefallEndTargetRadialVector = freefallPlanetRotation * currentTargetRadialVector;                                                               //Use this quaternion to find what the vector from the planet center to the target will be when we hit the ground
                Vector3d   freefallEndTargetPosition     = mainBody.position + freefallEndTargetRadialVector;                                                                //Then find the actual position of the target at that time
                Vector3d   freefallEndHorizontalToTarget = Vector3d.Exclude(vesselState.up, freefallEndTargetPosition - vesselState.CoM).normalized;                         //Find a horizontal unit vector that points toward where the target will be when we hit the ground
                Vector3d   currentHorizontalVelocity     = Vector3d.Exclude(vesselState.up, vesselState.orbitalVelocity);                                                    //Find our current horizontal velocity
                double     finalHorizontalSpeed          = (currentHorizontalVelocity + horizontalDV).magnitude;                                                             //Find the desired horizontal speed after the deorbit burn
                Vector3d   finalHorizontalVelocity       = finalHorizontalSpeed * freefallEndHorizontalToTarget;                                                             //Combine the desired speed and direction to get the desired velocity after the deorbi burn

                //Compute the angle between the location of the target at the end of freefall and the normal to our orbit:
                Vector3d currentRadialVector      = vesselState.CoM - mainBody.position;
                double   targetAngleToOrbitNormal = Vector3d.Angle(orbit.SwappedOrbitNormal(), freefallEndTargetRadialVector);

                targetAngleToOrbitNormal = Math.Min(targetAngleToOrbitNormal, 180 - targetAngleToOrbitNormal);

                double targetAheadAngle = Vector3d.Angle(currentRadialVector, freefallEndTargetRadialVector);       //How far ahead the target is, in degrees
                double planeChangeAngle = Vector3d.Angle(currentHorizontalVelocity, freefallEndHorizontalToTarget); //The plane change required to get onto the deorbit trajectory, in degrees

                //If the target is basically almost normal to our orbit, it doesn't matter when we deorbit; might as well do it now
                //Otherwise, wait until the target is ahead
                if (targetAngleToOrbitNormal < 10 ||
                    (targetAheadAngle < 90 && targetAheadAngle > 60 && planeChangeAngle < 90))
                {
                    deorbitBurnTriggered = true;
                }

                if (deorbitBurnTriggered)
                {
                    if (!MuUtils.PhysicsRunning())
                    {
                        core.warp.MinimumWarp();
                    }                                                           //get out of warp

                    Vector3d deltaV = finalHorizontalVelocity - currentHorizontalVelocity;
                    core.attitude.attitudeTo(deltaV.normalized, AttitudeReference.INERTIAL, core.landing);

                    if (deltaV.magnitude < 2.0)
                    {
                        return(new CourseCorrection(core));
                    }

                    status = Localizer.Format("#MechJeb_LandingGuidance_Status7");//"Doing high deorbit burn"
                }
                else
                {
                    core.attitude.attitudeTo(Vector3d.back, AttitudeReference.ORBIT, core.landing);
                    if (core.node.autowarp)
                    {
                        core.warp.WarpRegularAtRate((float)(orbit.period / 10));
                    }

                    status = Localizer.Format("#MechJeb_LandingGuidance_Status8");//"Moving to high deorbit burn point"
                }

                return(this);
            }