| | | 1 | | //======================================================================= |
| | | 2 | | // GridConfiguration.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 GridForge.Grids.Storage; |
| | | 10 | | using GridForge.Grids.Topology; |
| | | 11 | | using GridForge.Spatial; |
| | | 12 | | using MemoryPack; |
| | | 13 | | using SwiftCollections.Utility; |
| | | 14 | | using System; |
| | | 15 | | using System.Text.Json.Serialization; |
| | | 16 | | |
| | | 17 | | namespace GridForge.Configuration; |
| | | 18 | | |
| | | 19 | | /// <summary> |
| | | 20 | | /// Defines the configuration parameters for a grid, including boundaries, topology, storage, and scan cell size. |
| | | 21 | | /// Used to describe grid properties before a world normalizes and registers the grid. |
| | | 22 | | /// </summary> |
| | | 23 | | [Serializable] |
| | | 24 | | [MemoryPackable] |
| | | 25 | | public readonly partial struct GridConfiguration |
| | | 26 | | { |
| | | 27 | | /// <summary> |
| | | 28 | | /// The default size of each scan cell. |
| | | 29 | | /// </summary> |
| | | 30 | | public const int DefaultScanCellSize = 8; |
| | | 31 | | |
| | | 32 | | #region Properties |
| | | 33 | | |
| | | 34 | | /// <summary> |
| | | 35 | | /// The minimum boundary of the grid in world coordinates. |
| | | 36 | | /// </summary> |
| | | 37 | | [JsonInclude] |
| | | 38 | | [MemoryPackInclude] |
| | | 39 | | public readonly Vector3d BoundsMin; |
| | | 40 | | |
| | | 41 | | /// <summary> |
| | | 42 | | /// The maximum boundary of the grid in world coordinates. |
| | | 43 | | /// </summary> |
| | | 44 | | [JsonInclude] |
| | | 45 | | [MemoryPackInclude] |
| | | 46 | | public readonly Vector3d BoundsMax; |
| | | 47 | | |
| | | 48 | | /// <summary> |
| | | 49 | | /// The size of each scan cell, determining the granularity of spatial partitioning. |
| | | 50 | | /// Customizable based on grid density and expected entity distribution. |
| | | 51 | | /// </summary> |
| | | 52 | | [JsonInclude] |
| | | 53 | | [MemoryPackInclude] |
| | | 54 | | public readonly int ScanCellSize; |
| | | 55 | | |
| | | 56 | | /// <summary> |
| | | 57 | | /// The cell topology used by this grid. Rectangular-prism grids interpret |
| | | 58 | | /// <see cref="VoxelIndex"/> as local X/Y/Z coordinates; hex-prism grids |
| | | 59 | | /// interpret it as axial Q, vertical layer, and axial R. |
| | | 60 | | /// </summary> |
| | | 61 | | [JsonInclude] |
| | | 62 | | [MemoryPackInclude] |
| | | 63 | | public readonly GridTopologyKind TopologyKind; |
| | | 64 | | |
| | | 65 | | /// <summary> |
| | | 66 | | /// The deterministic cell geometry used by this grid's topology. |
| | | 67 | | /// Rectangular-prism metrics define cell width, layer height, and length. |
| | | 68 | | /// Hex-prism metrics define horizontal radius, layer height, and orientation. |
| | | 69 | | /// </summary> |
| | | 70 | | [JsonInclude] |
| | | 71 | | [MemoryPackInclude] |
| | | 72 | | public readonly GridTopologyMetrics TopologyMetrics; |
| | | 73 | | |
| | | 74 | | /// <summary> |
| | | 75 | | /// The physical voxel storage used by this grid. Dense storage materializes every in-bounds voxel; |
| | | 76 | | /// sparse storage materializes only explicitly configured voxels. |
| | | 77 | | /// </summary> |
| | | 78 | | [JsonInclude] |
| | | 79 | | [MemoryPackInclude] |
| | | 80 | | public readonly GridStorageKind StorageKind; |
| | | 81 | | |
| | | 82 | | /// <summary> |
| | | 83 | | /// The center point of the grid's bounding volume. |
| | | 84 | | /// </summary> |
| | | 85 | | [JsonIgnore] |
| | | 86 | | [MemoryPackIgnore] |
| | 163 | 87 | | public readonly Vector3d GridCenter => (BoundsMin + BoundsMax) * Fixed64.Half; |
| | | 88 | | |
| | | 89 | | #endregion |
| | | 90 | | |
| | | 91 | | #region Constructors |
| | | 92 | | |
| | | 93 | | /// <summary> |
| | | 94 | | /// Initializes a new instance of <see cref="GridConfiguration"/> with specified bounds and scan cell size. |
| | | 95 | | /// Ensures that <see cref="BoundsMin"/> is always less than or equal to <see cref="BoundsMax"/>. |
| | | 96 | | /// </summary> |
| | | 97 | | /// <param name="boundsMin">The minimum boundary of the grid.</param> |
| | | 98 | | /// <param name="boundsMax">The maximum boundary of the grid.</param> |
| | | 99 | | /// <param name="scanCellSize">The size of scan cells within the grid. Default is 8.</param> |
| | | 100 | | /// <param name="topologyKind">The topology kind used by the grid. Defaults to rectangular-prism.</param> |
| | | 101 | | /// <param name="topologyMetrics">Deterministic topology metrics. Defaults to 1x1x1 rectangular-prism cells.</param> |
| | | 102 | | /// <param name="storageKind">The physical voxel storage kind. Defaults to dense storage.</param> |
| | | 103 | | [JsonConstructor] |
| | | 104 | | public GridConfiguration( |
| | | 105 | | Vector3d boundsMin, |
| | | 106 | | Vector3d boundsMax, |
| | | 107 | | int scanCellSize = DefaultScanCellSize, |
| | | 108 | | GridTopologyKind topologyKind = GridTopologyKind.RectangularPrism, |
| | | 109 | | GridTopologyMetrics topologyMetrics = default, |
| | | 110 | | GridStorageKind storageKind = GridStorageKind.Dense) |
| | | 111 | | { |
| | 853 | 112 | | if (boundsMin > boundsMax) |
| | 4 | 113 | | GridForgeLogger.Channel.Warn($"GridMin was greater than GridMax, auto-correcting values."); |
| | | 114 | | |
| | 853 | 115 | | BoundsMin = new Vector3d( |
| | 853 | 116 | | FixedMath.Min(boundsMin.X, boundsMax.X), |
| | 853 | 117 | | FixedMath.Min(boundsMin.Y, boundsMax.Y), |
| | 853 | 118 | | FixedMath.Min(boundsMin.Z, boundsMax.Z)); |
| | 853 | 119 | | BoundsMax = new Vector3d( |
| | 853 | 120 | | FixedMath.Max(boundsMin.X, boundsMax.X), |
| | 853 | 121 | | FixedMath.Max(boundsMin.Y, boundsMax.Y), |
| | 853 | 122 | | FixedMath.Max(boundsMin.Z, boundsMax.Z)); |
| | | 123 | | |
| | 853 | 124 | | ScanCellSize = scanCellSize > 0 ? scanCellSize : DefaultScanCellSize; |
| | 853 | 125 | | TopologyKind = topologyKind; |
| | 853 | 126 | | TopologyMetrics = topologyMetrics == default |
| | 853 | 127 | | ? GridTopologyMetrics.Normalize(topologyKind, topologyMetrics) |
| | 853 | 128 | | : topologyMetrics; |
| | 853 | 129 | | StorageKind = storageKind; |
| | 853 | 130 | | } |
| | | 131 | | |
| | | 132 | | #endregion |
| | | 133 | | |
| | | 134 | | /// <summary> |
| | | 135 | | /// Creates an exact identity key for this configuration's snapped bounds. |
| | | 136 | | /// </summary> |
| | 5 | 137 | | public readonly BoundsKey ToBoundsKey() => new(BoundsMin, BoundsMax); |
| | | 138 | | |
| | | 139 | | /// <summary> |
| | | 140 | | /// Creates an exact identity key for this configuration's snapped bounds and topology. |
| | | 141 | | /// </summary> |
| | | 142 | | public readonly GridConfigurationKey ToGridKey() => |
| | 437 | 143 | | new(BoundsMin, BoundsMax, TopologyKind, TopologyMetrics); |
| | | 144 | | |
| | | 145 | | /// <inheritdoc/> |
| | | 146 | | public override readonly int GetHashCode() |
| | | 147 | | { |
| | 6 | 148 | | int hash = SwiftHashTools.CombineHashCodes(BoundsMin.GetHashCode(), BoundsMax.GetHashCode()); |
| | 6 | 149 | | hash = SwiftHashTools.CombineHashCodes(hash, TopologyKind.GetHashCode()); |
| | 6 | 150 | | return SwiftHashTools.CombineHashCodes(hash, TopologyMetrics.GetHashCode()); |
| | | 151 | | } |
| | | 152 | | } |