Example #1
0
        private void UpdateMove()
        {
            if (!MovingVessel)
            {
//                EndMove();
                return;
            }
            MovingVessel.IgnoreGForces(240);

            // Lerp is animating move
            if (!_hoverChanged)
            {
                MoveHeight = Mathf.Lerp(MoveHeight, _vBounds.BottomLength + HoverHeight, 10 * Time.fixedDeltaTime);
            }
            else
            {
                double alt = MovingVessel.radarAltitude;
                // sINCE Lerp is animating move from 0 to hoverheight, we do not want this going below current altitude
                if (MoveHeight < alt)
                {
                    MoveHeight = Convert.ToSingle(alt);
                }

                MoveHeight = MovingVessel.Splashed
                  ? Mathf.Lerp(MoveHeight, _vBounds.BottomLength + _hoverAdjust, 10 * Time.fixedDeltaTime)
                  : Mathf.Lerp(MoveHeight, _vBounds.BottomLength + (MoveHeight + _hoverAdjust < 0 ? -MoveHeight : _hoverAdjust), 10 * Time.fixedDeltaTime);
            }
            MovingVessel.ActionGroups.SetGroup(KSPActionGroup.RCS, false);

            _up = (MovingVessel.transform.position - FlightGlobals.currentMainBody.transform.position).normalized;

            Vector3 forward;

            if (MapView.MapIsEnabled)
            {
                forward = North();
            }
            else
            {
                forward = Vector3.ProjectOnPlane(MovingVessel.CoM - FlightCamera.fetch.mainCamera.transform.position, _up).normalized;
                if (Vector3.Dot(-_up, FlightCamera.fetch.mainCamera.transform.up) > 0)
                {
                    forward = Vector3.ProjectOnPlane(FlightCamera.fetch.mainCamera.transform.up, _up).normalized;
                }
            }

            Vector3 right = Vector3.Cross(_up, forward);

            Vector3 offsetDirection = Vector3.zero;
            bool    inputting       = false;

            //auto level plane
            if (GameSettings.TRANSLATE_FWD.GetKey())
            {
                Quaternion targetRot = Quaternion.LookRotation(-_up, forward);
                _startRotation = Quaternion.RotateTowards(_startRotation, targetRot, RotationSpeed * 2);
                _hasRotated    = true;
            }
            else if (GameSettings.TRANSLATE_BACK.GetKey())//auto level rocket
            {
                Quaternion targetRot = Quaternion.LookRotation(forward, _up);
                _startRotation = Quaternion.RotateTowards(_startRotation, targetRot, RotationSpeed * 2);
                _hasRotated    = true;
            }

            if (inputting)
            {
                _currMoveSpeed = Mathf.Clamp(Mathf.MoveTowards(_currMoveSpeed, MoveSpeed, MoveAccel * Time.fixedDeltaTime), 0, MoveSpeed);
            }
            else
            {
                _currMoveSpeed = 0;
            }

            Vector3 offset = offsetDirection.normalized * _currMoveSpeed;

            _currMoveVelocity = offset / Time.fixedDeltaTime;
            Vector3    vSrfPt        = MovingVessel.CoM - (MoveHeight * _up);
            bool       srfBelowWater = false;
            RaycastHit ringHit;

            bool    surfaceDetected = CapsuleCast(out ringHit);
            Vector3 finalOffset     = Vector3.zero;

            if (surfaceDetected)
            {
                if (FlightGlobals.getAltitudeAtPos(ringHit.point) < 0)
                {
                    srfBelowWater = true;
                }

                Vector3 rOffset = Vector3.Project(ringHit.point - vSrfPt, _up);
                Vector3 mOffset = (vSrfPt + offset) - MovingVessel.CoM;
                finalOffset = rOffset + mOffset + (MoveHeight * _up);
                MovingVessel.Translate(finalOffset);
            }

            PQS bodyPQS = MovingVessel.mainBody.pqsController;

            Vector3d geoCoords = WorldPositionToGeoCoords(MovingVessel.GetWorldPos3D() + (_currMoveVelocity * Time.fixedDeltaTime), MovingVessel.mainBody);
            double   lat       = geoCoords.x;
            double   lng       = geoCoords.y;

            Vector3d bodyUpVector = new Vector3d(1, 0, 0);

            bodyUpVector = QuaternionD.AngleAxis(lat, Vector3d.forward /*around Z axis*/) * bodyUpVector;
            bodyUpVector = QuaternionD.AngleAxis(lng, Vector3d.down /*around -Y axis*/) * bodyUpVector;

            double srfHeight = bodyPQS.GetSurfaceHeight(bodyUpVector);

            if (!surfaceDetected || srfBelowWater)
            {
                Vector3 terrainPos    = MovingVessel.mainBody.position + (float)srfHeight * _up;
                Vector3 waterSrfPoint = FlightGlobals.currentMainBody.position + ((float)FlightGlobals.currentMainBody.Radius * _up);

                if (!surfaceDetected)
                {
                    MovingVessel.SetPosition(terrainPos + (MoveHeight * _up) + offset);
                }
                else
                {
                    MovingVessel.SetPosition(waterSrfPoint + (MoveHeight * _up) + offset);
                }

                //update vessel situation to splashed down:
                //MovingVessel.UpdateLandedSplashed();
            }

            //fix surface rotation
            Quaternion srfRotFix = Quaternion.FromToRotation(_startingUp, _up);

            _currRotation = srfRotFix * _startRotation;
            MovingVessel.SetRotation(_currRotation);

            if (Vector3.Angle(_startingUp, _up) > 5)
            {
                _startRotation = _currRotation;
                _startingUp    = _up;
            }

            MovingVessel.SetWorldVelocity(Vector3d.zero);
            MovingVessel.angularVelocity = Vector3.zero;
            MovingVessel.angularMomentum = Vector3.zero;
        }
            public static IEnumerator UpdateTextures(CelestialBody celestialBody, TextureOptions options)
            {
                // Get time
                DateTime now = DateTime.Now;

                // If the user wants to export normals, we need height too
                if (options.ExportNormal)
                {
                    options.ExportHeight = true;
                }

                // Prepare the PQS
                PQS pqsVersion = celestialBody.pqsController;

                // If the PQS is null, abort
                if (pqsVersion == null)
                {
                    yield break;
                }

                // Tell the PQS that we are going to build maps
                pqsVersion.SetupExternalRender();

                // Get the mod building methods from the PQS
                #if !KSP131
                Action <PQS.VertexBuildData, Boolean> modOnVertexBuildHeight =
                    (Action <PQS.VertexBuildData, Boolean>)Delegate.CreateDelegate(
                        typeof(Action <PQS.VertexBuildData, Boolean>),
                        pqsVersion,
                        typeof(PQS).GetMethod("Mod_OnVertexBuildHeight",
                                              BindingFlags.Instance | BindingFlags.NonPublic));
                #else
                Action <PQS.VertexBuildData> modOnVertexBuildHeight =
                    (Action <PQS.VertexBuildData>)Delegate.CreateDelegate(
                        typeof(Action <PQS.VertexBuildData>),
                        pqsVersion,
                        typeof(PQS).GetMethod("Mod_OnVertexBuildHeight",
                                              BindingFlags.Instance | BindingFlags.NonPublic));
                #endif
                Action <PQS.VertexBuildData> modOnVertexBuild = (Action <PQS.VertexBuildData>)Delegate.CreateDelegate(
                    typeof(Action <PQS.VertexBuildData>),
                    pqsVersion,
                    typeof(PQS).GetMethod("Mod_OnVertexBuild", BindingFlags.Instance | BindingFlags.NonPublic));

                // Get all mods the PQS is connected to
                PQSMod[] mods = pqsVersion.GetComponentsInChildren <PQSMod>()
                                .Where(m => m.sphere == pqsVersion && m.modEnabled).OrderBy(m => m.order).ToArray();

                // Prevent the PQS from updating
                pqsVersion.enabled = false;

                // Create the Textures
                Texture2D colorMap = new Texture2D(options.Resolution, options.Resolution / 2,
                                                   TextureFormat.ARGB32,
                                                   true);
                Texture2D heightMap = new Texture2D(options.Resolution, options.Resolution / 2,
                                                    TextureFormat.RGB24,
                                                    true);

                // Arrays
                Color[] colorMapValues  = new Color[options.Resolution * (options.Resolution / 2)];
                Color[] heightMapValues = new Color[options.Resolution * (options.Resolution / 2)];

                // Create a VertexBuildData
                PQS.VertexBuildData data = new PQS.VertexBuildData();

                // Display
                ScreenMessage message = ScreenMessages.PostScreenMessage("Generating Planet-Maps", Single.MaxValue, ScreenMessageStyle.UPPER_CENTER);
                yield return(null);

                // Loop through the pixels
                for (Int32 y = 0; y < options.Resolution / 2; y++)
                {
                    for (Int32 x = 0; x < options.Resolution; x++)
                    {
                        // Update Message
                        Double percent = (Double)(y * options.Resolution + x) /
                                         (options.Resolution / 2 * options.Resolution) * 100;
                        while (CanvasUpdateRegistry.IsRebuildingLayout())
                        {
                            Thread.Sleep(10);
                        }
                        message.textInstance.text.text = "Generating Planet-Maps: " + percent.ToString("0.00") + "%";

                        // Update the VertexBuildData
                        data.directionFromCenter =
                            QuaternionD.AngleAxis(360d / options.Resolution * x, Vector3d.up) *
                            QuaternionD.AngleAxis(90d - 180d / (options.Resolution / 2f) * y, Vector3d.right)
                            * Vector3d.forward;
                        data.vertHeight = pqsVersion.radius;

                        // Build from the Mods
                        Double height = Double.MinValue;
                        if (options.ExportHeight)
                        {
                            #if !KSP131
                            modOnVertexBuildHeight(data, true);
                            #else
                            modOnVertexBuildHeight(data);
                            #endif

                            // Adjust the height
                            height = (data.vertHeight - pqsVersion.radius) * (1d / pqsVersion.radiusDelta);
                            if (height < 0)
                            {
                                height = 0;
                            }
                            else if (height > 1)
                            {
                                height = 1;
                            }

                            // Set the Pixels
                            heightMapValues[y * options.Resolution + x] =
                                new Color((Single)height, (Single)height, (Single)height);
                        }

                        if (options.ExportColor)
                        {
                            modOnVertexBuild(data);

                            // Adjust the Color
                            Color color = data.vertColor;
                            if (!pqsVersion.mapOcean)
                            {
                                color.a = 1f;
                            }
                            else if (height > pqsVersion.mapOceanHeight)
                            {
                                color.a = options.TransparentMaps ? 0f : 1f;
                            }
                            else
                            {
                                color = pqsVersion.mapOceanColor.A(1f);
                            }

                            // Set the Pixels
                            colorMapValues[y * options.Resolution + x] = color;
                        }
                    }

                    yield return(null);
                }

                // Serialize the maps to disk
                String name = "KittopiaTech/PluginData/" + celestialBody.transform.name + "/" + DateTime.Now.ToString("yyyy-MM-dd_hh-mm-ss") + "/";
                String path = KSPUtil.ApplicationRootPath + "/GameData/" + name;
                Directory.CreateDirectory(path);

                // Colormap
                if (options.ExportColor)
                {
                    // Save it
                    colorMap.SetPixels(colorMapValues);
                    yield return(null);

                    if (options.SaveToDisk)
                    {
                        File.WriteAllBytes(path + celestialBody.transform.name + "_Color.png", colorMap.EncodeToPNG());
                        colorMap.name = name + celestialBody.transform.name + "_Color.png";
                        yield return(null);
                    }

                    // Apply it
                    if (options.ApplyToScaled)
                    {
                        colorMap.Apply();
                        ScaledSpaceOnDemand od = celestialBody.scaledBody.GetComponent <ScaledSpaceOnDemand>();
                        if (od != null)
                        {
                            od.texture = colorMap.name;
                            UnityEngine.Object.DestroyImmediate(colorMap);

                            if (od.isLoaded)
                            {
                                od.UnloadTextures();
                                od.LoadTextures();
                            }
                        }
                        else
                        {
                            celestialBody.scaledBody.GetComponent <MeshRenderer>().sharedMaterial.SetTexture("_MainTex", colorMap);
                        }
                    }
                    else
                    {
                        UnityEngine.Object.DestroyImmediate(colorMap);
                    }
                }

                if (options.ExportHeight)
                {
                    heightMap.SetPixels(heightMapValues);
                    yield return(null);

                    if (options.SaveToDisk)
                    {
                        File.WriteAllBytes(path + celestialBody.transform.name + "_Height.png",
                                           heightMap.EncodeToPNG());
                        yield return(null);
                    }

                    if (options.ExportNormal)
                    {
                        // Bump to Normal Map
                        Texture2D normalMap = Utility.BumpToNormalMap(heightMap, pqsVersion, options.NormalStrength / 10);
                        yield return(null);

                        if (options.SaveToDisk)
                        {
                            File.WriteAllBytes(path + celestialBody.transform.name + "_Normal.png",
                                               normalMap.EncodeToPNG());
                            normalMap.name = name + celestialBody.transform.name + "_Normal.png";
                            yield return(null);
                        }

                        // Apply it
                        if (options.ApplyToScaled)
                        {
                            normalMap.Apply();
                            ScaledSpaceOnDemand od = celestialBody.scaledBody.GetComponent <ScaledSpaceOnDemand>();
                            if (od != null)
                            {
                                od.normals = normalMap.name;
                                UnityEngine.Object.DestroyImmediate(normalMap);

                                if (od.isLoaded)
                                {
                                    od.UnloadTextures();
                                    od.LoadTextures();
                                }
                            }
                            else
                            {
                                celestialBody.scaledBody.GetComponent <MeshRenderer>().sharedMaterial
                                .SetTexture("_BumpMap", normalMap);
                            }
                        }
                        else
                        {
                            UnityEngine.Object.DestroyImmediate(normalMap);
                        }
                    }

                    UnityEngine.Object.DestroyImmediate(heightMap);
                }

                // Close the Renderer
                pqsVersion.enabled = true;
                pqsVersion.CloseExternalRender();

                // Declare that we're done
                ScreenMessages.RemoveMessage(message);
                ScreenMessages.PostScreenMessage("Operation completed in: " + (DateTime.Now - now).TotalMilliseconds + " ms", 2f, ScreenMessageStyle.UPPER_CENTER);
            }
