Example #1
0
        public static Vector3d WorldPositionToGeoCoords(Vector3d worldPosition, CelestialBody body)
        {
            if(!body)
            {
                return Vector3d.zero;
            }

            double lat = body.GetLatitude(worldPosition);
            double longi = body.GetLongitude(worldPosition);
            double alt = body.GetAltitude(worldPosition);
            return new Vector3d(lat,longi,alt);
        }
Example #2
0
 public static DMPRaycastPair RaycastGround(double latitude, double longitude, CelestialBody body)
 {
     //We can only find the ground on bodies that actually *have* ground and if we are in flight near the origin
     if (!HighLogic.LoadedSceneIsFlight || FlightGlobals.fetch.activeVessel == null || body.pqsController == null)
     {
         return new DMPRaycastPair(-1f, Vector3.up);
     }
     //Math functions take radians.
     double latRadians = latitude * Mathf.Deg2Rad;
     double longRadians = longitude * Mathf.Deg2Rad;
     //Radial vector
     Vector3d surfaceRadial = new Vector3d(Math.Cos(latRadians) * Math.Cos(longRadians), Math.Sin(latRadians), Math.Cos(latRadians) * Math.Sin(longRadians));
     double surfaceHeight = body.pqsController.GetSurfaceHeight(surfaceRadial) - body.pqsController.radius;
     Vector3d origin = body.GetWorldSurfacePosition(latitude, longitude, surfaceHeight + 500);
     //Only return the surface if it's really close.
     double highestHit = double.NegativeInfinity;
     Vector3 rotatedVector = Vector3.up;
     if (Vector3d.Distance(FlightGlobals.fetch.activeVessel.GetWorldPos3D(), origin) < 2500)
     {
         //Down vector
         Vector3d downVector = -body.GetSurfaceNVector(latitude, longitude);
         //Magic numbers!
         LayerMask groundMask = 33792;
         RaycastHit[] raycastHits = Physics.RaycastAll(origin, downVector, 1000f, groundMask);
         foreach (RaycastHit raycastHit in raycastHits)
         {
             if (raycastHit.collider == null)
             {
                 //I don't think this is technically possible, but unity's weird enough that we should probably check this anyway.
                 continue;
             }
             if (raycastHit.collider.name == body.name)
             {
                 continue;
             }
             double hitAltitude = body.GetAltitude(raycastHit.point);
             if ((hitAltitude > highestHit) && (!body.ocean || hitAltitude > 0))
             {
                 highestHit = hitAltitude;
                 rotatedVector = Quaternion.Inverse(body.rotation) * raycastHit.normal;
             }
         }
     }
     if (highestHit == double.NegativeInfinity)
     {
         return new DMPRaycastPair(-1f, Vector3.up);
     }
     else
     {
         return new DMPRaycastPair(highestHit, rotatedVector);
     }
 }
Example #3
0
 public static string traceTrans(string prev, Transform tr, CelestialBody body = null)
 {
     string tmp;
     if (body != null)
     {
         tmp = prev + "." + tr.name + " - (" + body.GetLatitude(tr.position) + ", " + body.GetLongitude(tr.position) + ", " + body.GetAltitude(tr.position) + ")\n";
     }
     else
     {
         tmp = prev + "." + tr.name + " - (" + tr.position + ", " + tr.rotation + ")\n";
     }
     Component[] comps = tr.gameObject.GetComponents<Component>();
     foreach (Component comp in comps)
     {
         tmp += "\t" + comp.GetType().Name + " - " + comp.name + "\n";
     }
     for (int i = 0; i < tr.childCount; i++)
     {
         tmp += traceTrans(prev + "." + tr.name, tr.GetChild(i), body);
     }
     return tmp;
 }
Example #4
0
        /// <summary>
        /// Converts world position to Lat,Long,Alt form.
        /// </summary>
        /// <returns>The position in geo coords.</returns>
        /// <param name="worldPosition">World position.</param>
        /// <param name="body">Body.</param>
        public static Vector3d WorldPositionToGeoCoords(Vector3d worldPosition, CelestialBody body)
        {
            if(!body)
            {
                //Debug.Log ("BahaTurret.VectorUtils.WorldPositionToGeoCoords body is null");
                return Vector3d.zero;
            }

            double lat = body.GetLatitude(worldPosition);
            double longi = body.GetLongitude(worldPosition);
            double alt = body.GetAltitude(worldPosition);
            return new Vector3d(lat,longi,alt);
        }
