| | | 1 | | //======================================================================= |
| | | 2 | | // GridTopologyMetrics.cs |
| | | 3 | | //======================================================================= |
| | | 4 | | // MIT License, Copyright (c) 2024–present David Oravsky (mrdav30) |
| | | 5 | | // See LICENSE file in the project root for full license information. |
| | | 6 | | //======================================================================= |
| | | 7 | | |
| | | 8 | | using FixedMathSharp; |
| | | 9 | | using MemoryPack; |
| | | 10 | | using SwiftCollections.Utility; |
| | | 11 | | using System; |
| | | 12 | | using System.Runtime.CompilerServices; |
| | | 13 | | using System.Text.Json.Serialization; |
| | | 14 | | |
| | | 15 | | namespace GridForge.Grids.Topology; |
| | | 16 | | |
| | | 17 | | /// <summary> |
| | | 18 | | /// Stores deterministic cell geometry for a grid topology. |
| | | 19 | | /// </summary> |
| | | 20 | | [Serializable] |
| | | 21 | | [MemoryPackable] |
| | | 22 | | public readonly partial struct GridTopologyMetrics : IEquatable<GridTopologyMetrics> |
| | | 23 | | { |
| | | 24 | | /// <summary> |
| | | 25 | | /// Horizontal center-to-corner radius for hex-prism cells. Rectangular-prism grids leave this as zero. |
| | | 26 | | /// </summary> |
| | | 27 | | [JsonInclude] |
| | | 28 | | [MemoryPackInclude] |
| | | 29 | | public readonly Fixed64 CellRadius; |
| | | 30 | | |
| | | 31 | | /// <summary> |
| | | 32 | | /// Rectangular-prism cell width along world X. |
| | | 33 | | /// </summary> |
| | | 34 | | [JsonInclude] |
| | | 35 | | [MemoryPackInclude] |
| | | 36 | | public readonly Fixed64 CellWidth; |
| | | 37 | | |
| | | 38 | | /// <summary> |
| | | 39 | | /// Vertical layer height along world Y for rectangular-prism and hex-prism grids. |
| | | 40 | | /// </summary> |
| | | 41 | | [JsonInclude] |
| | | 42 | | [MemoryPackInclude] |
| | | 43 | | public readonly Fixed64 LayerHeight; |
| | | 44 | | |
| | | 45 | | /// <summary> |
| | | 46 | | /// Rectangular-prism cell length along world Z. |
| | | 47 | | /// </summary> |
| | | 48 | | [JsonInclude] |
| | | 49 | | [MemoryPackInclude] |
| | | 50 | | public readonly Fixed64 CellLength; |
| | | 51 | | |
| | | 52 | | /// <summary> |
| | | 53 | | /// Hex-prism horizontal projection orientation. Rectangular-prism grids ignore this value. |
| | | 54 | | /// The orientation affects fixed-point world XZ projection only; it is not an engine rendering setting. |
| | | 55 | | /// </summary> |
| | | 56 | | [JsonInclude] |
| | | 57 | | [MemoryPackInclude] |
| | | 58 | | public readonly HexOrientation HexOrientation; |
| | | 59 | | |
| | | 60 | | /// <summary> |
| | | 61 | | /// Initializes deterministic topology metrics. |
| | | 62 | | /// </summary> |
| | | 63 | | [JsonConstructor] |
| | | 64 | | public GridTopologyMetrics( |
| | | 65 | | Fixed64 cellRadius, |
| | | 66 | | Fixed64 cellWidth, |
| | | 67 | | Fixed64 layerHeight, |
| | | 68 | | Fixed64 cellLength, |
| | | 69 | | HexOrientation hexOrientation = HexOrientation.PointyTop) |
| | | 70 | | { |
| | 900 | 71 | | CellRadius = cellRadius; |
| | 900 | 72 | | CellWidth = cellWidth; |
| | 900 | 73 | | LayerHeight = layerHeight; |
| | 900 | 74 | | CellLength = cellLength; |
| | 900 | 75 | | HexOrientation = hexOrientation; |
| | 900 | 76 | | } |
| | | 77 | | |
| | | 78 | | internal Fixed64 SmallestRectangularEdge |
| | | 79 | | { |
| | | 80 | | [MethodImpl(MethodImplOptions.AggressiveInlining)] |
| | | 81 | | get |
| | | 82 | | { |
| | 67 | 83 | | Fixed64 smallest = FixedMath.Min(CellWidth, LayerHeight); |
| | 67 | 84 | | return FixedMath.Min(smallest, CellLength); |
| | | 85 | | } |
| | | 86 | | } |
| | | 87 | | |
| | | 88 | | internal Fixed64 LargestRectangularEdge |
| | | 89 | | { |
| | | 90 | | [MethodImpl(MethodImplOptions.AggressiveInlining)] |
| | | 91 | | get |
| | | 92 | | { |
| | 387 | 93 | | Fixed64 largest = FixedMath.Max(CellWidth, LayerHeight); |
| | 387 | 94 | | return FixedMath.Max(largest, CellLength); |
| | | 95 | | } |
| | | 96 | | } |
| | | 97 | | |
| | | 98 | | internal Fixed64 LargestHexEdge |
| | | 99 | | { |
| | | 100 | | [MethodImpl(MethodImplOptions.AggressiveInlining)] |
| | | 101 | | get |
| | | 102 | | { |
| | 83 | 103 | | Fixed64 horizontalDiameter = CellRadius * new Fixed64(2); |
| | 83 | 104 | | return FixedMath.Max(horizontalDiameter, LayerHeight); |
| | | 105 | | } |
| | | 106 | | } |
| | | 107 | | |
| | | 108 | | /// <summary> |
| | | 109 | | /// Creates cubic rectangular-prism metrics. |
| | | 110 | | /// </summary> |
| | | 111 | | [MethodImpl(MethodImplOptions.AggressiveInlining)] |
| | | 112 | | public static GridTopologyMetrics Rectangular(Fixed64 cellSize) => |
| | 29 | 113 | | Rectangular(cellSize, cellSize, cellSize); |
| | | 114 | | |
| | | 115 | | /// <summary> |
| | | 116 | | /// Creates rectangular-prism metrics with independent X, Y, and Z cell edges. |
| | | 117 | | /// </summary> |
| | | 118 | | [MethodImpl(MethodImplOptions.AggressiveInlining)] |
| | | 119 | | public static GridTopologyMetrics Rectangular( |
| | | 120 | | Fixed64 cellWidth, |
| | | 121 | | Fixed64 layerHeight, |
| | 738 | 122 | | Fixed64 cellLength) => new(Fixed64.Zero, |
| | 738 | 123 | | ResolvePositive(cellWidth), |
| | 738 | 124 | | ResolvePositive(layerHeight), |
| | 738 | 125 | | ResolvePositive(cellLength), |
| | 738 | 126 | | HexOrientation.PointyTop); |
| | | 127 | | |
| | | 128 | | /// <summary> |
| | | 129 | | /// Creates hex-prism metrics with the supplied horizontal radius, vertical layer height, and orientation. |
| | | 130 | | /// </summary> |
| | | 131 | | [MethodImpl(MethodImplOptions.AggressiveInlining)] |
| | | 132 | | public static GridTopologyMetrics Hex( |
| | | 133 | | Fixed64 cellRadius, |
| | | 134 | | Fixed64 layerHeight, |
| | 157 | 135 | | HexOrientation hexOrientation = HexOrientation.PointyTop) => new( |
| | 157 | 136 | | cellRadius, |
| | 157 | 137 | | Fixed64.Zero, |
| | 157 | 138 | | layerHeight, |
| | 157 | 139 | | Fixed64.Zero, |
| | 157 | 140 | | hexOrientation); |
| | | 141 | | |
| | | 142 | | [MethodImpl(MethodImplOptions.AggressiveInlining)] |
| | | 143 | | internal static GridTopologyMetrics Normalize( |
| | | 144 | | GridTopologyKind topologyKind, |
| | 773 | 145 | | GridTopologyMetrics metrics) => topologyKind == GridTopologyKind.RectangularPrism |
| | 773 | 146 | | ? Rectangular(metrics.CellWidth, metrics.LayerHeight, metrics.CellLength) |
| | 773 | 147 | | : Hex(metrics.CellRadius, metrics.LayerHeight, metrics.HexOrientation); |
| | | 148 | | |
| | | 149 | | [MethodImpl(MethodImplOptions.AggressiveInlining)] |
| | | 150 | | internal static bool IsValid( |
| | | 151 | | GridTopologyKind topologyKind, |
| | 439 | 152 | | GridTopologyMetrics metrics) => topologyKind switch |
| | 439 | 153 | | { |
| | 373 | 154 | | GridTopologyKind.RectangularPrism => metrics.CellWidth > Fixed64.Zero |
| | 373 | 155 | | && metrics.LayerHeight > Fixed64.Zero |
| | 373 | 156 | | && metrics.CellLength > Fixed64.Zero, |
| | 65 | 157 | | GridTopologyKind.HexPrism => metrics.CellRadius > Fixed64.Zero |
| | 65 | 158 | | && metrics.LayerHeight > Fixed64.Zero, |
| | 1 | 159 | | _ => false |
| | 439 | 160 | | }; |
| | | 161 | | |
| | | 162 | | [MethodImpl(MethodImplOptions.AggressiveInlining)] |
| | | 163 | | private static Fixed64 ResolvePositive(Fixed64 value) => |
| | 2214 | 164 | | value > Fixed64.Zero ? value : Fixed64.One; |
| | | 165 | | |
| | | 166 | | /// <inheritdoc/> |
| | | 167 | | public override readonly int GetHashCode() |
| | | 168 | | { |
| | 840 | 169 | | int hash = SwiftHashTools.CombineHashCodes(CellRadius.GetHashCode(), CellWidth.GetHashCode()); |
| | 840 | 170 | | hash = SwiftHashTools.CombineHashCodes(hash, LayerHeight.GetHashCode()); |
| | 840 | 171 | | hash = SwiftHashTools.CombineHashCodes(hash, CellLength.GetHashCode()); |
| | 840 | 172 | | return SwiftHashTools.CombineHashCodes(hash, HexOrientation.GetHashCode()); |
| | | 173 | | } |
| | | 174 | | |
| | | 175 | | /// <inheritdoc/> |
| | | 176 | | public readonly bool Equals(GridTopologyMetrics other) |
| | | 177 | | { |
| | 941 | 178 | | return CellRadius == other.CellRadius |
| | 941 | 179 | | && CellWidth == other.CellWidth |
| | 941 | 180 | | && LayerHeight == other.LayerHeight |
| | 941 | 181 | | && CellLength == other.CellLength |
| | 941 | 182 | | && HexOrientation == other.HexOrientation; |
| | | 183 | | } |
| | | 184 | | |
| | | 185 | | /// <inheritdoc/> |
| | 3 | 186 | | public override readonly bool Equals(object? obj) => obj is GridTopologyMetrics other && Equals(other); |
| | | 187 | | |
| | | 188 | | /// <inheritdoc/> |
| | 888 | 189 | | public static bool operator ==(GridTopologyMetrics left, GridTopologyMetrics right) => left.Equals(right); |
| | | 190 | | |
| | | 191 | | /// <inheritdoc/> |
| | 2 | 192 | | public static bool operator !=(GridTopologyMetrics left, GridTopologyMetrics right) => !left.Equals(right); |
| | | 193 | | } |