Example #3
0
        public static void DrawGroundMarker(CelestialBody body, double latitude, double longitude, Color c, bool map, double rotation = 0, double radius = 0)
        {
            Vector3d up     = body.GetSurfaceNVector(latitude, longitude);
            var      height = body.pqsController.GetSurfaceHeight(QuaternionD.AngleAxis(longitude, Vector3d.down) * QuaternionD.AngleAxis(latitude, Vector3d.forward) * Vector3d.right);

            if (height < body.Radius)
            {
                height = body.Radius;
            }
            Vector3d center = body.position + height * up;

            Vector3d camPos = map ? ScaledSpace.ScaledToLocalSpace(PlanetariumCamera.Camera.transform.position) : (Vector3d)FlightCamera.fetch.mainCamera.transform.position;

            if (IsOccluded(center, body, camPos))
            {
                return;
            }

            Vector3d north = Vector3d.Exclude(up, body.transform.up).normalized;

            if (radius <= 0)
            {
                radius = map ? body.Radius / 15 : 5;
            }

            if (!map)
            {
                Vector3 centerPoint = FlightCamera.fetch.mainCamera.WorldToViewportPoint(center);
                if (centerPoint.z < 0)
                {
                    return;
                }
            }

            GLTriangle(
                center,
                center + radius * (QuaternionD.AngleAxis(rotation - 10, up) * north),
                center + radius * (QuaternionD.AngleAxis(rotation + 10, up) * north)
                , c, map);

            GLTriangle(
                center,
                center + radius * (QuaternionD.AngleAxis(rotation + 110, up) * north),
                center + radius * (QuaternionD.AngleAxis(rotation + 130, up) * north)
                , c, map);

            GLTriangle(
                center,
                center + radius * (QuaternionD.AngleAxis(rotation - 110, up) * north),
                center + radius * (QuaternionD.AngleAxis(rotation - 130, up) * north)
                , c, map);
        }
