// Return all times from start to stop. Also return the indexes of the times at which the earth elevation reaches a minima void GetLowEarthTimes(DateTime outer_start, DateTime outer_stop, out List <DateTime> all_times, out List <int> indices_of_minima_earth_elevation) { var center = new Point(Region.Left + Region.Width / 2, Region.Top + Region.Height / 2); var centerPatch = ViperEnvironment.GetPatch(TerrainPatch.LineSampleToId(center)); centerPatch.FillMatrices(ViperEnvironment.Terrain); // Generate the time / elevation pairs all_times = new List <DateTime>(); for (var time = outer_start; time <= outer_stop; time += Step) { all_times.Add(time); } var earth_elevations = all_times.Select(t => { centerPatch.GetAzEl(CSpice.EarthPosition(t), 0, 0, out float _, out float earth_elevation_rad); return(earth_elevation_rad); }).ToList(); // Find minima indices_of_minima_earth_elevation = new List <int>(); for (var i = 1; i < earth_elevations.Count - 1; i++) { if (Start <= all_times[i] && all_times[i] <= Stop && earth_elevations[i - 1] > earth_elevations[i] && earth_elevations[i] < earth_elevations[i + 1]) { indices_of_minima_earth_elevation.Add(i); } } }
public override void SunEarthAzEl(DateTime time, out double sunAzimuth, out double sunElevation, out double earthAzimuth, out double earthElevation) { //sunAzimuth = sunElevation = earthAzimuth = earthElevation = 0d; //return; var et = DateTimeToET(time); var state = new double[6]; double lt = 0d; double[] pos = { 0d, 0d, 0d }; CSpice.spkgeo_c(SunId, et, "MOON_ME", MoonId, state, ref lt); CSpice.spkcpo_c("SUN", et, "SITE_TOPO", "CENTER", "NONE", pos, "MOON", "MOON_ME", state, ref lt); //var d = Math.Sqrt(state[0] * state[0] + state[1] * state[1] + state[2] * state[2]); //Console.WriteLine(@"HERMITE: Sun= dist={3} vec=[{0},{1},{2}]", state[0], state[1], state[2], d); sunAzimuth = -Math.Atan2(state[1], state[0]); var flatd = Math.Sqrt(state[0] * state[0] + state[1] * state[1]); sunElevation = Math.Atan2(state[2], flatd); CSpice.spkcpo_c("EARTH", et, "SITE_TOPO", "CENTER", "NONE", pos, "MOON", "MOON_ME", state, ref lt); //d = Math.Sqrt(state[0] * state[0] + state[1] * state[1] + state[2] * state[2]); //Console.WriteLine(@"HERMITE: Earth= dist={3} vec=[{0},{1},{2}]", state[0], state[1], state[2], d); earthAzimuth = -Math.Atan2(state[1], state[0]); flatd = Math.Sqrt(state[0] * state[0] + state[1] * state[1]); earthElevation = Math.Atan2(state[2], flatd); }
private void ProjectPoint(double[] rectan, ref PointF p) { double r = 0, lat_rad = 0, lon_rad = 0; CSpice.reclat_c(rectan, ref r, ref lon_rad, ref lat_rad); InMemoryInt16Terrain.GetLineSample(lat_rad, lon_rad, out int line, out int sample); p.X = sample; p.Y = line; }
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); }
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(); }
public Vector3d EarthPosition(DateTime time) { lock (this) { var ticks = time.Ticks; var rep = ticks - (ticks / _minimumStep); if (_earthCache.TryGetValue(rep, out Vector3d v)) { return(v); } var et = (rep - _epoch) / 10000000L + 3d; double lt = 0d; CSpice.spkgeo_c(EarthId, et, "MOON_ME", MoonId, _state, ref lt); v = new Vector3d(_state[0], _state[1], _state[2]); if (_earthCache.Count < MaxCacheCount) { _earthCache.Add(rep, v); } return(v); } }
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 static void Furnish(string path) { Console.WriteLine(@"Spice furnishing {0}", path); CSpice.furnsh_c(path); }
public override void DSNAzEl(DateTime time, double lat, double lon, double height, out double dsnaz, out double dsnel) { const double stationHorizonMask = 10d * Math.PI / 190d; var siteLat = lat * Math.PI / 180d; var siteLon = lon * Math.PI / 180d; double[] traverseSite = { 0d, 0d, 0d }; CSpice.pgrrec_c("MOON", siteLon, siteLat, 0d, MoonRadius, 0f, traverseSite); var pz = MoonRadius * Math.Sin(siteLat); var temp = MoonRadius * Math.Cos(siteLat); var px = temp * Math.Cos(siteLon); var py = temp * Math.Sin(siteLon); Debug.Assert(Math.Abs(px - traverseSite[0]) < 1d); Debug.Assert(Math.Abs(py - traverseSite[1]) < 1d); Debug.Assert(Math.Abs(pz - traverseSite[2]) < 1d); var et = DateTimeToET(time); var state = new double[6]; var earthState = new double[6]; var moonPositionFromStation = new double[3]; double lt = 0d; CSpice.spkcpo_c("EARTH", et, "SITE_TOPO", "CENTER", "NONE", traverseSite, "MOON", "MOON_ME", earthState, ref lt); var earthAzimuth = -Math.Atan2(earthState[1], earthState[0]); var flatd1 = Math.Sqrt(earthState[0] * earthState[0] + earthState[1] * earthState[1]); var earthElevation = Math.Atan2(earthState[2], flatd1); var data = new List <DSNSiteData>(); for (var i = 0; i < DSNSiteNames.Length; i++) { // Station to the traverse site CSpice.spkezp_c(MoonId, et, DSNSiteFrames[i], "NONE", DSNIds[i], moonPositionFromStation, ref lt); var moonElevation = Math.Atan2(moonPositionFromStation[2], Math.Sqrt(moonPositionFromStation[0] * moonPositionFromStation[0] + moonPositionFromStation[1] * moonPositionFromStation[1])); // Traverse site to the station CSpice.spkcpo_c(DSNSiteNames[i], et, "SITE_TOPO", "CENTER", "NONE", traverseSite, "MOON", "MOON_ME", state, ref lt); var flatd = Math.Sqrt(state[0] * state[0] + state[1] * state[1]); data.Add(new DSNSiteData { SiteToStationAzimuth = -Math.Atan2(state[1], state[0]), SiteToStationElevation = Math.Atan2(state[2], flatd), StationToMoonElevation = moonElevation, Site = DSNSiteNames[i] }); } foreach (var d in data) { Console.WriteLine("complex={0} elev@complex={1} complexElev@traverse={2} complexAz@traverse={3}", d.Site, d.StationToMoonElevation, d.SiteToStationElevation, d.SiteToStationAzimuth); } DSNSiteData bestData = null; const double highestElev = double.MinValue; foreach (var d in data) { if (d.StationToMoonElevation >= stationHorizonMask && d.SiteToStationElevation > highestElev) { bestData = d; } } if (bestData == null) { Console.WriteLine(@"Couldn't find a suitable ground complex. Using {0}", data[0].Site); bestData = data[0]; } dsnaz = bestData.SiteToStationAzimuth; dsnel = bestData.SiteToStationElevation; Console.WriteLine(@"moon center"); Console.WriteLine(@" earth az={0}", earthAzimuth); Console.WriteLine(@" earth el={0}", earthElevation); Console.WriteLine(@"To {0}", bestData.Site); Console.WriteLine(@" earth az={0}", bestData.SiteToStationAzimuth); Console.WriteLine(@" earth el={0}", bestData.SiteToStationElevation); }
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); } }