Example #5
0
        Vector3d WorldPositionToGeoCoords(Vector3d worldPosition, CelestialBody body)
        {
            if(!body)
            {
                Debug.LogWarning ("WorldPositionToGeoCoords body is null");
                return Vector3d.zero;
            }

            double lat = body.GetLatitude(worldPosition);
            double longi = body.GetLongitude(worldPosition);
            double alt = body.GetAltitude(worldPosition);
            return new Vector3d(lat,longi,alt);
        }
Example #6
0
            private KSP.UI.Screens.Mapview.MapNode MakePoolNode()
            {
                var new_node = KSP.UI.Screens.Mapview.MapNode.Create(
                    "apsis",
                    // If we see this colour, something has gone wrong.
                    XKCDColors.Pale,
                    pixelSize: 32,
                    hoverable: true,
                    pinnable: true,
                    blocksInput: true);

                new_node.OnClick +=
                    (KSP.UI.Screens.Mapview.MapNode node,
                     Mouse.Buttons buttons) => {
                    if (buttons == Mouse.Buttons.Left)
                    {
                        var properties = properties_[node];
                        if (PlanetariumCamera.fetch.target !=
                            properties_[node].associated_map_object)
                        {
                            PlanetariumCamera.fetch.SetTarget(
                                properties_[node].associated_map_object);
                        }
                    }
                };
                new_node.OnUpdateVisible +=
                    (KSP.UI.Screens.Mapview.MapNode node,
                     KSP.UI.Screens.Mapview.MapNode.IconData icon) => {
                    icon.visible = properties_[node].visible;
                    icon.color   = properties_[node].colour;
                };
                new_node.OnUpdateType +=
                    (KSP.UI.Screens.Mapview.MapNode node,
                     KSP.UI.Screens.Mapview.MapNode.TypeData type) => {
                    var properties = properties_[node];
                    type.oType = properties.object_type;
                    if (properties.object_type == MapObject.ObjectType.PatchTransition)
                    {
                        type.pType =
                            KSP.UI.Screens.Mapview.MapNode.PatchTransitionNodeType.Impact;
                    }
                    else if (properties.object_type ==
                             MapObject.ObjectType.ApproachIntersect)
                    {
                        type.aType = KSP.UI.Screens.Mapview.MapNode.ApproachNodeType
                                     .CloseApproachOwn;
                    }
                };
                new_node.OnUpdateCaption +=
                    (KSP.UI.Screens.Mapview.MapNode node,
                     KSP.UI.Screens.Mapview.MapNode.CaptionData caption) => {
                    var    properties = properties_[node];
                    string source;
                    switch (properties.source)
                    {
                    case NodeSource.FLIGHT_PLAN:
                        source = "Planned";
                        break;

                    case NodeSource.PREDICTION:
                        source = "Predicted";
                        break;

                    default:
                        throw Log.Fatal($"Unexpected node source {properties.source}");
                    }
                    switch (properties.object_type)
                    {
                    case MapObject.ObjectType.Periapsis:
                    case MapObject.ObjectType.Apoapsis: {
                        string apsis_name =
                            properties.object_type == MapObject.ObjectType.Periapsis
                      ? "Periapsis"
                      : "Apoapsis";
                        CelestialBody celestial =
                            properties.reference_frame.selected_celestial;
                        Vector3d position = properties.world_position;
                        double   speed    = properties.velocity.magnitude;
                        caption.Header =
                            $@"{source} {celestial.name} {apsis_name} :\n{
                     celestial.GetAltitude(position):N0} m".ToString(
                                Culture.culture);
                        caption.captionLine2 =
                            $"{speed:N0} m/s".ToString(Culture.culture);
                        break;
                    }

                    case MapObject.ObjectType.AscendingNode:
                    case MapObject.ObjectType.DescendingNode: {
                        string node_name =
                            properties.object_type == MapObject.ObjectType.AscendingNode
                      ? "Ascending Node"
                      : "Descending Node";
                        string plane =
                            properties.reference_frame.ReferencePlaneDescription();
                        caption.Header       = $"{source} {node_name} :\n{plane}";
                        caption.captionLine2 =
                            $"{properties.velocity.z:N0} m/s".ToString(Culture.culture);
                        break;
                    }

                    case MapObject.ObjectType.ApproachIntersect: {
                        Vessel target_vessel = properties.reference_frame.target_override;
                        double separation    = (target_vessel.GetWorldPos3D() -
                                                properties.world_position).magnitude;
                        double speed = properties.velocity.magnitude;
                        caption.Header =
                            $@"{source} Target Approach : {separation:N0} m".ToString(
                                Culture.culture);
                        caption.captionLine2 =
                            $"{speed:N0} m/s".ToString(Culture.culture);
                        break;
                    }

                    case MapObject.ObjectType.PatchTransition: {
                        CelestialBody celestial =
                            properties.reference_frame.selected_celestial;
                        caption.Header       = $"{source} {celestial.name} Impact";
                        caption.captionLine1 = "";
                        caption.captionLine2 = "";
                        break;
                    }
                    }
                    if (properties.object_type != MapObject.ObjectType.PatchTransition)
                    {
                        caption.captionLine1 =
                            "T" + FlightPlanner.FormatTimeSpan(TimeSpan.FromSeconds(
                                                                   Planetarium.GetUniversalTime() - properties.time));
                    }
                };
                new_node.OnUpdatePosition +=
                    (KSP.UI.Screens.Mapview.MapNode node) =>
                    ScaledSpace.LocalToScaledSpace(properties_[node].world_position);
                return(new_node);
            }