Example #4
0
        public void Update()
        {
            this.impactHappening = false;

            if (FlightGlobals.ActiveVessel.mainBody.pqsController != null)
            {
                //do impact site calculations
                this.impactHappening = true;
                this.impactTime      = 0;
                this.impactLongitude = 0;
                this.impactLatitude  = 0;
                this.impactAltitude  = 0;
                var e = FlightGlobals.ActiveVessel.orbit.eccentricity;
                //get current position direction vector
                var currentpos = this.RadiusDirection(FlightGlobals.ActiveVessel.orbit.trueAnomaly * Units.RAD_TO_DEG);
                //calculate longitude in inertial reference frame from that
                var currentirflong = 180 * Math.Atan2(currentpos.x, currentpos.y) / Math.PI;

                //experimentally determined; even for very flat trajectories, the errors go into the sub-millimeter area after 5 iterations or so
                const int impactiterations = 6;

                //do a few iterations of impact site calculations
                for (var i = 0; i < impactiterations; i++)
                {
                    if (FlightGlobals.ActiveVessel.orbit.PeA >= this.impactAltitude)
                    {
                        //periapsis must be lower than impact alt
                        this.impactHappening = false;
                    }
                    if ((FlightGlobals.ActiveVessel.orbit.eccentricity < 1) && (FlightGlobals.ActiveVessel.orbit.ApA <= this.impactAltitude))
                    {
                        //apoapsis must be higher than impact alt
                        this.impactHappening = false;
                    }
                    if ((FlightGlobals.ActiveVessel.orbit.eccentricity >= 1) && (FlightGlobals.ActiveVessel.orbit.timeToPe <= 0))
                    {
                        //if currently escaping, we still need to be before periapsis
                        this.impactHappening = false;
                    }
                    if (!this.impactHappening)
                    {
                        this.impactTime      = 0;
                        this.impactLongitude = 0;
                        this.impactLatitude  = 0;
                        this.impactAltitude  = 0;
                        break;
                    }

                    double impacttheta = 0;
                    if (e > 0)
                    {
                        //in this step, we are using the calculated impact altitude of the last step, to refine the impact site position
                        double costheta = (FlightGlobals.ActiveVessel.orbit.PeR * (1 + e) / (FlightGlobals.ActiveVessel.mainBody.Radius + this.impactAltitude) - 1) / e;
                        if (costheta < -1d)
                        {
                            costheta = -1d;
                        }
                        else if (costheta > 1d)
                        {
                            costheta = 1d;
                        }
                        impacttheta = -180 * Math.Acos(costheta) / Math.PI;
                    }

                    //calculate time to impact
                    this.impactTime = FlightGlobals.ActiveVessel.orbit.timeToPe - this.TimeToPeriapsis(impacttheta);
                    //calculate position vector of impact site
                    var impactpos = this.RadiusDirection(impacttheta);
                    //calculate longitude of impact site in inertial reference frame
                    var impactirflong = 180 * Math.Atan2(impactpos.x, impactpos.y) / Math.PI;
                    var deltairflong  = impactirflong - currentirflong;
                    //get body rotation until impact
                    var bodyrot = 360 * this.impactTime / FlightGlobals.ActiveVessel.mainBody.rotationPeriod;
                    //get current longitude in body coordinates
                    var currentlong = FlightGlobals.ActiveVessel.longitude;
                    //finally, calculate the impact longitude in body coordinates
                    this.impactLongitude = this.NormAngle(currentlong - deltairflong - bodyrot);
                    //calculate impact latitude from impact position
                    this.impactLatitude = 180 * Math.Asin(impactpos.z / impactpos.magnitude) / Math.PI;
                    //calculate the actual altitude of the impact site
                    //altitude for long/lat code stolen from some ISA MapSat forum post; who knows why this works, but it seems to.
                    var rad = QuaternionD.AngleAxis(this.impactLongitude, Vector3d.down) * QuaternionD.AngleAxis(this.impactLatitude, Vector3d.forward) * Vector3d.right;
                    this.impactAltitude = FlightGlobals.ActiveVessel.mainBody.pqsController.GetSurfaceHeight(rad) - FlightGlobals.ActiveVessel.mainBody.pqsController.radius;
                    if ((this.impactAltitude < 0) && FlightGlobals.ActiveVessel.mainBody.ocean)
                    {
                        this.impactAltitude = 0;
                    }
                }
            }

            // Set accessable properties.
            if (this.impactHappening)
            {
                ShowDetails = true;
                Time        = this.impactTime;
                Longitude   = this.impactLongitude;
                Latitude    = this.impactLatitude;
                Altitude    = this.impactAltitude;
                try
                {
                    Biome = ScienceUtil.GetExperimentBiome(FlightGlobals.ActiveVessel.mainBody, this.impactLatitude, this.impactLongitude);
                }
                catch (Exception ex)
                {
                    MyLogger.Log("GetExperimentBiome(" + FlightGlobals.ActiveVessel.mainBody.name + ", " + this.impactLatitude + ", " + this.impactLongitude + ") died");
                    MyLogger.Exception(ex);
                    Biome = "<failed>";
                }
            }
            else
            {
                ShowDetails = false;
            }
        }
