コード例 #1
0
        private void UpdateParallel(
            double t,
            ImagingParallel parallel,
            Vector3d vesselInSurfaceFrame,
            Vector3d swathNormal,
            ImagingProduct[] products,
            out bool parallelVisibleAtRelevantResolution)
        {
            parallelVisibleAtRelevantResolution = false;
            for (int x = parallel.x_begin; x != parallel.x_end; ++x)
            {
                SunSurfaceSatelliteGeometry geometry = products[0].pushbroom
                                        ? new SunSurfaceSatelliteGeometry(
                    vesselInSurfaceFrame,
                    swathNormal,
                    parallel.surface[x],
                    parallel.sun[x])
                                        : new SunSurfaceSatelliteGeometry(
                    vesselInSurfaceFrame,
                    parallel.surface[x],
                    parallel.sun[x]);
                if (geometry.surfaceSatelliteGeometry.Visible)
                {
                    foreach (var product in products)
                    {
                        bool sunlit = parallel.sun[x].cosSolarZenithAngle > cos75degrees;
                        bool night  = parallel.sun[x].cosSolarZenithAngle < cos105degrees;
                        if (product.band == OpticalBand.VisNIR && !sunlit && !night)
                        {
                            continue;
                        }
                        double resolution = product.HorizontalResolution(geometry.surfaceSatelliteGeometry);
                        for (int i = 0; i < resolutionThresholds.Length; ++i)
                        {
                            if (product.HorizontalResolution(geometry.surfaceSatelliteGeometry) <
                                resolutionThresholds[i])
                            {
                                parallelVisibleAtRelevantResolution = true;
                                for (; i < resolutionThresholds.Length; ++i)
                                {
                                    switch (product.band)
                                    {
                                    case OpticalBand.MidInfrared:
                                        parallel.midInfrared[x].lastImagingTime[i] =
                                            Math.Max(parallel.midInfrared[x].lastImagingTime[i], t);
                                        break;

                                    case OpticalBand.VisNIR:
                                        if (sunlit)
                                        {
                                            if (geometry.cosGlintAngle > cos15degrees)
                                            {
                                                parallel.glintedReflectiveVisNIR[x].lastImagingTime[i] =
                                                    Math.Max(parallel.glintedReflectiveVisNIR[x].lastImagingTime[i], t);
                                            }
                                            else
                                            {
                                                parallel.unglintedReflectiveVisNIR[x].lastImagingTime[i] =
                                                    Math.Max(parallel.unglintedReflectiveVisNIR[x].lastImagingTime[i], t);
                                            }
                                        }
                                        else if (night)
                                        {
                                            parallel.nightVisNIR[x].lastImagingTime[i] =
                                                Math.Max(parallel.nightVisNIR[x].lastImagingTime[i], t);
                                        }
                                        break;
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
コード例 #2
0
        public void Update()
        {
            timeSpentInIllumination  = TimeSpan.Zero;
            timeSpentInTextureUpdate = TimeSpan.Zero;
            DateTime      start  = DateTime.UtcNow;
            CelestialBody kerbin = FlightGlobals.GetHomeBody();

            if (reset)
            {
                reset          = false;
                kerbin_imaging = null;
                lastUpdateUT   = null;
                window.width   = 0;
                window.height  = 0;
                return;
            }
            if (pause)
            {
                return;
            }
            if (kerbin_imaging == null)
            {
                UnityEngine.Debug.LogWarning("Rebuilding map...");
                x_size         = small ? 256 : 512;
                y_size         = small ? 128 : 256;
                kerbin_imaging = new ImagingParallel[y_size];
                minimap        = new UnityEngine.Texture2D(x_size, y_size);
                for (int y = 0; y < y_size; ++y)
                {
                    // Mollweide on [-2, 2] × [-1, 1].
                    double y_normalized = 2.0 * y / y_size - 1;
                    double θ            = Math.Asin(y_normalized);
                    double sinφ         = (2 * θ + Math.Sin(2 * θ)) / Math.PI;
                    double φ            = Math.Asin(sinφ);
                    double φ_deg        = φ * (180 / Math.PI);
                    var    parallel     = kerbin_imaging[y] = new ImagingParallel
                    {
                        cosLatitude = Math.Cos(φ),
                        sinLatitude = sinφ,
                        map         = new MapPoint[x_size],
                        midInfrared = new ImagingStatus[x_size],
                        nightVisNIR = new ImagingStatus[x_size],
                        unglintedReflectiveVisNIR = new ImagingStatus[x_size],
                        glintedReflectiveVisNIR   = new ImagingStatus[x_size],
                        sun     = new SunSurfaceGeometry[x_size],
                        surface = new SurfacePoint[x_size]
                    };
                    bool entered_map = false;
                    parallel.x_end = x_size;
                    for (int x = 0; x < x_size; ++x)
                    {
                        double x_normalized = 4.0 * x / x_size - 2;
                        double λ            = Math.PI * x_normalized / (2 * Math.Cos(θ));
                        double λ_deg        = λ * (180 / Math.PI);

                        if (double.IsNaN(φ) || double.IsNaN(λ) || Math.Abs(λ) > Math.PI)
                        {
                            parallel.map[x].on_map = false;
                            if (entered_map && parallel.x_end == x_size)
                            {
                                parallel.x_end = x;
                            }
                        }
                        else
                        {
                            parallel.map[x].on_map = true;
                            if (!entered_map)
                            {
                                parallel.x_begin = x;
                            }
                            entered_map = true;
                            double altitude = kerbin.TerrainAltitude(φ_deg, λ_deg);
                            parallel.surface[x] = new SurfacePoint(
                                kerbin.scaledBody.transform.rotation.Inverse() *
                                (kerbin.GetWorldSurfacePosition(φ_deg, λ_deg, altitude) - kerbin.position));
                            parallel.map[x].ocean = altitude == 0;
                            parallel.midInfrared[x].lastImagingTime               = new double[resolutionThresholds.Length];
                            parallel.nightVisNIR[x].lastImagingTime               = new double[resolutionThresholds.Length];
                            parallel.glintedReflectiveVisNIR[x].lastImagingTime   = new double[resolutionThresholds.Length];
                            parallel.unglintedReflectiveVisNIR[x].lastImagingTime = new double[resolutionThresholds.Length];
                            for (int i = 0; i < resolutionThresholds.Length; ++i)
                            {
                                parallel.midInfrared[x].lastImagingTime[i]               = double.NegativeInfinity;
                                parallel.nightVisNIR[x].lastImagingTime[i]               = double.NegativeInfinity;
                                parallel.glintedReflectiveVisNIR[x].lastImagingTime[i]   = double.NegativeInfinity;
                                parallel.unglintedReflectiveVisNIR[x].lastImagingTime[i] = double.NegativeInfinity;
                            }
                        }
                    }
                }
            }
            var    imagers = activeImagers.ToArray();
            double Δt      = 30;

            if (lastUpdateUT == null || kerbin.scaledBody.transform.rotation == null)
            {
                lastUpdateUT       = Planetarium.GetUniversalTime();
                lastKerbinRotation = kerbin.scaledBody.transform.rotation;
            }
            var current_kerbin_to_world = kerbin.scaledBody.transform.rotation;

            for (int n = (int)Math.Floor((Planetarium.GetUniversalTime() - lastUpdateUT.Value) / Δt); n >= 0; --n)
            {
                double t = Planetarium.GetUniversalTime() - n * Δt;
                // TODO(egg): This will fail hilariously if the interval between updates is greater than half a day.
                // It is probably broken in other ways.
                var kerbin_to_world = UnityEngine.Quaternion.Slerp(
                    lastKerbinRotation.Value, current_kerbin_to_world,
                    (float)((t - lastUpdateUT) / (Planetarium.GetUniversalTime() - lastUpdateUT)));
                var      world_to_kerbin       = kerbin_to_world.Inverse();
                double   kerbin_radius         = kerbin.Radius;
                var      kerbin_world_position = kerbin.orbit.getPositionAtUT(t);
                Vector3d sunInSurfaceFrame     = world_to_kerbin *
                                                 (kerbin.referenceBody.getPositionAtUT(t) - kerbin_world_position);
                Vector3d sunDirection = sunInSurfaceFrame.normalized;
                for (int y = 0; y != y_size; ++y)
                {
                    var parallel = kerbin_imaging[y];
                    for (int x = parallel.x_begin; x != parallel.x_end; ++x)
                    {
                        if (solarParallax)
                        {
                            parallel.sun[x] = SunSurfaceGeometry.FromSunPosition(
                                parallel.surface[x],
                                sunInSurfaceFrame);
                        }
                        else
                        {
                            parallel.sun[x] = SunSurfaceGeometry.FromSunDirection(
                                parallel.surface[x],
                                sunDirection);
                        }
                    }
                }
                foreach (var imager in imagers)
                {
                    Vessel           platform = FlightGlobals.FindVessel(imager.Key);
                    ImagingProduct[] products = imager.Value;
                    Vector3d         vesselFromKerbinInWorld;
                    Vector3d         kerbinCentredVesselVelocityInWorld;
                    if (platform.orbit.referenceBody == kerbin)
                    {
                        var vesselFromKerbinInAlice            = platform.orbit.getRelativePositionAtUT(t);
                        var kerbinCentredVesselVelocityInAlice = platform.orbit.getOrbitalVelocityAtUT(t);
                        vesselFromKerbinInWorld            = vesselFromKerbinInAlice.xzy;
                        kerbinCentredVesselVelocityInWorld = kerbinCentredVesselVelocityInAlice.xzy;
                    }
                    else
                    {
                        Vector3d vesselFromSunInAlice = Vector3d.zero;
                        Vector3d kerbinFromSunInAlice = Vector3d.zero;
                        Vector3d heliocentricVesselVelocityInAlice = Vector3d.zero;
                        Vector3d heliocentricKerbinVelocityInAlice = Vector3d.zero;
                        for (var orbit = platform.orbit; orbit != null; orbit = orbit.referenceBody?.orbit)
                        {
                            vesselFromSunInAlice += orbit.getRelativePositionAtUT(t);
                            heliocentricVesselVelocityInAlice += orbit.getOrbitalVelocityAtUT(t);
                        }
                        for (var orbit = kerbin.orbit; orbit != null; orbit = orbit.referenceBody?.orbit)
                        {
                            kerbinFromSunInAlice += orbit.getRelativePositionAtUT(t);
                            heliocentricKerbinVelocityInAlice += orbit.getOrbitalVelocityAtUT(t);
                        }
                        vesselFromKerbinInWorld            = (vesselFromSunInAlice - kerbinFromSunInAlice).xzy;
                        kerbinCentredVesselVelocityInWorld =
                            (heliocentricVesselVelocityInAlice - heliocentricKerbinVelocityInAlice).xzy;
                    }
                    Vector3d swathNormal;
                    if (platform.loaded)
                    {
                        // The rotation transforms from part coordinates to
                        // world coordinates.
                        // TODO(egg): that products[0] is a hack.
                        swathNormal = world_to_kerbin *
                                      (products[0].part.rb.rotation * Vector3d.up);
                    }
                    else
                    {
                        // TODO(egg): Fetch from Principia if available.
                        swathNormal = world_to_kerbin * kerbinCentredVesselVelocityInWorld.normalized;
                    }
                    Vector3d             vesselInSurfaceFrame = world_to_kerbin * vesselFromKerbinInWorld;
                    UnityEngine.Vector2d subsatellitePoint    = kerbin.GetLatitudeAndLongitude(
                        kerbin.position + current_kerbin_to_world * world_to_kerbin * vesselFromKerbinInWorld);
                    double latitude  = subsatellitePoint.x;
                    double longitude = subsatellitePoint.y;
                    double xVessel   = (0.5 + longitude / 360) % 1;
                    double yVessel   = (0.5 + latitude / 180) % 1;
                    for (int y = (int)(yVessel * y_size); y < y_size; ++y)
                    {
                        var parallel = kerbin_imaging[y];
                        UpdateParallel(
                            t, parallel, vesselInSurfaceFrame, swathNormal, products,
                            out bool parallelVisibleAtRelevantResolution);
                        if (!parallelVisibleAtRelevantResolution)
                        {
                            break;
                        }
                    }
                    for (int y = (int)(yVessel * y_size) - 1; y >= 0; --y)
                    {
                        var parallel = kerbin_imaging[y];
                        UpdateParallel(
                            t, parallel, vesselInSurfaceFrame, swathNormal, products,
                            out bool parallelVisibleAtRelevantResolution);
                        if (!parallelVisibleAtRelevantResolution)
                        {
                            break;
                        }
                    }
                }
                lastUpdateUT       = t;
                lastKerbinRotation = current_kerbin_to_world;
            }

            RefreshMap();

            minimap.Apply(updateMipmaps: false);
            timeSpentInUpdate = DateTime.UtcNow - start;
        }