Example #7
0
        //This method is called periodically by the main thread,
        //then it decides if it is time to start a new thread or not
        public static void update()
        {
            now = Time.time;
            //double lc = lastCharge;
            //float lt = lastTime;
            //lastTime = now;
            double dt = TimeWarp.fixedDeltaTime;

            //Log.Info("Starting simulation at " + Math.Round(now, 3));
            isReadable = false;
            //Reset some stuff
            ship              = FlightGlobals.ActiveVessel;
            body              = ship.mainBody;
            _gravity          = FlightGlobals.getGeeForceAtPosition(ship.CoM).magnitude;
            _electricCharge   = 0;
            _electricMax      = 0;
            _evamaxfuel       = 0;
            _evafuel          = 0;
            _liquidFuel       = 0;
            _liquidMax        = 0;
            _monoFuel         = 0;
            _monoMax          = 0;
            _airin            = 0;
            _airreq           = 0;
            _mass             = 0;
            _max_thrust       = 0;
            _cur_thrust       = 0;
            _isp              = 0;
            _engineaccel      = 0;
            _enginedecel      = 0;
            _max_temp_percent = 0;
            _max_temp_actual  = 0;
            double _best_temp     = 0;
            double _best_ablation = 0;

            _ablation = 1;
            _tarpos   = new Vector3();


//            int cur_stage = ship.currentStage;
//Log.Info("##########################");
//Log.Info("Current Stage: "+cur_stage);
            //Part loop - look at all the parts and modules for stuff.
            foreach (Part P in ship.parts)
            {
                /*Log.Info("-------------------------------");
                *  Log.Info(P.name);
                *  Log.Info("inStageIndex: " + P.inStageIndex);
                *  Log.Info("inv Stage: " + P.inverseStage);
                *  Log.Info("Manual Stage Offset: " + P.manualStageOffset);
                *  Log.Info("Computed Stage: " + (P.inverseStage + P.manualStageOffset));
                *  Log.Info("Original Stage: " + P.originalStage);
                *  //Log.Info("Stage After: " + P.stageAfter);
                *  //Log.Info("Stage Before: " + P.stageBefore);
                *  Log.Info("Stage Offset: " + P.stageOffset); */

                //Temperature
                //First, look at internal temps
                _best_temp = P.temperature / P.maxTemp;
                if (_best_temp > _max_temp_percent)
                {
                    _max_temp_percent = _best_temp;
                    _max_temp_actual  = P.temperature;
                }
                //Now look at skin temps
                _best_temp = P.skinTemperature / P.skinMaxTemp;
                if (_best_temp > _max_temp_percent)
                {
                    _max_temp_percent = _best_temp;
                    _max_temp_actual  = P.skinTemperature;
                }

                //if (P.temperature/P.maxTemp > .5) Log.Info(P.partInfo.title + " Temp: " + (int)P.temperature + "⁰/" + (int)P.maxTemp + "⁰");



                //Vessel Mass
                if (P.physicalSignificance == Part.PhysicalSignificance.FULL)
                {
                    _mass += P.mass;
                    _mass += P.GetResourceMass();
                }
                //Resource loop
                foreach (PartResource pr in P.Resources)
                {
                    if (pr.resourceName.Equals("ElectricCharge"))
                    {
                        _electricCharge += pr.amount;
                        _electricMax    += pr.maxAmount;
                    }
                    else if (pr.resourceName.Equals("LiquidFuel"))
                    {
                        _liquidFuel += pr.amount;
                        _liquidMax  += pr.maxAmount;
                    }
                    else if (pr.resourceName.Equals("MonoPropellant"))
                    {
                        _monoFuel += pr.amount;
                        _monoMax  += pr.maxAmount;
                    }
                    else if (pr.resourceName.Equals("Ablator"))
                    {
                        _best_ablation = pr.amount / pr.maxAmount;
                        if (_best_ablation < _ablation)
                        {
                            _ablation = _best_ablation;
                        }
                    }
                }
                //Module loop
                foreach (PartModule pm in P.Modules)
                {
                    if (pm is KerbalEVA)
                    {
                        KerbalEVA eva = pm as KerbalEVA;
                        _evafuel    = eva.Fuel;
                        _evamaxfuel = eva.FuelCapacity;
                    }
                    else if (pm is ModuleWheelDeployment)
                    {
                        _gearstate = 0; //Gear up
                        ModuleWheelDeployment mlg = pm as ModuleWheelDeployment;
                        if (mlg.stateString.Equals("Deployed"))
                        {
                            _gearstate = 3;
                        }
                        if (mlg.stateString.StartsWith("Deploying"))
                        {
                            _gearstate = 2;
                        }
                        if (mlg.stateString.StartsWith("Retracting"))
                        {
                            _gearstate = 1;
                        }
                    }
                    else if (pm is ModuleEngines)
                    {
                        ModuleEngines ME = pm as ModuleEngines;
                        if (ME.engineShutdown || !ME.EngineIgnited) //We don't care about engines that aren't ready to fire
                        {
                            continue;
                        }
                        if (1 / ME.engineAccelerationSpeed > _engineaccel)
                        {
                            _engineaccel = 1 / ME.engineAccelerationSpeed;
                        }
                        if (1 / ME.engineDecelerationSpeed > _enginedecel)
                        {
                            _enginedecel = 1 / ME.engineDecelerationSpeed;
                        }
                        //Thrust/ISP
                        float thrust = ME.maxThrust * ME.thrustPercentage * 0.01f;

                        _isp        += thrust / ME.atmosphereCurve.Evaluate((float)ship.staticPressurekPa);
                        _max_thrust += thrust;
                        _cur_thrust += ME.finalThrust;  //I think this is the actual thrust being produced by each engine
                        //Intake Air
                        foreach (Propellant Pro in ME.propellants)
                        {
                            if (Pro.name.Equals("IntakeAir"))
                            {
                                _airreq += Pro.currentRequirement;
                            }
                        }
                        //Overheat stuff
                        //if (!ME.flameout)
                        //{
                        //    double temp = P.temperature / P.maxTemp;
                        //    if (temp > _max_temp) _max_temp = temp;
                        //}
                    }
                    else if (pm is ModuleEnginesFX)  //The newer engines all use this instead of ModuleEngines
                    {
                        ModuleEnginesFX MFX = pm as ModuleEnginesFX;
                        if (MFX.engineShutdown || !MFX.EngineIgnited)
                        {
                            continue;
                        }
                        //Thrust/ISP
                        float thrust = MFX.maxThrust * MFX.thrustPercentage * 0.01f;
                        _isp        += thrust / MFX.atmosphereCurve.Evaluate((float)ship.staticPressurekPa);
                        _max_thrust += thrust;
                        _cur_thrust += MFX.finalThrust;
                        //Overheat stuff
                        //if (!MFX.flameout)
                        //{
                        //    double temp = P.temperature / P.maxTemp;
                        //    if (temp > _max_temp) _max_temp = temp;
                        //}
                        if (1 / MFX.engineAccelerationSpeed > _engineaccel)
                        {
                            _engineaccel = 1 / MFX.engineAccelerationSpeed;
                        }
                        if (1 / MFX.engineDecelerationSpeed > _enginedecel)
                        {
                            _enginedecel = 1 / MFX.engineDecelerationSpeed;
                        }
                        foreach (Propellant Pro in MFX.propellants)
                        {
                            if (Pro.name.Equals("IntakeAir"))
                            {
                                _airreq += Pro.currentRequirement;
                            }
                        }
                    }
                    else if (pm is ModuleResourceIntake)
                    {
                        ModuleResourceIntake MRI = pm as ModuleResourceIntake;
                        if (MRI.intakeEnabled && MRI.resourceName.Equals("IntakeAir"))
                        {
                            _airin += MRI.airFlow * dt; //Using dt courtesy of FAR
                        }
                    }
                }
            }
            _isp = _max_thrust / _isp;    //Complete the average isp

            if (_engineaccel == 0)
            {
                _engineaccel = 2;                       //Default in case the engines don't define it
            }
            //Log.Info("Engine Acceleration: " + Math.Round(_engineaccel, 2));

            //Electric charge rate
            if (now - lastTime > 0.1)
            {
                _chargeRate = (_electricCharge - lastCharge) / (now - lastTime);
                lastCharge  = _electricCharge;
                lastTime    = now;
            }
            //Clamp to +30/-30
            if (_chargeRate > 30)
            {
                _chargeRate = 30;
            }
            if (_chargeRate < -30)
            {
                _chargeRate = -30;
            }

            //Maneuver node burn calculations
            //dv = Isp * ln (m0 / m1)
            //e^(dv/ISP) = m0/m1
            //m1 = m0/e^(dv/ISP)
            //mass flow = thrust/isp
            try
            {
                ManeuverNode myNode    = FlightGlobals.ActiveVessel.patchedConicSolver.maneuverNodes.ToArray()[0];
                double       deltaVRem = myNode.GetBurnVector(ship.orbit).magnitude; //Remaining ΔV in the burn, per maneuver node
                //Log.Info("dV: " + Math.Round(deltaVRem, 1));
                //Log.Info("Mass: " + Math.Round(_mass, 1) + " ISP: " + Math.Round(_isp, 1));
                _final_mass = _mass / Math.Pow(Math.E, (deltaVRem / (_isp * 9.82)));                   //Mass after burn   Changed from 9.821
                //Log.Info("Final Mass: " + Math.Round(_final_mass, 1));
                _mass_rate = _max_thrust / (_isp * 9.82);                                              //Mass flow rate
                //Log.Info("Mass Rate: " + Math.Round(_mass_rate, 3));
                //Log.Info("Burn Mass: " + Math.Round(_mass - _final_mass, 1));
                _burn_time = (_mass - _final_mass);// / _mass_rate;                                         //Time it takes for this burn
                //Log.Info("Burn Mass: " + _burn_time);
                _burn_time = _burn_time / _mass_rate;
                //Log.Info("Burn Time: " + _burn_time);
                _burn_time += 2d;
                //_burn_time += _engineaccel + _enginedecel;                                             //Factor in slow throttles
            }
            catch
            {
                _burn_time  = 0;
                _final_mass = 0;
                _mass_rate  = 0;
            }

            //Heading, courtesy of MechJeb

            /*Vector3d CoM, up, north, east, forward, rootPartPos;
             * Quaternion rotationSurface, rotationVesselSurface;
             * CoM = ship.findWorldCenterOfMass();
             * up = (CoM - body.position).normalized;
             * Rigidbody rigidBody = ship.rootPart.rigidbody;
             * if (rigidBody != null) rootPartPos = rigidBody.position;
             * north = Vector3d.Exclude(up, (body.position + body.transform.up * (float)body.Radius) - CoM).normalized;
             * east = body.getRFrmVel(CoM).normalized;
             * forward = ship.GetTransform().up;
             * rotationSurface = Quaternion.LookRotation(north, up);
             * rotationVesselSurface = Quaternion.Inverse(Quaternion.Euler(90, 0, 0) * Quaternion.Inverse(ship.GetTransform().rotation) * rotationSurface);
             * _heading = rotationVesselSurface.eulerAngles.y; */
            _heading = FlightGlobals.ship_heading;
            //Log.Info("FlightGlobals Heading: " + FlightGlobals.ship_heading + " MechJeb Heading: " + _heading);   //good
            //Log.Info("Ship temp: " + FlightGlobals.ship_temp);    //not useful
            //Log.Info("Get dV: " + FlightGlobals.ActiveVessel.GetDeltaV());    //nothing
            //Log.Info("Surface Height: " + FlightGlobals.ActiveVessel.GetHeightFromSurface() + " Terrain Height: "+FlightGlobals.ActiveVessel.GetHeightFromTerrain()); //not useful
            //Log.Info("GetMass(): " + FlightGlobals.ActiveVessel.GetTotalMass()+" myMass: "+_mass);    //good
            //Log.Info("IAS: " + FlightGlobals.ActiveVessel.indicatedAirSpeed + " M: " + FlightGlobals.ActiveVessel.mach);  //good
            //Waypoint distance code
            //Uses the Spherical Law of Cosines from http://www.movable-type.co.uk/scripts/latlong.html
            NavWaypoint nW = NavWaypoint.fetch; //The active nav waypoint

            FinePrint.WaypointManager WM;
            WM = FinePrint.WaypointManager.Instance();
            if (nW != null && nW.IsActive)
            {
                //Convert these all to radians to do actual math on them.
                double Aa = ship.latitude * Math.PI / 180;
                double Ao = ship.longitude * Math.PI / 180;
                double Ba = nW.Latitude * Math.PI / 180;
                double Bo = nW.Longitude * Math.PI / 180;
                _nav_dist = Math.Acos(Math.Sin(Aa) * Math.Sin(Ba) + Math.Cos(Aa) * Math.Cos(Ba) * Math.Cos(Bo - Ao)) * FlightGlobals.currentMainBody.Radius;  //used to be 600000
                double y = Math.Sin(Bo - Ao) * Math.Cos(Ba);
                double x = Math.Cos(Aa) * Math.Sin(Ba) - Math.Sin(Aa) * Math.Cos(Ba) * Math.Cos(Bo - Ao);
                double b = Math.Atan2(y, x) * 180 / Math.PI; //Converted to degrees.
                _nav_heading = (b + 360f) % 360f;            //Convert to 0-360 from -180 to 180
            }
            else if (_nav_waypoint != 0)
            {
                //defaults
                _nav_heading = -1;
                _nav_dist    = -1;
                //now try actually calculating things
                int count = 0;
                foreach (FinePrint.Waypoint W in WM.Waypoints)
                {
                    //we clearly only care about waypoints on this planet
                    if (W.celestialName.Equals(body.name))
                    {
                        count++;
                        if (count == _nav_waypoint)
                        {
                            //Convert these all to radians to do actual math on them.
                            double Aa = ship.latitude * Math.PI / 180;
                            double Ao = ship.longitude * Math.PI / 180;
                            double Ba = W.latitude * Math.PI / 180;
                            double Bo = W.longitude * Math.PI / 180;
                            _nav_dist = Math.Acos(Math.Sin(Aa) * Math.Sin(Ba) + Math.Cos(Aa) * Math.Cos(Ba) * Math.Cos(Bo - Ao)) * FlightGlobals.currentMainBody.Radius;
                            double y = Math.Sin(Bo - Ao) * Math.Cos(Ba);
                            double x = Math.Cos(Aa) * Math.Sin(Ba) - Math.Sin(Aa) * Math.Cos(Ba) * Math.Cos(Bo - Ao);
                            double b = Math.Atan2(y, x) * 180 / Math.PI; //Converted to degrees.
                            _nav_heading = (b + 360f) % 360f;            //Convert to 0-360 from -180 to 180
                        }
                    }
                }
            }
            else
            {
                _nav_dist    = -1;    //Both of these at -1 implies no nav data
                _nav_heading = -1f;
            }

            //Pitch, yaw, roll

            /*NavBall ball = FlightUIController.fetch.GetComponentInChildren<NavBall>();
             * Quaternion vesselRot = Quaternion.Inverse(ball.relativeGymbal);
             * pitch = (vesselRot.eulerAngles.x > 180) ? (360 - vesselRot.eulerAngles.x) : -vesselRot.eulerAngles.x;
             * roll = (vesselRot.eulerAngles.z > 180) ? (360 - vesselRot.eulerAngles.z) : -vesselRot.eulerAngles.z;
             * yaw = vesselRot.eulerAngles.y;    //Heading, more or less
             * _rel_yaw = AngleAroundNormal(ship.GetObtVelocity(), ship.ReferenceTransform.up, ship.ReferenceTransform.forward);
             * _rel_pitch = AngleAroundNormal(ship.GetObtVelocity(), ship.ReferenceTransform.up, ship.ReferenceTransform.right);
             *
             * //Polars
             * if (pitch > 0f)
             * {
             *  Quaternion polarRot = Quaternion.Euler(90, 0, 0) * vesselRot;
             *  polar_yaw = (polarRot.eulerAngles.y + 180f) % 360f - 180f;
             *  polar_pitch = (polarRot.eulerAngles.x + 180f) % 360f - 180f;
             *  polar_roll = polarRot.eulerAngles.z;
             * }
             * else
             * {
             *  Quaternion polarRot = Quaternion.Euler(-90, 0, 0) * vesselRot;
             *  polar_yaw = (polarRot.eulerAngles.y + 180f) % 360f - 180f;
             *  polar_pitch = (polarRot.eulerAngles.x + 180f) % 360f - 180f;
             *  polar_roll = polarRot.eulerAngles.z;
             * }*/

            //Airspeed stuff
            getAirspeedInfo(ship, out _mach, out _tas, out _eas);

            //Max Altitude
            if (ship.Landed)
            {
                max_altitude = ship.altitude;               //Reset max altitude upon landing/takeoff
            }
            if (ship.altitude > max_altitude)
            {
                max_altitude = ship.altitude;
            }

            //RA
            double terrain = ship.terrainAltitude;

            if (terrain < 0)
            {
                terrain = 0;
            }
            _ra = (long)(body.GetAltitude(ship.CoM) - terrain);

            //In orbit?
            inOrbit = false;
            //Minimum periapsis of 5km
            if (ship.orbit.PeA > 5000)
            {
                //Make sure our orbit is out of the atmosphere, if there is one.
                if (body.atmosphere)
                {
                    if (ship.orbit.PeA > body.atmosphereDepth)  //is this the same as max altitude?
                    {
                        inOrbit = true;
                    }
                }
                else
                {
                    inOrbit = true;
                }
            }

            //Closest approach and time, target distance and speed
            if (FlightGlobals.fetch.VesselTarget != null)
            {
                Orbit    TO   = FlightGlobals.fetch.VesselTarget.GetOrbit();
                Vector3d aPos = ship.ReferenceTransform.position;                                   //Control source's position
                Vector3d tPos = _tarpos = FlightGlobals.fetch.VesselTarget.GetTransform().position; //Rough distance
                if (FlightGlobals.fetch.VesselTarget is ModuleDockingNode)                          //Use more precise distance
                {
                    ModuleDockingNode targetDockingPort = FlightGlobals.fetch.VesselTarget as ModuleDockingNode;
                    tPos = _tarpos = targetDockingPort.controlTransform.position;
                }
                // MechJeb guidance targets _don't have an orbit_!
                else if (TO != null)
                {
                    // This is in the wrong coordinate system for _tarpos, and only usable for distance
                    aPos = ship.GetOrbit().pos;
                    tPos = TO.pos;
                }
                _target_dist = Vector3d.Distance(aPos, tPos);
            }
            else
            {
                _target_dist = 0;
            }

            var target = FlightGlobals.fetch.VesselTarget;

            // MechJeb guidance targets _don't have an orbit!
            // Also, landed targets often have invalid orbit that causes error spam and lag.
            if (target != null && target.GetOrbit() != null)
            {
                Orbit O  = ship.GetOrbit();
                Orbit TO = target.GetOrbit();

                double t = Planetarium.GetUniversalTime();
                Func <double, Vector3d> targetPosAt = (d => TO.getPositionAtUT(t + d));

                // For landed targets the orbit doesn't make sense, so calculate planet rotation
                if (target.GetVessel() != null && target.GetVessel().LandedOrSplashed)
                {
                    Vessel        ves   = target.GetVessel();
                    CelestialBody vbody = ves.mainBody;
                    Vector3d      pos   = vbody.GetRelSurfacePosition(ves.latitude, ves.longitude, ves.altitude);

                    targetPosAt = delegate(double d) {
                        double angle = vbody.rotates ? d * 360.0 / vbody.rotationPeriod : 0;
                        return(vbody.position + QuaternionD.AngleAxis(angle, Vector3d.down) * pos);
                    };
                }

                //I chunck my orbit into 100 pieces, and find between which two chuncks the minimum occurs...
                double period   = O.period;
                double bestDist = double.MaxValue;
                double bestTime = 0;

                for (double d = 0; d < period; d += period / 100)    //Look at 100 places around the orbit
                {
                    if (d == 0)
                    {
                        continue;           //skip the first time
                    }
                    double dist = Vector3d.Distance(O.getPositionAtUT(t + d), targetPosAt(d));
                    if (dist < bestDist)
                    {
                        bestDist = dist;
                        bestTime = d;
                    }
                }
                //Now, do it again, but over a small section of the orbit centered on the above
                double start = bestTime - (period / 100);
                double end   = bestTime + (period / 100);
                for (double d = start; d < end; d += period / 1000)    //Look at 100 places within this chunck of orbit
                {
                    if (d == start)
                    {
                        continue;               //Skip the first time
                    }
                    double dist = Vector3d.Distance(O.getPositionAtUT(t + d), targetPosAt(d));
                    if (dist < bestDist)
                    {
                        bestDist = dist;
                        bestTime = d;
                    }
                }
                //And one last time, which is probably overkill
                start = bestTime - (period / 1000);
                end   = bestTime + (period / 1000);
                for (double d = start; d < end; d += period / 10000)    //Look at 100 places within this chunck of orbit
                {
                    if (d == start)
                    {
                        continue;               //For ease of computation
                    }
                    double dist = Vector3d.Distance(O.getPositionAtUT(t + d), targetPosAt(d));
                    if (dist < bestDist)
                    {
                        bestDist = dist;
                        bestTime = d;   //previous time is my start time
                    }
                }
                _closest_time     = bestTime;
                _closest_approach = bestDist;
            }
            else
            {
                _closest_approach = 0;
                _closest_time     = 0;
            }

            //Time to Impact calculations
            double vertspeed = FlightGlobals.ActiveVessel.verticalSpeed;

            if (!ship.Landed && vertspeed < 0 && ship.orbit.PeA <= 0 && !ship.mainBody.atmosphere)
            {
                double Vf = Math.Sqrt((vertspeed * vertspeed) + 2 * _ra * _gravity);
                //t = 2d/(Vi+Vf)
                _tti = (Math.Abs(Vf) - Math.Abs(vertspeed)) / _gravity;
                _tti++;  //So you hit the ground at 0, not 1 second after 0
            }
            else
            {
                _tti = 0;
            }
            //Suicide Altitude calculations
            if (ship.Landed || ship.orbit.PeA > 0 || body.atmosphere)
            {
                _sa = -1;  //Not calculating this
            }
            else
            {
                _sa = 0;
                double avgG = body.gravParameter / ((body.Radius + ship.terrainAltitude) * (body.Radius + ship.terrainAltitude));
                avgG += FlightGlobals.getGeeForceAtPosition(ship.CoM).magnitude;
                avgG /= 2;
                //Log.Info("Average G: " + Math.Round(avgG, 2));
                double vdv = Math.Sqrt((2 * avgG * _ra) + (ship.verticalSpeed * ship.verticalSpeed));
                //Log.Info("Vertical Delta V: " + Math.Round(vdv, 1));
                //Altitude Fraction = (Vertical dv ^2) / (2 * 1000 * Thrust (kN))
                double altFrac = (vdv * vdv) / (2 * 1000 * _max_thrust);
                //Log.Info("Altitude Fraction: " + Math.Round(altFrac, 2));
                //m-avg = (m0 + (m0 / e ^ (dv / (Isp * 9.82)))) / 2
                double avgMass = (_mass / Math.Pow(Math.E, (vdv / (_isp * 9.82))));
                avgMass = (_mass + avgMass) / 2;
                //Log.Info("Average mass: " + Math.Round(avgMass, 1));
                _sa = (long)Math.Round(altFrac * avgMass * 1000);
                //Log.Info("Suicide Altitude: " + Math.Round(_sa));
            }

            //Cleanup
            isReadable = true;
            //Log.Info("Thread simulation complete at " + Math.Round(Time.time, 3));
        }
Example #8
0
    public static string traceTrans(string prev, Transform tr, CelestialBody body = null)
    {
        string tmp;

        if (body != null)
        {
            tmp = prev + "." + tr.name + " - (" + body.GetLatitude(tr.position) + ", " + body.GetLongitude(tr.position) + ", " + body.GetAltitude(tr.position) + ")\n";
        }
        else
        {
            tmp = prev + "." + tr.name + " - (" + tr.position + ", " + tr.rotation + ")\n";
        }
        Component[] comps = tr.gameObject.GetComponents <Component>();
        foreach (Component comp in comps)
        {
            tmp += "\t" + comp.GetType().Name + " - " + comp.name + "\n";
        }
        for (int i = 0; i < tr.childCount; i++)
        {
            tmp += traceTrans(prev + "." + tr.name, tr.GetChild(i), body);
        }
        return(tmp);
    }