Example #5
0
 public static double PQSSurfaceHeight(double latitude, double longitude, CelestialBody body)
 {
     if (body.pqsController != null)
     {
         Vector3d pqsRadialVector = QuaternionD.AngleAxis(longitude, Vector3d.down) * QuaternionD.AngleAxis(latitude, Vector3d.forward) * Vector3d.right;
         return(body.pqsController.GetSurfaceHeight(pqsRadialVector) - body.pqsController.radius);
     }
     else
     {
         return(0);
     }
 }
Example #6
0
        public static Coordinates GetMouseCoordinates(CelestialBody body)
        {
            Ray mouseRay = PlanetariumCamera.Camera.ScreenPointToRay(Input.mousePosition);

            mouseRay.origin = ScaledSpace.ScaledToLocalSpace(mouseRay.origin);
            Vector3d relOrigin = mouseRay.origin - body.position;
            Vector3d relSurfacePosition;
            double   curRadius  = body.pqsController.radiusMax;
            double   lastRadius = 0;
            double   error      = 0;
            int      loops      = 0;
            float    st         = Time.time;

            while (loops < 50)
            {
                if (PQS.LineSphereIntersection(relOrigin, mouseRay.direction, curRadius, out relSurfacePosition))
                {
                    Vector3d surfacePoint = body.position + relSurfacePosition;
                    double   alt          = body.pqsController.GetSurfaceHeight(QuaternionD.AngleAxis(body.GetLongitude(surfacePoint), Vector3d.down) * QuaternionD.AngleAxis(body.GetLatitude(surfacePoint), Vector3d.forward) * Vector3d.right);
                    error = Math.Abs(curRadius - alt);
                    if (error < (body.pqsController.radiusMax - body.pqsController.radiusMin) / 100)
                    {
                        return(new Coordinates(body.GetLatitude(surfacePoint), MuUtils.ClampDegrees180(body.GetLongitude(surfacePoint))));
                    }
                    else
                    {
                        lastRadius = curRadius;
                        curRadius  = alt;
                        loops++;
                    }
                }
                else
                {
                    if (loops == 0)
                    {
                        break;
                    }
                    else
                    { // Went too low, needs to try higher
                        curRadius = (lastRadius * 9 + curRadius) / 10;
                        loops++;
                    }
                }
            }

            return(null);
        }
