unsafe void GeneratePSRImage()
        {
            var side = TerrainPatch.DefaultSize;

            // Prepare bitmap
            var width       = side * IdBounds.Width;
            var height      = side * IdBounds.Height;
            var sum_image   = new Int32[height, width];
            var time_image  = new Int32[height, width];
            var bitmap_rect = new Rectangle(0, 0, width, height);

            // Generate sun vectors
            var start_time  = new DateTime(2000, 1, 1);
            var stop_time   = new DateTime(2019, 1, 1);
            var time_step   = TimeSpan.FromHours(2);
            var sun_vectors = new List <Vector3d>();

            for (var time = start_time; time <= stop_time; time += time_step)
            {
                sun_vectors.Add(CSpice.SunPosition(time));
            }

            Console.WriteLine(sun_vectors.Count);

            System.Diagnostics.Debug.Assert(sun_vectors.Count <= 256 * 256 * 256);

            // Calculate psr image; parallelize over patches
            var options = new ParallelOptions {
                MaxDegreeOfParallelism = ViperEnvironment.MaxDegreeOfParallelism
            };                                                                                                       //TODO: Environment.ProcessorCount - 2 isn't working

            Parallel.ForEach(_patches, options,
                             patch =>
            {
                patch.FillPointsAndMatrices(ViperEnvironment.Terrain);
                var base_row = (patch.Id.Y - IdBounds.Top) * side;
                var base_col = (patch.Id.X - IdBounds.Left) * side;
                for (var row = 0; row < side; row++)
                {
                    var row1 = row + base_row;
                    for (var col = 0; col < side; col++)
                    {
                        var horizon = patch.Horizons[row][col];
                        var sum     = 0;
                        var time    = 0;
                        for (var svi = 0; svi < sun_vectors.Count; svi++)
                        {
                            var sun = sun_vectors[svi];
                            patch.GetAzEl(sun, col, row, out float sun_azimuth_rad, out float sun_elevation_rad);
                            var val = (int)(255f * horizon.SunFraction2(sun_azimuth_rad * 180f / 3.141592653589f, sun_elevation_rad * 180f / 3.141592653589f));
                            sum    += val;
                            time   += Math.Sign(val);
                        }
Beispiel #2
0
        void FillAzimuthElevation()
        {
            var       center_patch = GetCenterPatch();
            var       center_pt    = center_patch.PointInPatch(new Point(TerrainPatch.DEM_size / 2, TerrainPatch.DEM_size / 2));
            var       mat          = center_patch.Matrices[center_pt.Y][center_pt.X];
            const int per_degree   = 4;
            const int count        = 360 * per_degree;
            var       slope_array  = Enumerable.Range(0, count).Select(i => float.MinValue).ToArray();
            var       vec_array    = new PointF[count];
            var       stop         = TileLightingProductManager.MetonicCycleStop;
            var       step         = TileLightingProductManager.MetonicCycleStep;
            var       temp         = new Vector3d();

            for (var time = TileLightingProductManager.MetonicCycleStart; time <= stop; time += step)
            {
                var sun = CSpice.SunPosition(time);
                TerrainPatch.Transform(ref sun, ref mat, ref temp);
                var sun_x       = temp[0];
                var sun_y       = temp[1];
                var sun_z       = temp[2];
                var azimuth_rad = Math.Atan2(sun_y, sun_x) + Math.PI;  // [0,2PI]
                var azimuth_deg = azimuth_rad * 180d / Math.PI;
                var index       = (int)(azimuth_deg * per_degree);
                var alen        = Math.Sqrt(sun_x * sun_x + sun_y * sun_y);
                var slope       = (float)(sun_z / alen);
                if (slope > slope_array[index])
                {
                    slope_array[index] = slope;
                    vec_array[index]   = new PointF((float)(sun_x / alen), (float)(sun_y / alen));
                }
            }
            var slope_list = new List <float>();
            var vec_list   = new List <PointF>();

            for (var i = 0; i < slope_array.Length; i++)
            {
                var s = slope_array[i];
                if (s > float.MinValue)
                {
                    slope_list.Add(s);
                    vec_list.Add(vec_array[i]);
                }
            }
            cpu_slope    = slope_array.ToArray();
            cpu_vector_x = vec_list.Select(p => p.X).ToArray();
            cpu_vector_y = vec_list.Select(p => p.Y).ToArray();
        }
        void PrepareSlopeArray(DateTime start, DateTime stop, TimeSpan step)
        {
            const int bins = 4 * 360;
            var       flip = -LonFactor;

            for (var i = 0; i < bins; i++)
            {
                cpu_slope[i] = float.MaxValue;
            }

            var elev = cpu_slope;

            for (var time = start; time <= stop; time += step)
            {
                var vec           = CSpice.SunPosition(time);
                var x             = vec[0];
                var y             = vec[1];
                var z             = vec[2];
                var alen          = Math.Sqrt(x * x + y * y);
                var azimuth_rad   = (float)(Math.Atan2(y, x) + Math.PI); // [0,2PI]
                var azimuth_index = (int)((azimuth_rad / (2 * Math.PI)) * bins);
                var slope         = flip * z / alen;
                if (slope < elev[azimuth_index])
                {
                    elev[azimuth_index] = (float)slope;
                }
            }

            if (false)
            {
                for (var i = 0; i < elev.Length; i++)
                {
                    elev[i] = 0f;
                }
            }
        }
        public void WriteSafeHavenGeotiffs(string path)
        {
            var outer_start = Start.AddDays(-28);
            var outer_stop  = Stop.AddDays(28);

            GetLowEarthTimes(outer_start, outer_stop, out List <DateTime> times_start_to_stop, out List <int> indices_of_minima_earth_elevation);

            for (var i = 0; i < indices_of_minima_earth_elevation.Count; i++)
            {
                Console.WriteLine($"i={i} index={indices_of_minima_earth_elevation[i]} time={times_start_to_stop[indices_of_minima_earth_elevation[i]]}");
            }
            var region_width  = Region.Width;
            var region_height = Region.Height;

            var combined     = new float[region_height, region_width];
            var month_images = Enumerable.Range(0, indices_of_minima_earth_elevation.Count).Select(i => new float[region_height, region_width]).ToList();

            var sun_vectors   = times_start_to_stop.Select(time => CSpice.SunPosition(time)).ToList();
            var earth_vectors = times_start_to_stop.Select(time => CSpice.EarthPosition(time)).ToList();

            // Get the indexes in the time and vector arrays of Start and Stop
            var first_inside = times_start_to_stop.Select((time, index) => (time, index)).Where(pair => pair.time >= Start).Select(pair => pair.index).First();
            var last_inside  = -1;

            for (var i = times_start_to_stop.Count - 1; i >= 0; i--)
            {
                if (times_start_to_stop[i] <= Stop)
                {
                    last_inside = i;
                    break;
                }
            }

            //var debugpt = new Point(Region.Left + 545, Region.Top + 490);
            //debugpt = new Point(Region.Left + 494, Region.Top + 438);
            var ids = TerrainPatch.EnumerateIds(TerrainPatch.CoveringIdRectangle(Region)).ToList();

            {
                var not_generated = ids.Where(id => !File.Exists(TerrainPatch.FromId(id, ObserverHeightInMeters).Path)).ToList();
                Console.WriteLine($"{not_generated.Count} patches haven't been generated yet.  Generating them.");
                var gpuProcessor = ViperEnvironment.Processor as CPUHorizons;
                var queue        = not_generated.Select(id => TerrainPatch.FromId(id)).ToList();
                gpuProcessor.RunQueue(queue, writeHorizons: WriteHorizons, unloadHorizons: true);
            }

            Parallel.ForEach(ids,
                             new ParallelOptions {
                MaxDegreeOfParallelism = ViperEnvironment.MaxDegreeOfParallelism
            },
                             id =>
            {
                var patch = GetPatchWithHorizons(id, ObserverHeightInMeters);
                for (var row = 0; row < TerrainPatch.DefaultSize; row++)
                {
                    var region_row = (patch.Line + row) - Region.Y;
                    if (region_row < 0 || region_row >= region_height)
                    {
                        continue;
                    }
                    for (var col = 0; col < TerrainPatch.DefaultSize; col++)
                    {
                        //if ((patch.Line + row) != debugpt.Y || (patch.Sample + col) != debugpt.X)
                        //    continue;
                        var region_col = patch.Sample + col - Region.X;
                        if (region_col < 0 || region_col >= region_width)
                        {
                            continue;
                        }
                        var has_sun     = patch.GetLightCurve(row, col, sun_vectors).Select(sun => sun >= SafeHavenSunThreshold).ToList();
                        var has_comm    = patch.GetEarthOverHorizonCurve(row, col, earth_vectors).Select(rise => rise >= EarthMultipathThreshold).ToList();
                        var month_steps = MaxShadowWithoutComm2(indices_of_minima_earth_elevation, has_sun, has_comm);
                        combined[region_row, region_col] = 2f * month_steps.Max();
                        for (var i = 0; i < month_steps.Count; i++)
                        {
                            month_images[i][region_row, region_col] = 2f * month_steps[i];
                        }
                    }
                }
            });

            {
                var path_combined = LandingSiteDataset.AppendToFilename(path, "_combined");
                GeotiffHelper.WriteArrayAsGeotiff(combined, Region, path_combined);
                WriteSafeHavenOverlay(combined, path_combined);
            }

            for (var i = 0; i < month_images.Count; i++)
            {
                var time  = times_start_to_stop[indices_of_minima_earth_elevation[i]];
                var path1 = LandingSiteDataset.AppendToFilename(path, "_" + time.ToString("yyyy-MM-dd"));
                GeotiffHelper.WriteArrayAsGeotiff(month_images[i], Region, path1);
                WriteSafeHavenOverlay(month_images[i], path1);
            }
        }