Пример #1
0
    /// <summary>
    /// Gets the <see cref="BiomeType"/> associated with the given conditions.
    /// </summary>
    /// <param name="climateType">The climate type of the location.</param>
    /// <param name="humidityType">The humidity type of the location.</param>
    /// <param name="elevation">The elevation of the location above sea level.</param>
    /// <returns>The <see cref="BiomeType"/> associated with the given conditions.</returns>
    public static BiomeType GetBiomeType(ClimateType climateType, HumidityType humidityType, double elevation)
    {
        if (elevation <= 0)
        {
            return(BiomeType.Sea);
        }

        switch (climateType)
        {
        case ClimateType.Polar:
            return(elevation >= 0.15 ? BiomeType.Alpine : BiomeType.Polar);

        case ClimateType.Subpolar:
            return(elevation >= 0.15 ? BiomeType.Subalpine : BiomeType.Tundra);

        case ClimateType.Boreal:
            if (humidityType <= HumidityType.Arid)
            {
                return(BiomeType.LichenWoodland);
            }
            else
            {
                return(BiomeType.ConiferousForest);
            }

        case ClimateType.CoolTemperate:
            if (humidityType <= HumidityType.Perarid)
            {
                return(BiomeType.ColdDesert);
            }
            else if (humidityType == HumidityType.Arid)
            {
                return(BiomeType.Steppe);
            }
            else
            {
                return(BiomeType.MixedForest);
            }

        case ClimateType.WarmTemperate:
            if (humidityType <= HumidityType.Perarid)
            {
                return(BiomeType.HotDesert);
            }
            else if (humidityType <= HumidityType.Arid)
            {
                return(BiomeType.Shrubland);
            }
            else
            {
                return(BiomeType.DeciduousForest);
            }

        case ClimateType.Subtropical:
            if (humidityType <= HumidityType.Perarid)
            {
                return(BiomeType.HotDesert);
            }
            else if (humidityType == HumidityType.Arid)
            {
                return(BiomeType.Savanna);
            }
            else if (humidityType <= HumidityType.Subhumid)
            {
                return(BiomeType.MonsoonForest);
            }
            else
            {
                return(BiomeType.RainForest);
            }

        case ClimateType.Tropical:
            if (humidityType <= HumidityType.Perarid)
            {
                return(BiomeType.HotDesert);
            }
            else if (humidityType <= HumidityType.Semiarid)
            {
                return(BiomeType.Savanna);
            }
            else if (humidityType == HumidityType.Subhumid)
            {
                return(BiomeType.MonsoonForest);
            }
            else
            {
                return(BiomeType.RainForest);
            }

        default:
            return(BiomeType.HotDesert);
        }
    }