Example #7
0
        /// <summary>
        /// Generates planet maps from a PQS
        /// </summary>
        private void GenerateMaps(Int32 width, Body body, PQSMod[] mods, Boolean hasOcean, Double oceanHeight,
                                  Color oceanColor, Single normalStrength, out Texture2D colorMap, out Texture2D heightMap, out Texture2D normalMap)
        {
            // Generate the textures
            Int32 height = width / 2;

            colorMap  = new Texture2D(width, height, TextureFormat.ARGB32, true);
            heightMap = new Texture2D(width, height, TextureFormat.RGB24, true);

            // Create a VertexBuildData
            PQS.VertexBuildData data = new PQS.VertexBuildData();
            Vector3             direction;

            // Build the textures
            for (Int32 y = 0; y < height; y++)
            {
                for (Int32 x = 0; x < width; x++)
                {
                    // Update the build data
                    data.directionFromCenter = QuaternionD.AngleAxis(360d / width * x, Vector3d.up) *
                                               QuaternionD.AngleAxis(90d - 180d / height * y, Vector3d.right) *
                                               Vector3d.forward;
                    data.vertHeight = body.pqs.Value.radius;

                    // Map coords
                    data.latitude = Math.Asin(data.directionFromCenter.y);
                    if (double.IsNaN(data.latitude))
                    {
                        data.latitude = 1.5707963267948966;
                    }
                    direction = new Vector3d(data.directionFromCenter.x, 0.0, data.directionFromCenter.z).normalized;
                    if (direction.magnitude > 0.0)
                    {
                        data.longitude = direction.z >= 0.0 ? Math.Asin(direction.x) : Math.PI - Math.Asin(direction.x);
                    }
                    else
                    {
                        data.longitude = 0.0;
                    }
                    data.v = data.latitude / 3.1415926535897931 + 0.5;
                    data.u = data.longitude / 3.1415926535897931 * 0.5;

                    // Build the height data
                    for (Int32 i = 0; i < mods.Length; i++)
                    {
                        mods[i].OnVertexBuildHeight(data);
                    }

                    // Build the color data
                    for (Int32 i = 0; i < mods.Length; i++)
                    {
                        mods[i].OnVertexBuild(data);
                    }

                    // Process the height
                    Single h = (Single)((data.vertHeight - body.pqs.Value.radius) *
                                        (1d / body.pqs.Value.mapMaxHeight));
                    if (h < 0)
                    {
                        h = 0;
                    }
                    else if (h > 1)
                    {
                        h = 1;
                    }
                    heightMap.SetPixel(x, y, new Color(h, h, h));

                    // Process the color
                    if (hasOcean)
                    {
                        if (h <= oceanHeight)
                        {
                            colorMap.SetPixel(x, y, oceanColor.A(1f));
                        }
                        else
                        {
                            colorMap.SetPixel(x, y, data.vertColor.A(0f));
                        }
                    }
                    else
                    {
                        colorMap.SetPixel(x, y, data.vertColor.A(1f));
                    }
                }
            }

            // Generate the normalmap
            normalMap = Utility.BumpToNormalMap(heightMap, normalStrength);
        }
