/// <summary> /// Map over the fraction of the sun's disk visible times Cos(theta) - theta is the angle between the sun and normal /// </summary> /// <param name="line"></param> /// <param name="sample"></param> /// <param name="start"></param> /// <param name="stop"></param> /// <param name="step"></param> /// <param name="action"></param> /// <returns></returns> public bool MapOverSunContribution(int line, int sample, DateTime start, DateTime stop, TimeSpan step, Action <DateTime, float> action) { var id = TerrainPatch.LineSampleToId(line, sample); var patch = GetPatch(id); if (patch == null) { return(false); } var cross = GetSurfaceNormal(line, sample); var y_offset = line - patch.Line; var x_offset = sample - patch.Sample; var mat = patch.Matrices[y_offset][x_offset]; var horizon = patch.Horizons[y_offset][x_offset]; if (!horizon.IsDegrees) { lock (horizon) horizon.ConvertSlopeToDegrees(); } var cache = SunVectorCache.GetSingleton(); var temp = new Vector3d(); for (var time = start; time <= stop; time += step) { var sunvec = cache.SunPosition(time); TerrainPatch.Transform(ref sunvec, 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 = (float)(azimuth_rad * 180d / Math.PI); var alen = Math.Sqrt(sun_x * sun_x + sun_y * sun_y); var slope = sun_z / alen; var elevation_deg = ((float)Math.Atan(slope)) * 180f / 3.141592653589f; var sunfrac = horizon.SunFraction2(azimuth_deg, elevation_deg); //if (line == 17522 && sample == 12388) //{ // Console.WriteLine($"{line},{sample}, time={time} elevation_deg={elevation_deg} sun={sunfrac}"); //} sunvec.NormalizeFast(); // Normalize before calculating surface temp var dot = Vector3d.Dot(sunvec, cross); var sun_contrib = dot < 0d ? 0d : sunfrac * dot; //if (sun_contrib > 0) // Console.WriteLine(sun_contrib); action(time, (float)sun_contrib); } return(true); }
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 void MapOverLightCurve(int line, int sample, DateTime start, DateTime stop, TimeSpan step, Action <DateTime, float> action) { var id = TerrainPatch.LineSampleToId(line, sample); var patch = GetPatch(id); if (patch == null) { return; } var y_offset = line - patch.Line; var x_offset = sample - patch.Sample; var mat = patch.Matrices[y_offset][x_offset]; var horizon = patch.Horizons[y_offset][x_offset]; if (!horizon.IsDegrees) { lock (horizon) horizon.ConvertSlopeToDegrees(); } var cache = SunVectorCache.GetSingleton(); var temp = new Vector3d(); for (var time = start; time <= stop; time += step) { var sunvec = cache.SunPosition(time); TerrainPatch.Transform(ref sunvec, 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 = (float)(azimuth_rad * 180d / Math.PI); var alen = Math.Sqrt(sun_x * sun_x + sun_y * sun_y); var slope = sun_z / alen; var elevation_deg = ((float)Math.Atan(slope)) * 180f / 3.141592653589f; var sun = horizon.SunFraction2(azimuth_deg, elevation_deg); //Console.WriteLine($"time={time} elevation_deg={elevation_deg} sun={sun}"); action(time, sun); } }
protected override void OnPaint(PaintEventArgs e) { if (!ReadyToRender()) { return; } if (_bitmap == null || _bitmap.Width != Width || _bitmap.Height != Height) { _bitmap?.Dispose(); _bitmap = new Bitmap(Width, Height, PixelFormat.Format32bppArgb); } Patch.FillPointsAndMatrices(Terrain); var m = Patch.Matrices[PointInPatch.Y][PointInPatch.X]; var temp = new Vector3d(); TerrainPatch.Transform(ref ShadowCaster, ref m, ref temp); var x = temp[0]; var y = temp[1]; var z = temp[2]; var azimuth_rad = Math.Atan2(y, x) + Math.PI; // [0,2PI] var alen = Math.Sqrt(x * x + y * y); var slope = z / alen; var elevation_deg = ((float)Math.Atan(slope)) * 180f / 3.141592653589f; var normalized_azimuth = azimuth_rad / (2d * Math.PI); // range [0,1) var horizon_index_f = (float)(Horizon.HorizonSamplesD * normalized_azimuth); var buf = Patch.Horizons[PointInPatch.Y][PointInPatch.X].Buffer; var width = _bitmap.Width; var height = _bitmap.Height; var sunCenter = new Point(width / 2, height / 2); var sunRadius = 8; // was 20 // The width of a single slat in pixels const float sun_width_deg = .25f; var slat_width = sunRadius; // .25 deg var slat_width2 = slat_width / 2; // The index of the slat that 'covers' the sun's center var index_center = (int)horizon_index_f; var center_slat_left = (int)((sunCenter.X - (horizon_index_f - index_center) * sunRadius) + 0.5f); //Console.WriteLine($"caster render idx={index_center} horizon_elev={LookupHorizon(buf, index_center)} sun_elev={elevation_deg}"); var span = (width / 2) / sunRadius + 1; var span2 = 2 * span; using (var g = Graphics.FromImage(_bitmap)) { g.FillRectangle(Brushes.White, 0, 0, _bitmap.Width, _bitmap.Height); g.FillEllipse(Brushes.Yellow, sunCenter.X - sunRadius, sunCenter.Y - sunRadius, sunRadius * 2, sunRadius * 2); for (var slat_offset = -span; slat_offset <= span2; slat_offset++) { var slat_left = center_slat_left + slat_offset * slat_width; var slat_index = index_center + slat_offset; var slat_angle1 = LookupHorizon(buf, slat_index); var slat_angle2 = LookupHorizon(buf, slat_index - 1); var slat_top1 = sunCenter.Y + ((elevation_deg - slat_angle1) / sun_width_deg) * sunRadius; var slat_top2 = sunCenter.Y + ((elevation_deg - slat_angle2) / sun_width_deg) * sunRadius; //Console.WriteLine($" slat_top={slat_top1} slat_angle={slat_angle1}"); var top = Math.Max(0, slat_top1); g.FillRectangle(_grayBrush, slat_left, top, slat_width, height); g.DrawRectangle(Pens.DarkGray, slat_left, top, slat_width, height); g.DrawLine(Pens.Red, slat_left - slat_width2, slat_top2, slat_left + slat_width2, slat_top1); } var azimuth_deg = azimuth_rad * 180d / Math.PI; var frac = SunFraction2(g, sunCenter, sunRadius, buf, (float)azimuth_deg, elevation_deg); Console.WriteLine($"sun frac={frac}"); } e.Graphics.DrawImage(_bitmap, 0, 0); }