/// <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); }
public static SunVectorCache GetSingleton() => _singleton != null ? _singleton : _singleton = new SunVectorCache();