Example #8
0
        /// <summary>
        /// By default, KSP merges all scatters that are on one quad into one gigantic mesh that is then rendered.
        /// Because Kopernicus wants to know where each scatter actually is, we have to create our own scatter objects
        /// </summary>
        private void CreateScatterMeshes(PQSMod_LandClassScatterQuad quad)
        {
            Random.InitState(quad.seed);

            // Redo the density calculation
            if (useBetterDensity)
            {
                Dictionary <String, Double> densities = quad.quad.GetComponent <DensityContainer>().densities;
                if (densities.ContainsKey(quad.scatter.scatterName))
                {
                    Double density = densities[quad.scatter.scatterName];
                    if (ignoreDensityGameSetting && PQS.Global_ScatterFactor > 0)
                    {
                        density /= PQS.Global_ScatterFactor;
                    }
                    Double scatterN = density * quad.scatter.densityFactor *
                                      (quad.quad.quadArea / quad.quad.sphereRoot.radius / 1000.0) *
                                      quad.scatter.maxScatter;
                    scatterN  += Random.Range(-0.5f, 0.5f);
                    quad.count = Math.Min((Int32)Math.Round(scatterN), quad.scatter.maxScatter);
                }
            }

            for (Int32 i = 0; i < quad.count; i++)
            {
                if (useBetterDensity)
                {
                    // Generate a random number between 0 and 1. If it is above the spawn chance, abort
                    if (Random.value > spawnChance)
                    {
                        continue;
                    }
                }

                Int32 num2 = -1;
                Int32 num3 = -1;
                while (num3 == num2)
                {
                    Int32 num4 = Random.Range(1, PQS.cacheRes + 1);
                    Int32 num5 = Random.Range(1, PQS.cacheRes + 1);
                    Int32 x    = num4 + Random.Range(-1, 1);
                    Int32 z    = num5 + Random.Range(-1, 1);
                    num3 = PQS.vi(num4, num5);
                    num2 = PQS.vi(x, z);
                }

                Vector3 scatterPos = Vector3.Lerp(quad.quad.verts[num3], quad.quad.verts[num2], Random.value);
                Vector3 scatterUp  = quad.quad.sphereRoot.surfaceRelativeQuads
                    ? (Vector3)(scatterPos + quad.quad.positionPlanet).normalized
                    : scatterPos.normalized;

                scatterPos += scatterUp * quad.scatter.verticalOffset;
                Single     scatterAngle = Random.Range(rotation[0], rotation[1]);
                Quaternion scatterRot   = QuaternionD.AngleAxis(scatterAngle, scatterUp) * quad.quad.quadRotation;
                Single     scatterScale = Random.Range(quad.scatter.minScale, quad.scatter.maxScale);

                // Create a new object for the scatter
                GameObject scatterObject = new GameObject("Scatter");
                scatterObject.transform.parent        = quad.obj.transform;
                scatterObject.transform.localPosition = scatterPos;
                scatterObject.transform.localRotation = scatterRot;
                scatterObject.transform.localScale    = Vector3.one * scatterScale;
                scatterObject.AddComponent <KopernicusSurfaceObject>().objectName = quad.scatter.scatterName;
                MeshFilter filter = scatterObject.AddComponent <MeshFilter>();
                filter.sharedMesh = meshes.Count > 0 ? meshes[Random.Range(0, meshes.Count)] : baseMesh;
                MeshRenderer renderer = scatterObject.AddComponent <MeshRenderer>();
                renderer.sharedMaterial    = quad.scatter.material;
                renderer.shadowCastingMode = quad.scatter.castShadows ? ShadowCastingMode.On : ShadowCastingMode.Off;
                renderer.receiveShadows    = quad.scatter.recieveShadows;
                scatterObject.layer        = GameLayers.LOCAL_SPACE;
                scatterObjects.Add(scatterObject);
            }

            quad.obj.name = "Kopernicus-" + quad.scatter.scatterName;
            quad.obj.AddOrGetComponent <ScatterDistanceCuller>();
        }
        public static void updatePlanetaryResourceMap()
        {
            if (FlightGlobals.currentMainBody.flightGlobalsIndex != current_body)
            {
                loadPlanetaryResourceData(FlightGlobals.currentMainBody.flightGlobalsIndex);
            }

            if (body_resource_maps.ContainsKey(displayed_resource) && (FlightGlobals.currentMainBody.flightGlobalsIndex != map_body || displayed_resource != map_resource))
            {
                foreach (ORSResourceAbundanceMarker abundance_marker in abundance_markers)
                {
                    removeAbundanceSphere(abundance_marker.getPlanetarySphere());
                    removeAbundanceSphere(abundance_marker.getScaledSphere());
                }

                abundance_markers.Clear();
                CelestialBody celbody = FlightGlobals.currentMainBody;
                sphere_texture = body_resource_maps[displayed_resource].getDisplayTexturePath();
                Vector2d[] abundance_points_list = body_abudnance_angles[displayed_resource];
                if (abundance_points_list != null && celbody.pqsController != null)
                {
                    foreach (Vector2d abundance_point in abundance_points_list)
                    {
                        double   theta = abundance_point.x;
                        double   phi   = abundance_point.y;
                        Vector3d up    = celbody.GetSurfaceNVector(phi, theta).normalized;

                        double     surface_height       = celbody.pqsController.GetSurfaceHeight(QuaternionD.AngleAxis(theta, Vector3d.down) * QuaternionD.AngleAxis(phi, Vector3d.forward) * Vector3d.right);
                        GameObject resource_prim        = createAbundanceSphere();
                        GameObject resource_prim_scaled = createAbundanceSphere();

                        Vector3d center       = celbody.position + surface_height * up;
                        Vector3d scaledcenter = ScaledSpace.LocalToScaledSpace(celbody.position) + surface_height * up * ScaledSpace.InverseScaleFactor;

                        Transform scaled_trans = PSystemManager.Instance.localBodies.Select(b => b.scaledBody.transform).Single(t => t.name == celbody.name);
                        resource_prim_scaled.transform.position      = scaledcenter;
                        resource_prim_scaled.transform.localScale    = sphere_scale_scaled * (FlightGlobals.currentMainBody.Radius / FlightGlobals.Bodies[ORSGameConstants.REF_BODY_KERBIN].Radius);
                        resource_prim_scaled.transform.localRotation = Quaternion.identity;
                        resource_prim_scaled.transform.parent        = scaled_trans;
                        resource_prim_scaled.layer = 10;

                        resource_prim.transform.position      = center;
                        resource_prim.transform.parent        = celbody.transform;
                        resource_prim.transform.localScale    = sphere_scale * (FlightGlobals.currentMainBody.Radius / FlightGlobals.Bodies[ORSGameConstants.REF_BODY_KERBIN].Radius);
                        resource_prim.transform.localRotation = Quaternion.identity;

                        ORSResourceAbundanceMarker abundance_marker = new ORSResourceAbundanceMarker(resource_prim_scaled, resource_prim);
                        abundance_markers.Add(abundance_marker);
                    }
                    map_body     = current_body;
                    map_resource = displayed_resource;
                    stored_scale = ScaledSpace.ScaleFactor;
                }
                //celbody.renderer.material.mainTexture.
            }
            else
            {
                if (body_resource_maps.ContainsKey(displayed_resource) && FlightGlobals.currentMainBody.flightGlobalsIndex == map_body && displayed_resource == map_resource)
                {
                    CelestialBody celbody = FlightGlobals.currentMainBody;
                    foreach (ORSResourceAbundanceMarker abundance_marker in abundance_markers)
                    {
                        if (lineOfSightToPosition(abundance_marker.getPlanetarySphere().transform.position, celbody))
                        {
                            if (MapView.MapIsEnabled)
                            {
                                abundance_marker.getScaledSphere().GetComponent <Renderer>().enabled    = true;
                                abundance_marker.getPlanetarySphere().GetComponent <Renderer>().enabled = false;
                            }
                            else
                            {
                                abundance_marker.getScaledSphere().GetComponent <Renderer>().enabled    = false;
                                abundance_marker.getPlanetarySphere().GetComponent <Renderer>().enabled = true;
                            }
                        }
                        else
                        {
                            abundance_marker.getScaledSphere().GetComponent <Renderer>().enabled    = false;
                            abundance_marker.getPlanetarySphere().GetComponent <Renderer>().enabled = false;
                        }
                    }
                }
            }
        }