Пример #2
0
    /// <summary>
    /// Initializes a new instance of <see cref="WeatherMaps"/>.
    /// </summary>
    /// <param name="planet">The planet being mapped.</param>
    /// <param name="elevationMap">An elevation map.</param>
    /// <param name="winterTemperatureMap">A winter temperature map.</param>
    /// <param name="summerTemperatureMap">A summer temperature map.</param>
    /// <param name="precipitationMap">A precipitation map.</param>
    /// <param name="resolution">The intended vertical resolution of the maps.</param>
    /// <param name="options">
    /// The map projection options to use. All the map images must have been generated using
    /// these same options, or thew results will not be accurate.
    /// </param>
    public WeatherMaps(
        Planetoid planet,
        Image <L16> elevationMap,
        Image <L16> winterTemperatureMap,
        Image <L16> summerTemperatureMap,
        Image <L16> precipitationMap,
        int resolution,
        MapProjectionOptions?options = null)
    {
        var projection = options ?? MapProjectionOptions.Default;

        XLength = (int)Math.Floor(projection.AspectRatio * resolution);
        YLength = resolution;

        BiomeMap   = new BiomeType[XLength][];
        ClimateMap = new ClimateType[XLength][];
        var humidityMap = new HumidityType[XLength][];

        SeaIceRangeMap = new FloatRange[XLength][];

        for (var x = 0; x < XLength; x++)
        {
            BiomeMap[x]       = new BiomeType[YLength];
            ClimateMap[x]     = new ClimateType[YLength];
            humidityMap[x]    = new HumidityType[YLength];
            SeaIceRangeMap[x] = new FloatRange[YLength];
        }

        var scale          = SurfaceMap.GetScale(resolution, projection.Range);
        var stretch        = scale / projection.ScaleFactor;
        var elevationScale = SurfaceMap.GetScale(elevationMap.Height, projection.Range);
        var winterScale    = winterTemperatureMap.Height == elevationMap.Height
            ? elevationScale
            : SurfaceMap.GetScale(winterTemperatureMap.Height, projection.Range);
        var summerScale = summerTemperatureMap.Height == elevationMap.Height
            ? elevationScale
            : SurfaceMap.GetScale(summerTemperatureMap.Height, projection.Range);
        var precipitationScale = precipitationMap.Height == elevationMap.Height
            ? elevationScale
            : SurfaceMap.GetScale(precipitationMap.Height, projection.Range);

        var totalElevation    = 0.0;
        var minTemperature    = 5000.0f;
        var maxTemperature    = 0.0f;
        var totalTemperature  = 0.0f;
        var totalPrecipiation = 0.0;
        var xToEX             = new Dictionary <int, int>();
        var xToWX             = new Dictionary <int, int>();
        var xToSX             = new Dictionary <int, int>();
        var xToPX             = new Dictionary <int, int>();

        for (var y = 0; y < YLength; y++)
        {
            var latitude = projection.EqualArea
                ? SurfaceMap.GetLatitudeOfCylindricalEqualAreaProjection(y, resolution, scale, projection)
                : SurfaceMap.GetLatitudeOfEquirectangularProjection(y, resolution, scale, projection);

            var elevationY = projection.EqualArea
                ? SurfaceMap.GetCylindricalEqualAreaYFromLatWithScale(latitude, elevationMap.Height, elevationScale, projection)
                : SurfaceMap.GetEquirectangularYFromLatWithScale(latitude, elevationMap.Height, elevationScale, projection);
            var elevationSpan = elevationMap.GetPixelRowSpan(elevationY);

            int winterY;
            if (winterTemperatureMap.Height == elevationMap.Height)
            {
                winterY = elevationY;
            }
            else if (projection.EqualArea)
            {
                winterY = SurfaceMap.GetCylindricalEqualAreaYFromLatWithScale(latitude, winterTemperatureMap.Height, winterScale, projection);
            }
            else
            {
                winterY = SurfaceMap.GetEquirectangularYFromLatWithScale(latitude, winterTemperatureMap.Height, winterScale, projection);
            }

            var winterSpan = winterTemperatureMap.GetPixelRowSpan(winterY);

            int summerY;
            if (summerTemperatureMap.Height == elevationMap.Height)
            {
                summerY = elevationY;
            }
            else if (projection.EqualArea)
            {
                summerY = SurfaceMap.GetCylindricalEqualAreaYFromLatWithScale(latitude, summerTemperatureMap.Height, summerScale, projection);
            }
            else
            {
                summerY = SurfaceMap.GetEquirectangularYFromLatWithScale(latitude, summerTemperatureMap.Height, summerScale, projection);
            }

            var summerSpan = summerTemperatureMap.GetPixelRowSpan(summerY);

            int precipitationY;
            if (precipitationMap.Height == elevationMap.Height)
            {
                precipitationY = elevationY;
            }
            else if (projection.EqualArea)
            {
                precipitationY = SurfaceMap.GetCylindricalEqualAreaYFromLatWithScale(latitude, precipitationMap.Height, precipitationScale, projection);
            }
            else
            {
                precipitationY = SurfaceMap.GetEquirectangularYFromLatWithScale(latitude, precipitationMap.Height, precipitationScale, projection);
            }

            var precipitationSpan = precipitationMap.GetPixelRowSpan(precipitationY);

            for (var x = 0; x < XLength; x++)
            {
                if (!xToEX.TryGetValue(x, out var elevationX))
                {
                    var longitude = projection.EqualArea
                        ? SurfaceMap.GetLongitudeOfCylindricalEqualAreaProjection(x, XLength, scale, projection)
                        : SurfaceMap.GetLongitudeOfEquirectangularProjection(x, XLength, stretch, projection);

                    elevationX = projection.EqualArea
                        ? SurfaceMap.GetCylindricalEqualAreaXFromLonWithScale(longitude, elevationMap.Width, elevationScale, projection)
                        : SurfaceMap.GetEquirectangularXFromLonWithScale(longitude, elevationMap.Width, elevationScale, projection);
                    int wX;
                    if (winterTemperatureMap.Width == elevationMap.Width)
                    {
                        wX = elevationX;
                    }
                    else if (projection.EqualArea)
                    {
                        wX = SurfaceMap.GetCylindricalEqualAreaXFromLonWithScale(longitude, winterTemperatureMap.Width, winterScale, projection);
                    }
                    else
                    {
                        wX = SurfaceMap.GetEquirectangularXFromLonWithScale(longitude, winterTemperatureMap.Width, winterScale, projection);
                    }

                    int sX;
                    if (summerTemperatureMap.Width == elevationMap.Width)
                    {
                        sX = elevationX;
                    }
                    else if (projection.EqualArea)
                    {
                        sX = SurfaceMap.GetCylindricalEqualAreaXFromLonWithScale(longitude, summerTemperatureMap.Width, summerScale, projection);
                    }
                    else
                    {
                        sX = SurfaceMap.GetEquirectangularXFromLonWithScale(longitude, summerTemperatureMap.Width, summerScale, projection);
                    }

                    int pX;
                    if (precipitationMap.Width == elevationMap.Width)
                    {
                        pX = elevationX;
                    }
                    else if (projection.EqualArea)
                    {
                        pX = SurfaceMap.GetCylindricalEqualAreaXFromLonWithScale(longitude, precipitationMap.Width, precipitationScale, projection);
                    }
                    else
                    {
                        pX = SurfaceMap.GetEquirectangularXFromLonWithScale(longitude, precipitationMap.Width, precipitationScale, projection);
                    }

                    xToEX.Add(x, elevationX);
                    xToWX.Add(x, wX);
                    xToSX.Add(x, sX);
                    xToPX.Add(x, pX);
                }
                var winterX        = xToWX[x];
                var summerX        = xToSX[x];
                var precipitationX = xToPX[x];

                var normalizedElevation = elevationSpan[elevationX].GetValueFromPixel_PosNeg() - planet.NormalizedSeaLevel;
                totalElevation += normalizedElevation;

                var winterTemperature = (float)(winterSpan[winterX].GetValueFromPixel_Pos() * SurfaceMapImage.TemperatureScaleFactor);
                var summerTemperature = (float)(summerSpan[summerX].GetValueFromPixel_Pos() * SurfaceMapImage.TemperatureScaleFactor);
                minTemperature    = Math.Min(minTemperature, Math.Min(winterTemperature, summerTemperature));
                maxTemperature    = Math.Max(maxTemperature, Math.Max(winterTemperature, summerTemperature));
                totalTemperature += (minTemperature + maxTemperature) / 2;

                var precipValue   = precipitationSpan[precipitationX].GetValueFromPixel_Pos();
                var precipitation = precipValue * planet.Atmosphere.MaxPrecipitation;
                totalPrecipiation += precipValue;

                ClimateMap[x][y] = Universe.Climate.Climate.GetClimateType(new FloatRange(
                                                                               Math.Min(winterTemperature, summerTemperature),
                                                                               Math.Max(winterTemperature, summerTemperature)));
                humidityMap[x][y] = Universe.Climate.Climate.GetHumidityType(precipitation);
                BiomeMap[x][y]    = Universe.Climate.Climate.GetBiomeType(ClimateMap[x][y], humidityMap[x][y], normalizedElevation);

                if (normalizedElevation > 0 ||
                    (summerTemperature >= Substances.All.Seawater.MeltingPoint &&
                     winterTemperature >= Substances.All.Seawater.MeltingPoint))
                {
                    continue;
                }

                if (summerTemperature < Substances.All.Seawater.MeltingPoint &&
                    winterTemperature < Substances.All.Seawater.MeltingPoint)
                {
                    SeaIceRangeMap[x][y] = FloatRange.ZeroToOne;
                    continue;
                }

                var freezeProportion = ((summerTemperature >= winterTemperature
                    ? winterTemperature.InverseLerp(summerTemperature, (float)(Substances.All.Seawater.MeltingPoint ?? 0))
                    : summerTemperature.InverseLerp(winterTemperature, (float)(Substances.All.Seawater.MeltingPoint ?? 0))) * 0.8f) - 0.1f;
                if (freezeProportion <= 0 ||
                    float.IsNaN(freezeProportion))
                {
                    continue;
                }

                var freezeStart   = 1 - (freezeProportion / 4);
                var iceMeltFinish = freezeProportion * 3 / 4;
                if (latitude < 0)
                {
                    freezeStart += 0.5f;
                    if (freezeStart > 1)
                    {
                        freezeStart--;
                    }

                    iceMeltFinish += 0.5f;
                    if (iceMeltFinish > 1)
                    {
                        iceMeltFinish--;
                    }
                }
                SeaIceRangeMap[x][y] = new FloatRange(freezeStart, iceMeltFinish);
            }
        }

        Climate = Universe.Climate.Climate.GetClimateType(new FloatRange(minTemperature, totalTemperature / (XLength * YLength), maxTemperature));
        var humidity = Universe.Climate.Climate.GetHumidityType(totalPrecipiation / (XLength * YLength) * planet.Atmosphere.MaxPrecipitation);

        Biome = Universe.Climate.Climate.GetBiomeType(Climate, humidity, totalElevation / (XLength * YLength) * planet.MaxElevation);
    }