/// <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);
        }
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();
        }
Beispiel #3
0
        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);
            }
        }
Beispiel #4
0
        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);
        }