Example #10
0
        // Get true altitude above terrain (from MuMech lib)
        // Also from: http://kerbalspaceprogram.com/forum/index.php?topic=10324.msg161923#msg161923
        private static double getTrueAltitude(Vessel vessel)
        {
            Vector3    CoM          = vessel.findWorldCenterOfMass();
            Vector3    up           = (CoM - vessel.mainBody.position).normalized;
            double     altitudeASL  = vessel.mainBody.GetAltitude(CoM);
            double     altitudeTrue = 0.0;
            RaycastHit sfc;

            if (Physics.Raycast(CoM, -up, out sfc, (float)altitudeASL + 10000.0F, 1 << 15))
            {
                altitudeTrue = sfc.distance;
            }
            else if (vessel.mainBody.pqsController != null)
            {
                altitudeTrue = vessel.mainBody.GetAltitude(CoM) - (vessel.mainBody.pqsController.GetSurfaceHeight(QuaternionD.AngleAxis(vessel.mainBody.GetLongitude(CoM), Vector3d.down) * QuaternionD.AngleAxis(vessel.mainBody.GetLatitude(CoM), Vector3d.forward) * Vector3d.right) - vessel.mainBody.pqsController.radius);
            }
            else
            {
                altitudeTrue = vessel.mainBody.GetAltitude(CoM);
            }
            return(altitudeTrue);
        }
Example #11
0
        public void FixedUpdate()
        {
            var vessel = GetComponent <Vessel>();

            if (vessel != FlightGlobals.ActiveVessel)
            {
                KRASHShelter.instance.SetSimActiveNotification();
                Destroy(this);
                return;
            }
            KRASHShelter.instance.SetSimNotification("Simulation Setup in Progress");
            if (AlreadyTeleported)
            {
                if (vessel.LandedOrSplashed)
                {
                    if (!pausebeforestarting)
                    {
                        pausebeforestarting = true;
                        FlightDriver.SetPause(true);
                        //PopupDialog.SpawnPopupDialog ("Vessel has landed", "Vessel has landed.  Click the OK button to continue", "OK", true, HighLogic.Skin);
                        var dialog = new MultiOptionDialog("krash4", "Vessel has landed.  Click the OK button to continue", "", HighLogic.UISkin, new DialogGUIBase[] {
                            new DialogGUIButton("OK", () => {
                                FlightDriver.SetPause(false);
                                KRASHShelter.instance.SetSimActiveNotification();
                                Destroy(this);
                                //	_activePopup.Dismiss ();
                            })
                        });
                        PopupDialog.SpawnPopupDialog(new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), dialog, false, HighLogic.UISkin, true);
                    }
                }
                else
                {
                    var accel = (vessel.srf_velocity + vessel.upAxis) * -0.5;
                    vessel.ChangeWorldVelocity(accel);
                    Hyperedit.RateLimitedLogger.Log(accelLogObject,
                                                    string.Format("(Happening every frame) Soft-lander changed ship velocity this frame by vector {0},{1},{2} (mag {3})",
                                                                  accel.x, accel.y, accel.z, accel.magnitude));
                }
            }
            else
            {
                Log.Info("NotTeleported");
                var pqs = Body.pqsController;
                if (pqs == null)
                {
                    KRASHShelter.instance.SetSimActiveNotification();
                    Destroy(this);
                    return;
                }

                var alt = pqs.GetSurfaceHeight(
                    QuaternionD.AngleAxis(Longitude, Vector3d.down) *
                    QuaternionD.AngleAxis(Latitude, Vector3d.forward) * Vector3d.right) -
                          pqs.radius;
                alt = Math.Max(alt, 0);                 // Underwater!

                if (TimeWarp.CurrentRateIndex != 0)
                {
                    TimeWarp.SetRate(0, true);
                    Log.Info("Set time warp to index 0");
                }
                // HoldVesselUnpack is in display frames, not physics frames
                Log.Info("alt: " + alt.ToString() + "   Altitude: " + Altitude.ToString());
                Log.Info("Latitude: " + Latitude.ToString() + "   Longitude: " + Longitude.ToString());

                //var teleportPosition = Body.GetRelSurfacePosition(Latitude, Longitude, alt + Altitude);
                var teleportPosition = Body.GetWorldSurfacePosition(Latitude, Longitude, alt + Altitude) - Body.position;

                var teleportVelocity = Body.getRFrmVel(teleportPosition + Body.position);
                // convert from world space to orbit space
                teleportPosition = teleportPosition.xzy;
                teleportVelocity = teleportVelocity.xzy;
                // counter for the momentary fall when on rails (about one second)
                teleportVelocity += teleportPosition.normalized * (Body.gravParameter / teleportPosition.sqrMagnitude);

                //	var oldUp = vessel.orbit.pos.xzy.normalized; // can also be vessel.vesselTransform.position, I think
                //	var newUp = teleportPosition.xzy.normalized; // teleportPosition is the orbitspace location (note the .xzy)
                //	var rotation = Quaternion.FromToRotation(oldUp, newUp)*vessel.vesselTransform.rotation;

                var from     = Vector3d.up;
                var to       = teleportPosition.xzy.normalized;
                var rotation = Quaternion.FromToRotation(from, to);


                var orbit = vessel.orbitDriver.orbit.Clone();
                orbit.UpdateFromStateVectors(teleportPosition, teleportVelocity, Body, Planetarium.GetUniversalTime());


                vessel.SetOrbit(orbit);
                vessel.SetRotation(rotation);

                AlreadyTeleported = true;
            }
        }
        public static QuaternionD BodyRotationAtdT(CelestialBody Body, double dT)
        {
            var angle = -(dT / Body.rotationPeriod * 360 % 360.0);

            return(QuaternionD.AngleAxis(angle, Body.zUpAngularVelocity.normalized));
        }
