< Summary

Information
Class: GridForge.Configuration.GridConfiguration
Assembly: GridForge
File(s): /home/runner/work/GridForge/GridForge/src/GridForge/Configuration/GridConfiguration.cs
Line coverage
100%
Covered lines: 45
Uncovered lines: 0
Coverable lines: 45
Total lines: 196
Line coverage: 100%
Branch coverage
100%
Covered branches: 24
Total branches: 24
Branch coverage: 100%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
get_GridCenter()100%11100%
.ctor(...)100%88100%
ToBoundsKey()100%11100%
ToGridKey()100%11100%
TryNormalize(...)100%1616100%
GetHashCode()100%11100%

File(s)

/home/runner/work/GridForge/GridForge/src/GridForge/Configuration/GridConfiguration.cs

#LineLine coverage
 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
 8using System;
 9using System.Text.Json.Serialization;
 10using FixedMathSharp;
 11using GridForge.Grids.Storage;
 12using GridForge.Grids.Topology;
 13using GridForge.Spatial;
 14using MemoryPack;
 15using SwiftCollections.Utility;
 16
 17namespace 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]
 25public 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]
 51287    public readonly Vector3d GridCenter => Vector3d.Midpoint(BoundsMin, BoundsMax);
 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    {
 1900112        if (boundsMin > boundsMax)
 4113            GridForgeLogger.Channel.Warn($"GridMin was greater than GridMax, auto-correcting values.");
 114
 1900115        BoundsMin = new Vector3d(
 1900116            FixedMath.Min(boundsMin.X, boundsMax.X),
 1900117            FixedMath.Min(boundsMin.Y, boundsMax.Y),
 1900118            FixedMath.Min(boundsMin.Z, boundsMax.Z));
 1900119        BoundsMax = new Vector3d(
 1900120            FixedMath.Max(boundsMin.X, boundsMax.X),
 1900121            FixedMath.Max(boundsMin.Y, boundsMax.Y),
 1900122            FixedMath.Max(boundsMin.Z, boundsMax.Z));
 123
 1900124        ScanCellSize = scanCellSize > 0 ? scanCellSize : DefaultScanCellSize;
 1900125        TopologyKind = topologyKind;
 1900126        TopologyMetrics = topologyMetrics == default
 1900127            ? GridTopologyMetrics.Normalize(topologyKind, topologyMetrics)
 1900128            : topologyMetrics;
 1900129        StorageKind = storageKind;
 1900130    }
 131
 132    #endregion
 133
 134    /// <summary>
 135    /// Creates an exact identity key for this configuration's snapped bounds.
 136    /// </summary>
 5137    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() =>
 1727143        new(BoundsMin, BoundsMax, TopologyKind, TopologyMetrics);
 144
 145    /// <summary>
 146    /// Validates and normalizes this configuration without registering a live grid.
 147    /// </summary>
 148    /// <param name="descriptor">
 149    /// The normalized configuration, exact binding key, dimensions, and local-index validator.
 150    /// </param>
 151    /// <returns>
 152    /// True when the topology and dimensions are supported; otherwise false and
 153    /// <paramref name="descriptor"/> is default.
 154    /// </returns>
 155    public readonly bool TryNormalize(out NormalizedGridConfiguration descriptor)
 156    {
 977157        descriptor = default;
 977158        if (!GridTopologyFactory.TryCreate(this, out IGridTopology? topology))
 12159            return false;
 160
 965161        (Vector3d boundsMin, Vector3d boundsMax) =
 965162            topology!.NormalizeBounds(BoundsMin, BoundsMax);
 965163        GridConfiguration normalizedConfiguration = new(
 965164            boundsMin,
 965165            boundsMax,
 965166            ScanCellSize,
 965167            TopologyKind,
 965168            TopologyMetrics,
 965169            StorageKind);
 965170        GridDimensions dimensions = topology.CalculateDimensions(boundsMin, boundsMax);
 171
 965172        if (dimensions.Width <= 0 || dimensions.Height <= 0 || dimensions.Length <= 0)
 173        {
 6174            GridForgeLogger.Channel.Warn($"Grid dimensions must define a positive voxel address space.");
 6175            return false;
 176        }
 177
 959178        long layerSize = (long)dimensions.Width * dimensions.Height;
 959179        if (layerSize > int.MaxValue || layerSize * dimensions.Length > int.MaxValue)
 180        {
 4181            GridForgeLogger.Channel.Warn($"Grid dimensions exceed the supported int voxel address space.");
 4182            return false;
 183        }
 184
 955185        descriptor = new NormalizedGridConfiguration(normalizedConfiguration, topology, dimensions);
 955186        return true;
 187    }
 188
 189    /// <inheritdoc/>
 190    public override readonly int GetHashCode()
 191    {
 6192        int hash = SwiftHashTools.CombineHashCodes(BoundsMin.GetHashCode(), BoundsMax.GetHashCode());
 6193        hash = SwiftHashTools.CombineHashCodes(hash, TopologyKind.GetHashCode());
 6194        return SwiftHashTools.CombineHashCodes(hash, TopologyMetrics.GetHashCode());
 195    }
 196}