using System; using UnityEngine; namespace FloodSWE.Preprocess { public sealed class TileStaticData { public int GridRes { get; } public float TileSizeMeters { get; } public float MinHeight { get; } public float MaxHeight { get; } public float[] Heights { get; } public float[] BuildingHeights { get; } public byte[] Porosity { get; } public TileStaticData( int gridRes, float tileSizeMeters, float[] heights, float minHeight, float maxHeight, float[] buildingHeights = null, byte[] porosity = null) { if (gridRes <= 0) { throw new ArgumentOutOfRangeException(nameof(gridRes)); } if (tileSizeMeters <= 0.0f) { throw new ArgumentOutOfRangeException(nameof(tileSizeMeters)); } if (heights == null) { throw new ArgumentNullException(nameof(heights)); } int expectedLength = gridRes * gridRes; if (heights.Length != expectedLength) { throw new ArgumentException("Heights length does not match grid resolution.", nameof(heights)); } if (buildingHeights != null && buildingHeights.Length != expectedLength) { throw new ArgumentException("Building heights length does not match grid resolution.", nameof(buildingHeights)); } if (porosity != null && porosity.Length != expectedLength) { throw new ArgumentException("Porosity length does not match grid resolution.", nameof(porosity)); } GridRes = gridRes; TileSizeMeters = tileSizeMeters; MinHeight = minHeight; MaxHeight = maxHeight; Heights = heights; BuildingHeights = buildingHeights; Porosity = porosity; } public static TileStaticData CreateFlat( int gridRes, float tileSizeMeters, float heightMeters, byte porosityValue = 255) { int length = gridRes * gridRes; float[] heights = new float[length]; byte[] porosity = new byte[length]; for (int i = 0; i < length; i++) { heights[i] = heightMeters; porosity[i] = porosityValue; } return new TileStaticData(gridRes, tileSizeMeters, heights, heightMeters, heightMeters, null, porosity); } public bool ValidateMinMax(float toleranceMeters, out float resampledMin, out float resampledMax) { ComputeMinMax(Heights, out resampledMin, out resampledMax); if (toleranceMeters < 0.0f) { toleranceMeters = 0.0f; } return Mathf.Abs(resampledMin - MinHeight) <= toleranceMeters && Mathf.Abs(resampledMax - MaxHeight) <= toleranceMeters; } public ushort[] EncodeHeightsToUInt16Mm() { int length = Heights.Length; ushort[] packed = new ushort[length]; for (int i = 0; i < length; i++) { float mm = (Heights[i] - MinHeight) * 1000.0f; if (mm < 0.0f) { mm = 0.0f; } else if (mm > ushort.MaxValue) { mm = ushort.MaxValue; } packed[i] = (ushort)Mathf.RoundToInt(mm); } return packed; } private static void ComputeMinMax(float[] data, out float min, out float max) { min = float.PositiveInfinity; max = float.NegativeInfinity; for (int i = 0; i < data.Length; i++) { float value = data[i]; if (value < min) { min = value; } if (value > max) { max = value; } } if (float.IsInfinity(min)) { min = 0.0f; max = 0.0f; } } } }