Example #13
0
        public void RandomizePosition(bool waterAllowed = true)
        {
            System.Random generator = new System.Random(seed + id);

            CelestialBody myPlanet = null;

            foreach (CelestialBody body in FlightGlobals.Bodies)
            {
                if (body.GetName() == celestialName)
                {
                    myPlanet = body;
                }
            }

            if (myPlanet != null)
            {
                if (myPlanet.ocean && !waterAllowed)
                {
                    if (myPlanet.pqsController != null)
                    {
                        while (true)
                        {
                            double rand = generator.NextDouble();
                            rand      = 1.0 - (rand * 2);
                            latitude  = Math.Asin(rand) * UnityEngine.Mathf.Rad2Deg;
                            longitude = generator.NextDouble() * 360 - 180;
                            Vector3d pqsRadialVector = QuaternionD.AngleAxis(longitude, Vector3d.down) * QuaternionD.AngleAxis(latitude, Vector3d.forward) * Vector3d.right;
                            double   chosenHeight    = myPlanet.pqsController.GetSurfaceHeight(pqsRadialVector) - myPlanet.pqsController.radius;

                            if (chosenHeight < 0)
                            {
                                continue;
                            }
                            else
                            {
                                break;
                            }
                        }
                    }
                }
                else
                {
                    double rand = generator.NextDouble();
                    rand      = 1.0 - (rand * 2);
                    latitude  = Math.Asin(rand) * UnityEngine.Mathf.Rad2Deg;
                    longitude = generator.NextDouble() * 360 - 180;
                }
            }
        }
Example #14
0
        public void RandomizeNear(double centerLatitude, double centerLongitude, string celestialName, double searchRadius, bool waterAllowed = true)
        {
            CelestialBody myPlanet = null;

            System.Random generator = new System.Random(this.seed + this.id);

            foreach (CelestialBody body in FlightGlobals.Bodies)
            {
                if (body.GetName() == celestialName)
                {
                    myPlanet = body;
                }
            }

            if (myPlanet != null)
            {
                if (myPlanet.ocean && !waterAllowed)
                {
                    if (myPlanet.pqsController != null)
                    {
                        while (true)
                        {
                            double distancePerDegree = (myPlanet.Radius * 2 * UnityEngine.Mathf.PI) / 360.0;
                            double lng_min           = centerLongitude - searchRadius / UnityEngine.Mathf.Abs(UnityEngine.Mathf.Cos(UnityEngine.Mathf.Deg2Rad * (float)centerLatitude) * (float)distancePerDegree);
                            double lng_max           = centerLongitude + searchRadius / UnityEngine.Mathf.Abs(UnityEngine.Mathf.Cos(UnityEngine.Mathf.Deg2Rad * (float)centerLatitude) * (float)distancePerDegree);
                            double lat_min           = centerLatitude - (searchRadius / distancePerDegree);
                            double lat_max           = centerLatitude + (searchRadius / distancePerDegree);
                            latitude  = lat_min + generator.NextDouble() * (lat_max - lat_min);
                            longitude = lng_min + generator.NextDouble() * (lng_max - lng_min);
                            Vector3d pqsRadialVector = QuaternionD.AngleAxis(longitude, Vector3d.down) * QuaternionD.AngleAxis(latitude, Vector3d.forward) * Vector3d.right;
                            double   chosenHeight    = myPlanet.pqsController.GetSurfaceHeight(pqsRadialVector) - myPlanet.pqsController.radius;

                            if (chosenHeight < 0)
                            {
                                continue;
                            }
                            else
                            {
                                break;
                            }
                        }
                    }
                }
                else
                {
                    double distancePerDegree = (myPlanet.Radius * 2 * UnityEngine.Mathf.PI) / 360.0;
                    double lng_min           = centerLongitude - searchRadius / UnityEngine.Mathf.Abs(UnityEngine.Mathf.Cos(UnityEngine.Mathf.Deg2Rad * (float)centerLatitude) * (float)distancePerDegree);
                    double lng_max           = centerLongitude + searchRadius / UnityEngine.Mathf.Abs(UnityEngine.Mathf.Cos(UnityEngine.Mathf.Deg2Rad * (float)centerLatitude) * (float)distancePerDegree);
                    double lat_min           = centerLatitude - (searchRadius / distancePerDegree);
                    double lat_max           = centerLatitude + (searchRadius / distancePerDegree);
                    latitude  = lat_min + generator.NextDouble() * (lat_max - lat_min);
                    longitude = lng_min + generator.NextDouble() * (lng_max - lng_min);
                }
            }
        }
Example #15
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 #16
0
        private static void PlaceWaypointAtCursor()
        {
            if (targetBody.pqsController == null)
            {
                return;
            }

            Ray mouseRay = PlanetariumCamera.Camera.ScreenPointToRay(Input.mousePosition);

            mouseRay.origin = ScaledSpace.ScaledToLocalSpace(mouseRay.origin);
            var    bodyToOrigin = mouseRay.origin - targetBody.position;
            double curRadius    = targetBody.pqsController.radiusMax;
            double lastRadius   = 0;
            int    loops        = 0;

            while (loops < 50)
            {
                Vector3d relSurfacePosition;
                if (PQS.LineSphereIntersection(bodyToOrigin, mouseRay.direction, curRadius, out relSurfacePosition))
                {
                    var    surfacePoint = targetBody.position + relSurfacePosition;
                    double alt          = targetBody.pqsController.GetSurfaceHeight(
                        QuaternionD.AngleAxis(targetBody.GetLongitude(surfacePoint), Vector3d.down) * QuaternionD.AngleAxis(targetBody.GetLatitude(surfacePoint), Vector3d.forward) * Vector3d.right);
                    double error = Math.Abs(curRadius - alt);
                    if (error < (targetBody.pqsController.radiusMax - targetBody.pqsController.radiusMin) / 100)
                    {
                        latitude  = targetBody.GetLatitude(surfacePoint).ToString();
                        longitude = targetBody.GetLongitude(surfacePoint).ToString();
                        return;
                    }
                    else
                    {
                        lastRadius = curRadius;
                        curRadius  = alt;
                        loops++;
                    }
                }
                else
                {
                    if (loops == 0)
                    {
                        break;
                    }
                    // Went too low, needs to try higher
                    else
                    {
                        curRadius = (lastRadius * 9 + curRadius) / 10;
                        loops++;
                    }
                }
            }
        }