/// <summary> /// Calculates the approximate area of a point on a map projection with the given /// characteristics, by transforming the point and its nearest neighbors to latitude and /// longitude, calculating the midpoints between them, and calculating the area of the /// region enclosed within those midpoints. /// </summary> /// <param name="radius">The radius of the planet.</param> /// <param name="x">The x coordinate of a point on a map projection, with zero as the /// westernmost point.</param> /// <param name="y">The y coordinate of a point on a map projection, with zero as the /// northernmost point.</param> /// <param name="resolution">The vertical resolution of the projection.</param> /// <param name="options"> /// The map projection options used to generate the map used. /// </param> /// <returns>The area of the given point, in m².</returns> public static HugeNumber GetAreaOfPoint( HugeNumber radius, int x, int y, int resolution, MapProjectionOptions options) => GetAreaOfPointFromRadiusSquared( radius.Square(), x, y, (int)Math.Floor(resolution * options.AspectRatio), resolution, options);
/// <summary> /// Calculates the approximate area of a point on a map projection with the given /// characteristics, by transforming the point and its nearest neighbors to latitude and /// longitude, calculating the midpoints between them, and calculating the area of the /// region enclosed within those midpoints. /// </summary> /// <param name="region">The mapped region.</param> /// <param name="planet">The mapped planet.</param> /// <param name="x">The x coordinate of a point on a map projection, with zero as the /// westernmost point.</param> /// <param name="y">The y coordinate of a point on a map projection, with zero as the /// northernmost point.</param> /// <param name="resolution">The vertical resolution of the projection.</param> /// <param name="options"> /// The map projection options used to generate the map used. /// </param> /// <returns>The area of the given point, in m².</returns> public static HugeNumber GetAreaOfLocalPoint( this SurfaceRegion region, Planetoid planet, int x, int y, int resolution, MapProjectionOptions options) => SurfaceMap.GetAreaOfPointFromRadiusSquared( planet.RadiusSquared, x, y, (int)Math.Floor(resolution * options.AspectRatio), resolution, region.GetProjection(planet, options.EqualArea));
public void EarthlikePlanet() { // First run to ensure timed runs do not include any one-time initialization costs. _ = Planetoid.GetPlanetForSunlikeStar(out _); var stopwatch = new Stopwatch(); stopwatch.Start(); var planet = Planetoid.GetPlanetForSunlikeStar(out _); stopwatch.Stop(); Assert.IsNotNull(planet); Console.WriteLine($"Planet generation time: {stopwatch.Elapsed:s'.'FFF} s"); Console.WriteLine($"Radius: {planet!.Shape.ContainingRadius / 1000:N0} km"); Console.WriteLine($"Surface area: {planet!.Shape.ContainingRadius.Square() * HugeNumberConstants.FourPi / 1000000:N0} km²"); stopwatch.Restart(); using (var elevationMap = planet.GetElevationMap(MapResolution)) { var(winterTemperatureMap, summerTemperatureMap) = planet.GetTemperatureMaps(elevationMap, MapResolution); var(precipitationMaps, snowfallMaps) = planet .GetPrecipitationAndSnowfallMaps(winterTemperatureMap, summerTemperatureMap, MapResolution, Seasons); for (var i = 0; i < snowfallMaps.Length; i++) { snowfallMaps[i].Dispose(); } using var precipitationMap = SurfaceMapImage.AverageImages(precipitationMaps); for (var i = 0; i < precipitationMaps.Length; i++) { precipitationMaps[i].Dispose(); } _ = new WeatherMaps( planet, elevationMap, winterTemperatureMap, summerTemperatureMap, precipitationMap, MapResolution, MapProjectionOptions.Default); winterTemperatureMap.Dispose(); summerTemperatureMap.Dispose(); } stopwatch.Stop(); Console.WriteLine($"Equirectangular surface map generation time: {stopwatch.Elapsed:s'.'FFF} s"); var projection = new MapProjectionOptions(equalArea: true); stopwatch.Restart(); using var elevationMapEA = planet.GetElevationMap(MapResolution, projection); var(winterTemperatureMapEA, summerTemperatureMapEA) = planet.GetTemperatureMaps(elevationMapEA, MapResolution, projection, projection); using var temperatureMapEA = SurfaceMapImage.AverageImages(winterTemperatureMapEA, summerTemperatureMapEA); var(precipitationMapsEA, snowfallMapsEA) = planet .GetPrecipitationAndSnowfallMaps(winterTemperatureMapEA, summerTemperatureMapEA, MapResolution, Seasons, projection, projection); for (var i = 0; i < snowfallMapsEA.Length; i++) { snowfallMapsEA[i].Dispose(); } using var precipitationMapEA = SurfaceMapImage.AverageImages(precipitationMapsEA); for (var i = 0; i < precipitationMapsEA.Length; i++) { precipitationMapsEA[i].Dispose(); } var climateMapsEA = new WeatherMaps( planet, elevationMapEA, winterTemperatureMapEA, summerTemperatureMapEA, precipitationMapEA, MapResolution, projection); winterTemperatureMapEA.Dispose(); summerTemperatureMapEA.Dispose(); stopwatch.Stop(); Console.WriteLine($"Cylindrical equal-area surface map generation time: {stopwatch.Elapsed:s'.'FFF} s"); var normalizedSeaLevel = planet.SeaLevel / planet.MaxElevation; var elevationRange = planet.GetElevationRange(elevationMapEA); var landCoords = 0; if (planet.Hydrosphere?.IsEmpty == false) { for (var x = 0; x < elevationMapEA.Width; x++) { for (var y = 0; y < elevationMapEA.Height; y++) { var value = (2.0 * elevationMapEA[x, y].PackedValue / ushort.MaxValue) - 1; if (value - normalizedSeaLevel > 0) { landCoords++; } } } } var sb = new StringBuilder(); AddTempString(sb, temperatureMapEA); sb.AppendLine(); AddTerrainString(sb, planet, elevationMapEA, landCoords); sb.AppendLine(); AddClimateString(sb, elevationMapEA, normalizedSeaLevel, landCoords, climateMapsEA); sb.AppendLine(); AddPrecipitationString(sb, planet, elevationMapEA, precipitationMapEA, normalizedSeaLevel, landCoords, climateMapsEA); Console.WriteLine(sb.ToString()); }