< Summary

Information
Class: GridForge.Grids.VoxelGrid
Assembly: GridForge
File(s): /home/runner/work/GridForge/GridForge/src/GridForge/Grids/VoxelGrid.cs
Line coverage
100%
Covered lines: 285
Uncovered lines: 0
Coverable lines: 285
Total lines: 1021
Line coverage: 100%
Branch coverage
98%
Covered branches: 193
Total branches: 196
Branch coverage: 98.4%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
get_BoundsMin()100%11100%
get_BoundsMax()100%11100%
get_BoundsCenter()100%11100%
get_ConfiguredVoxelCount()100%22100%
get_StorageKind()100%22100%
get_Voxels()100%11100%
get_NeighborSlotCount()100%22100%
get_TopologyKind()100%22100%
get_IsConjoined()100%22100%
get_ScanCellSize()100%11100%
get_ScanCells()100%22100%
get_IsOccupied()100%22100%
.ctor()100%11100%
get_Topology()100%11100%
get_ScanWidth()100%11100%
get_ScanHeight()100%11100%
get_ScanLength()100%11100%
Initialize(...)100%22100%
Reset()100%22100%
ReleaseActiveScanCells()100%22100%
ReleaseNeighbors()100%44100%
ClearDimensions()100%11100%
IncrementVersion()100%22100%
ConfigureScanDimensions()100%11100%
GetRectangularNeighborDirection(...)100%22100%
GetHexNeighborDirection(...)100%22100%
TryGetNeighborSlot(...)100%88100%
TryGetNeighborSlot(...)100%88100%
GetNeighborOffset(...)100%11100%
TryGetNeighborSlot(...)100%44100%
TryGetNeighborSlot(...)100%44100%
TryAddGridNeighbor(...)100%88100%
TryRemoveGridNeighbor(...)100%66100%
TryGetGridNeighborSet(...)100%44100%
ReleaseNeighborSetIfEmpty(...)100%44100%
IsOnBoundary(...)100%1010100%
IsInBounds(...)100%22100%
IsGridOverlapValid(...)100%66100%
AxisOverlaps(...)100%22100%
GetAllGridNeighbors()100%88100%
IsValidVoxelIndex(...)100%88100%
IsVoxelIndexInBounds(...)100%44100%
IsFacingBoundary(...)100%22100%
IsFacingBoundary(...)100%22100%
TryGetVoxelIndex(...)100%88100%
TryGetVoxelIndex(...)100%11100%
TryGetVoxelIndex(...)100%11100%
IsVoxelAllocated(...)100%22100%
ContainsVoxel(...)100%11100%
TryAddVoxel(...)100%44100%
TryRemoveVoxel(...)83.33%66100%
CanMutateSparseVoxel(...)100%44100%
CanRemoveSparseVoxel(...)100%88100%
TryGetVoxel(...)100%22100%
EnumerateVoxels()100%44100%
VisitVoxels(...)50%22100%
AddVoxelsInIndexRange(...)100%22100%
TryGetVoxel(...)100%11100%
TryGetVoxel(...)100%22100%
TryGetClosestVoxel(...)100%11100%
TryGetClosestVoxel(...)100%66100%
TryGetVoxel(...)100%11100%
TryGetVoxel(...)100%11100%
TryGetClosestVoxel(...)100%11100%
TryGetClosestVoxel(...)100%11100%
GetScanCellKey(...)100%22100%
GetScanCellKey(...)100%44100%
GetScanCellKey(...)83.33%66100%
TryGetScanCell(...)100%22100%
TryGetScanCell(...)100%11100%
TryGetScanCell(...)100%22100%
AddScanCellsInRange(...)100%22100%
GetActiveScanCells()100%88100%
CeilToGrid(...)100%11100%
FloorToGrid(...)100%11100%
SnapToScanCell(...)100%11100%
NormalizeBounds(...)100%11100%
GetWorldPosition(...)100%11100%
GetWorldOffset(...)100%11100%
GetHashCode()100%11100%

File(s)

/home/runner/work/GridForge/GridForge/src/GridForge/Grids/VoxelGrid.cs

#LineLine coverage
 1//=======================================================================
 2// VoxelGrid.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 FixedMathSharp;
 9using GridForge.Configuration;
 10using GridForge.Grids.Storage;
 11using GridForge.Grids.Topology;
 12using GridForge.Spatial;
 13using SwiftCollections;
 14using SwiftCollections.Dimensions;
 15using SwiftCollections.Pool;
 16using SwiftCollections.Utility;
 17using System;
 18using System.Collections.Generic;
 19using System.Runtime.CompilerServices;
 20
 21namespace GridForge.Grids;
 22
 23/// <summary>
 24/// Represents a 3D grid structure for spatial organization, managing voxels and scan cells.
 25/// Handles initialization, neighbor relationships, and occupancy tracking.
 26/// </summary>
 27public class VoxelGrid
 28{
 29    #region Fields & Properties
 30
 31    /// <summary>
 32    /// Unique token identifying the grid instance.
 33    /// </summary>
 34    public int SpawnToken { get; private set; }
 35
 36    /// <summary>
 37    /// World-local index of the grid within its owning world.
 38    /// </summary>
 39    public ushort GridIndex { get; private set; }
 40
 41    /// <summary>
 42    /// The world that owns this grid instance.
 43    /// </summary>
 44    public GridWorld? World { get; private set; }
 45
 46    /// <summary>
 47    /// Synchronizes obstacle mutations for this grid.
 48    /// </summary>
 49    internal object ObstacleSyncRoot { get; } = new object();
 50
 51    /// <summary>
 52    /// Synchronizes occupant mutations for this grid.
 53    /// </summary>
 54    internal object OccupantSyncRoot { get; } = new object();
 55
 56    /// <inheritdoc cref="GridConfiguration"/>
 57    public GridConfiguration Configuration { get; private set; }
 58
 59    /// <summary>
 60    /// Minimum bounds of the grid in world coordinates.
 61    /// </summary>
 10581462    public Vector3d BoundsMin => Configuration.BoundsMin;
 63
 64    /// <summary>
 65    /// Maximum bounds of the grid in world coordinates.
 66    /// </summary>
 795567    public Vector3d BoundsMax => Configuration.BoundsMax;
 68
 69    /// <summary>
 70    /// Center position of the grid in world space.
 71    /// </summary>
 16272    public Vector3d BoundsCenter => Configuration.GridCenter;
 73
 74    /// <summary>
 75    /// Grid width in number of voxels.
 76    /// </summary>
 77    public int Width { get; private set; }
 78
 79    /// <summary>
 80    /// Grid height in number of voxels.
 81    /// </summary>
 82    public int Height { get; private set; }
 83
 84    /// <summary>
 85    /// Grid length in number of voxels.
 86    /// </summary>
 87    public int Length { get; private set; }
 88
 89    /// <summary>
 90    /// Total addressable voxel count within the grid bounds.
 91    /// </summary>
 92    public int Size { get; private set; }
 93
 94    /// <summary>
 95    /// The number of physical voxels configured in the grid storage.
 96    /// Dense grids report <see cref="Size"/>; sparse grids report configured voxels only.
 97    /// </summary>
 98    public int ConfiguredVoxelCount
 99    {
 100        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 73101        get => _storage?.ConfiguredVoxelCount ?? 0;
 102    }
 103
 104    /// <summary>
 105    /// The physical voxel storage strategy used by this grid.
 106    /// </summary>
 107    public GridStorageKind StorageKind
 108    {
 109        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 8864110        get => _storage?.Kind ?? GridStorageKind.Dense;
 111    }
 112
 113    /// <summary>
 114    /// The dense 3D collection of voxels managed by this grid when dense storage is active.
 115    /// </summary>
 116    internal SwiftArray3D<Voxel>? Voxels
 117    {
 118        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 3119        get => _denseStorage.Voxels;
 120    }
 121
 122    /// <summary>
 123    /// Stores topology-local neighbor slots for neighboring grids based on their relative positions.
 124    /// </summary>
 125    /// <remarks>
 126    /// Unlike voxel adjacency (which is always 1:1), grids can share multiple neighbors in the same direction.
 127    /// </remarks>
 128    public SwiftSparseMap<SwiftHashSet<int>>? Neighbors { get; private set; }
 129
 130    /// <summary>
 131    /// Count of currently linked neighboring grids.
 132    /// </summary>
 133    public byte NeighborCount { get; private set; }
 134
 135    /// <summary>
 136    /// Count of topology-local neighbor slots supported by this grid.
 137    /// </summary>
 424138    internal int NeighborSlotCount => _topology?.NeighborSlotCount ?? 0;
 139
 140    /// <summary>
 141    /// The active topology kind for this grid.
 142    /// </summary>
 91143    internal GridTopologyKind? TopologyKind => _topology?.Kind;
 144
 145    /// <summary>
 146    /// Determines whether this grid has any linked neighbors.
 147    /// </summary>
 57148    public bool IsConjoined => Neighbors != null && NeighborCount > 0;
 149
 150    /// <summary>
 151    /// Size of a scan cell used for spatial partitioning.
 152    /// </summary>
 290487153    public int ScanCellSize => Configuration.ScanCellSize;
 154
 155    /// <summary>
 156    /// Collection of scan cells indexed by their grid-local scan cell key.
 157    /// </summary>
 158    internal SwiftSparseMap<ScanCell>? ScanCells
 159    {
 160        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 3161        get => _storage?.ScanCells;
 162    }
 163
 164    /// <summary>
 165    /// Stores currently active (occupied) scan cells within the grid.
 166    /// </summary>
 167    public SwiftHashSet<int>? ActiveScanCells { get; internal set; }
 168
 169    /// <summary>
 170    /// Indicates whether the grid is currently active.
 171    /// </summary>
 172    public bool IsActive { get; private set; }
 173
 174    /// <summary>
 175    /// Determines whether the grid is occupied (active and containing occupants).
 176    /// </summary>
 27177    public bool IsOccupied => ActiveScanCells?.Count > 0;
 178
 179    /// <summary>
 180    /// Tracks the number of obstacles currently registered in the grid.
 181    /// </summary>
 182    public int ObstacleCount { get; internal set; }
 183
 184    /// <summary>
 185    /// Tracks the version of the grid, incremented when a <see cref="Voxel"/> is modified.
 186    /// </summary>
 187    public uint Version { get; private set; }
 188
 189    private int _scanWidth;
 190    private int _scanHeight;
 191    private int _scanLength;
 192    private int _scanLayerSize;
 193
 194    private IGridTopology? _topology;
 195    private IVoxelGridStorage? _storage;
 43196    private readonly DenseVoxelGridStorage _denseStorage = new();
 43197    private readonly SparseVoxelGridStorage _sparseStorage = new();
 198
 102100199    internal IGridTopology Topology => _topology!;
 200
 201    internal int ScanWidth
 202    {
 203        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 1034204        get => _scanWidth;
 205    }
 206
 207    internal int ScanHeight
 208    {
 209        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 1282210        get => _scanHeight;
 211    }
 212
 213    internal int ScanLength
 214    {
 215        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 2423216        get => _scanLength;
 217    }
 218
 219    #endregion
 220
 221    #region Initialization & Reset
 222
 223    /// <summary>
 224    /// Initializes the grid with an explicit owning world and configured sparse voxel set.
 225    /// </summary>
 226    /// <param name="world">The world that will own this grid.</param>
 227    /// <param name="gridIndex">The unique index of this grid in the world.</param>
 228    /// <param name="configuration">The normalized configuration settings for the grid.</param>
 229    /// <param name="topology">The validated topology instance for this grid.</param>
 230    /// <param name="configuredVoxels">The validated sparse voxel indices to materialize.</param>
 231    internal void Initialize(
 232        GridWorld world,
 233        ushort gridIndex,
 234        GridConfiguration configuration,
 235        IGridTopology topology,
 236        VoxelIndex[] configuredVoxels)
 237    {
 407238        Version = 1;
 239
 407240        World = world;
 407241        GridIndex = gridIndex;
 242
 407243        Configuration = configuration;
 407244        _topology = topology;
 245
 407246        SpawnToken = GetHashCode();
 247
 248        // +1 to account for inclusive bounds and to ensure that even the smallest grids (1x1x1) remain valid.
 407249        GridDimensions dimensions = topology.CalculateDimensions(BoundsMin, BoundsMax);
 407250        Width = dimensions.Width;
 407251        Height = dimensions.Height;
 407252        Length = dimensions.Length;
 407253        Size = Width * Height * Length;
 254
 407255        ConfigureScanDimensions();
 407256        if (configuration.StorageKind == GridStorageKind.Sparse)
 257        {
 63258            _sparseStorage.Initialize(this, configuredVoxels);
 63259            _storage = _sparseStorage;
 260        }
 261        else
 262        {
 344263            _denseStorage.Initialize(this);
 344264            _storage = _denseStorage;
 265        }
 266
 407267        IsActive = true;
 407268    }
 269
 270    /// <summary>
 271    /// Resets the grid, clearing all voxels and scan cells.
 272    /// </summary>
 273    internal void Reset()
 274    {
 409275        if (!IsActive)
 2276            return;
 277
 407278        _storage!.Reset(this);
 407279        _storage = null;
 280
 281        // Just in case since voxels should have already cleared any registered obstacles.
 407282        ObstacleCount = 0;
 283
 407284        ReleaseActiveScanCells();
 407285        ReleaseNeighbors();
 286
 407287        Configuration = default;
 407288        World = null;
 407289        _topology = null;
 290
 407291        SpawnToken = 0;
 407292        Version = 0;
 293
 407294        GridIndex = ushort.MaxValue;
 295
 407296        ClearDimensions();
 297
 407298        IsActive = false;
 407299    }
 300
 301    private void ReleaseActiveScanCells()
 302    {
 407303        if (ActiveScanCells == null)
 371304            return;
 305
 36306        SwiftHashSetPool<int>.Shared.Release(ActiveScanCells);
 36307        ActiveScanCells = null;
 36308    }
 309
 310    private void ReleaseNeighbors()
 311    {
 407312        if (Neighbors == null)
 371313            return;
 314
 160315        foreach (SwiftHashSet<int> neighbors in Neighbors.Values)
 44316            SwiftHashSetPool<int>.Shared.Release(neighbors);
 317
 36318        Neighbors = null;
 36319        NeighborCount = 0;
 36320    }
 321
 322    private void ClearDimensions()
 323    {
 407324        Width = 0;
 407325        Height = 0;
 407326        Length = 0;
 407327        Size = 0;
 407328        _scanWidth = 0;
 407329        _scanHeight = 0;
 407330        _scanLength = 0;
 407331        _scanLayerSize = 0;
 407332    }
 333
 334    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 335    internal uint IncrementVersion()
 336    {
 1487337        Version = Version == uint.MaxValue ? 1u : Version + 1u;
 1487338        return Version;
 339    }
 340
 341    #endregion
 342
 343    #region Grid Construction
 344
 345    private void ConfigureScanDimensions()
 346    {
 407347        _scanWidth = ((Width - 1) / ScanCellSize) + 1;
 407348        _scanHeight = ((Height - 1) / ScanCellSize) + 1;
 407349        _scanLength = ((Length - 1) / ScanCellSize) + 1;
 407350        _scanLayerSize = _scanWidth * _scanHeight;
 407351    }
 352
 353    #endregion
 354
 355    #region Boundary Management
 356
 357    /// <summary>
 358    /// Determines the rectangular-prism direction from grid <paramref name="a"/> to neighboring grid <paramref name="b"
 359    /// </summary>
 360    /// <param name="a">The source rectangular-prism grid.</param>
 361    /// <param name="b">The neighboring rectangular-prism grid.</param>
 362    /// <returns>The rectangular direction from <paramref name="a"/> to <paramref name="b"/>, or <see cref="RectangularD
 363    public static RectangularDirection GetRectangularNeighborDirection(VoxelGrid a, VoxelGrid b)
 364    {
 8365        return TryGetNeighborSlot(a, b, GridTopologyKind.RectangularPrism, out int slot)
 8366            ? (RectangularDirection)slot
 8367            : RectangularDirection.None;
 368    }
 369
 370    /// <summary>
 371    /// Determines the hex-prism direction from grid <paramref name="a"/> to neighboring grid <paramref name="b"/>.
 372    /// </summary>
 373    /// <param name="a">The source hex-prism grid.</param>
 374    /// <param name="b">The neighboring hex-prism grid.</param>
 375    /// <returns>The hex direction from <paramref name="a"/> to <paramref name="b"/>, or <see cref="HexDirection.None"/>
 376    public static HexDirection GetHexNeighborDirection(VoxelGrid a, VoxelGrid b)
 377    {
 7378        return TryGetNeighborSlot(a, b, GridTopologyKind.HexPrism, out int slot)
 7379            ? (HexDirection)slot
 7380            : HexDirection.None;
 381    }
 382
 383    private static bool TryGetNeighborSlot(VoxelGrid a, VoxelGrid b, GridTopologyKind expectedKind, out int slot)
 384    {
 15385        if (a._topology?.Kind != expectedKind || b._topology?.Kind != expectedKind)
 386        {
 10387            slot = -1;
 10388            return false;
 389        }
 390
 5391        return TryGetNeighborSlot(a, b, out slot);
 392    }
 393
 394    private static bool TryGetNeighborSlot(VoxelGrid a, VoxelGrid b, out int slot)
 395    {
 105396        slot = -1;
 397
 105398        if (a._topology == null
 105399            || b._topology == null
 105400            || a._topology.Kind != b._topology.Kind)
 401        {
 24402            return false;
 403        }
 404
 81405        return a._topology.TryGetNeighborSlotFromWorldDelta(b.BoundsCenter - a.BoundsCenter, out slot)
 81406            && (uint)slot < (uint)a._topology.NeighborSlotCount;
 407    }
 408
 409    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 481410    internal VoxelIndex GetNeighborOffset(int slot) => Topology.GetNeighborOffset(slot);
 411
 412    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 413    internal bool TryGetNeighborSlot(RectangularDirection direction, out int slot)
 414    {
 131415        slot = (int)direction;
 131416        return _topology?.Kind == GridTopologyKind.RectangularPrism
 131417            && (uint)slot < (uint)_topology.NeighborSlotCount;
 418    }
 419
 420    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 421    internal bool TryGetNeighborSlot(HexDirection direction, out int slot)
 422    {
 14423        slot = (int)direction;
 14424        return _topology?.Kind == GridTopologyKind.HexPrism
 14425            && (uint)slot < (uint)_topology.NeighborSlotCount;
 426    }
 427
 428    /// <summary>
 429    /// Adds a neighboring grid and updates relationships.
 430    /// </summary>
 431    /// <param name="neighborGrid">The neighboring grid to add.</param>
 432    internal bool TryAddGridNeighbor(VoxelGrid neighborGrid)
 433    {
 86434        if (!TryGetNeighborSlot(this, neighborGrid, out int neighborSlot))
 25435            return false;
 436
 437        // Ensure the neighbor array is allocated and store the new neighbor
 61438        Neighbors ??= new SwiftSparseMap<SwiftHashSet<int>>();
 61439        if (!Neighbors.TryGetValue(neighborSlot, out SwiftHashSet<int> neighborSet))
 440        {
 53441            neighborSet = SwiftHashSetPool<int>.Shared.Rent();
 53442            Neighbors.Add(neighborSlot, neighborSet);
 443        }
 444
 61445        if (!neighborSet.Add(neighborGrid.GridIndex))
 7446            return false;
 447
 54448        NeighborCount++;
 54449        IncrementVersion();
 450
 54451        return true;
 452    }
 453
 454    /// <summary>
 455    /// Removes a neighboring grid relationship.
 456    /// </summary>
 457    /// <param name="neighborGrid">The neighboring grid to remove.</param>
 458    internal bool TryRemoveGridNeighbor(VoxelGrid neighborGrid)
 459    {
 13460        if (!TryGetGridNeighborSet(neighborGrid, out int neighborSlot, out SwiftHashSet<int>? neighborSet))
 2461            return false;
 462
 11463        if (!neighborSet!.Remove(neighborGrid.GridIndex))
 1464            return false;
 465
 10466        ReleaseNeighborSetIfEmpty(neighborSlot, neighborSet);
 467
 10468        if (--NeighborCount == 0)
 6469            Neighbors = null;
 470
 10471        IncrementVersion();
 472
 10473        return true;
 474    }
 475
 476    private bool TryGetGridNeighborSet(
 477        VoxelGrid neighborGrid,
 478        out int neighborSlot,
 479        out SwiftHashSet<int>? neighborSet)
 480    {
 13481        neighborSet = null;
 13482        neighborSlot = -1;
 483
 13484        if (!IsConjoined)
 1485            return false;
 486
 12487        return TryGetNeighborSlot(this, neighborGrid, out neighborSlot)
 12488            && Neighbors!.TryGetValue(neighborSlot, out neighborSet);
 489    }
 490
 491    private void ReleaseNeighborSetIfEmpty(int neighborIndex, SwiftHashSet<int> neighborSet)
 492    {
 10493        if (neighborSet.Count > 0)
 1494            return;
 495
 9496        GridForgeLogger.Channel.Info($"Releasing unused neighbor collection.");
 9497        SwiftHashSetPool<int>.Shared.Release(neighborSet);
 9498        Neighbors!.Remove(neighborIndex);
 9499    }
 500
 501    #endregion
 502
 503    #region Grid Queries
 504
 505    /// <summary>
 506    /// Determines if a voxel coordinate is at the boundary of the grid.
 507    /// Used to determine if a voxel should update when a neighboring grid is added/removed.
 508    /// </summary>
 509    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 510    public bool IsOnBoundary(VoxelIndex coord) =>
 95913511         coord.x == 0 || coord.x == Width - 1
 95913512      || coord.y == 0 || coord.y == Height - 1
 95913513      || coord.z == 0 || coord.z == Length - 1;
 514
 515    /// <summary>
 516    /// Checks whether a given position falls within the grid bounds.
 517    /// </summary>
 518    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 519    public bool IsInBounds(Vector3d target) =>
 168520        IsActive && Topology.IsInBounds(BoundsMin, BoundsMax, Width, Height, Length, target);
 521
 522    /// <summary>
 523    /// Checks if two grids are overlapping within a given tolerance threshold.
 524    /// This is used to determine if grids should be linked as neighbors.
 525    /// </summary>
 526    /// <param name="a">The first grid.</param>
 527    /// <param name="b">The second grid.</param>
 528    /// <param name="tolerance">Optional tolerance to account for minor floating-point errors.</param>
 529    /// <returns>True if the grids overlap within the tolerance, otherwise false.</returns>
 530    public static bool IsGridOverlapValid(VoxelGrid a, VoxelGrid b, Fixed64? tolerance = null)
 531    {
 91532        Fixed64 toleranceValue = tolerance ?? a.Topology.OverlapTolerance;
 533
 91534        return AxisOverlaps(a.BoundsMin.X, a.BoundsMax.X, b.BoundsMin.X, b.BoundsMax.X, toleranceValue)
 91535            && AxisOverlaps(a.BoundsMin.Y, a.BoundsMax.Y, b.BoundsMin.Y, b.BoundsMax.Y, toleranceValue)
 91536            && AxisOverlaps(a.BoundsMin.Z, a.BoundsMax.Z, b.BoundsMin.Z, b.BoundsMax.Z, toleranceValue);
 537    }
 538
 539    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 540    private static bool AxisOverlaps(
 541        Fixed64 firstMin,
 542        Fixed64 firstMax,
 543        Fixed64 secondMin,
 544        Fixed64 secondMax,
 202545        Fixed64 tolerance) => firstMax >= secondMin - tolerance && firstMin <= secondMax + tolerance;
 546
 547    /// <summary>
 548    /// Retrieves all neighboring grids connected to this grid.
 549    /// </summary>
 550    /// <returns>An enumeration of all neighboring grids.</returns>
 551    public IEnumerable<VoxelGrid> GetAllGridNeighbors()
 552    {
 3553        if (!IsConjoined)
 1554            yield break;
 555
 2556        var values = Neighbors!.DenseValues;
 2557        int count = Neighbors.Count;
 558
 14559        for (int i = 0; i < count; i++)
 560        {
 5561            SwiftHashSet<int> neighborSet = values[i];
 20562            foreach (int neighborIndex in neighborSet)
 563            {
 5564                if (World!.TryGetGrid(neighborIndex, out VoxelGrid? neighborGrid))
 565                {
 5566                    yield return neighborGrid!;
 567                }
 568            }
 569        }
 2570    }
 571
 572    /// <summary>
 573    /// Determines whether the given voxel coordinates are within the valid range of the grid.
 574    /// </summary>
 575    public bool IsValidVoxelIndex(int x, int y, int z)
 576    {
 1720577        if (!IsActive)
 578        {
 6579            GridForgeLogger.Channel.Warn($"This Grid is not currently active.");
 6580            return false;
 581        }
 582
 1714583        bool result = IsVoxelIndexInBounds(x, y, z);
 584
 1714585        if (!result)
 280586            GridForgeLogger.Channel.Info($"The coordinate {(x, y, z)} is not valid for this grid.");
 587
 1714588        return result;
 589    }
 590
 591    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 592    private bool IsVoxelIndexInBounds(int x, int y, int z) =>
 1714593         (uint)x < (uint)Width
 1714594      && (uint)y < (uint)Height
 1714595      && (uint)z < (uint)Length;
 596
 597    /// <summary>
 598    /// Determines if a topology-local voxel index is facing the rectangular-prism boundary in the supplied direction.
 599    /// </summary>
 600    public bool IsFacingBoundary(VoxelIndex voxelIndex, RectangularDirection direction) =>
 56601        TryGetNeighborSlot(direction, out int slot)
 56602        && _topology!.IsFacingBoundary(voxelIndex, slot, Width, Height, Length);
 603
 604    /// <summary>
 605    /// Determines if a topology-local voxel index is facing the hex-prism boundary in the supplied direction.
 606    /// </summary>
 607    public bool IsFacingBoundary(VoxelIndex voxelIndex, HexDirection direction) =>
 5608        TryGetNeighborSlot(direction, out int slot)
 5609        && _topology!.IsFacingBoundary(voxelIndex, slot, Width, Height, Length);
 610
 611    /// <summary>
 612    /// Converts a world position to a topology-local voxel index within the grid.
 613    /// Rectangular-prism grids return X/Y/Z coordinates; hex-prism grids return axial Q, layer, and axial R in X/Y/Z fi
 614    /// </summary>
 615    public bool TryGetVoxelIndex(Vector3d position, out VoxelIndex result)
 616    {
 1509617        result = default;
 618
 1509619        if (!IsActive)
 620        {
 3621            GridForgeLogger.Channel.Warn($"This Grid is not currently allocated.");
 3622            return false;
 623        }
 624
 1506625        if (!Topology.TryGetVoxelIndex(BoundsMin, BoundsMax, Width, Height, Length, position, out VoxelIndex voxelIndex)
 626        {
 15627            GridForgeLogger.Channel.Warn($"Position does not fall in the bounds of this grid");
 15628            return false;
 629        }
 630
 1491631        result = voxelIndex;
 1491632        return true;
 633    }
 634
 635    /// <summary>
 636    /// Converts a 2D XZ-plane world position on the default world Y layer to a voxel index within the grid.
 637    /// </summary>
 638    /// <param name="position">The 2D position whose X component maps to world X and Y component maps to world Z.</param
 639    /// <param name="result">The resolved voxel index, if found.</param>
 640    /// <returns>True if the position resolved to an allocated voxel index; otherwise false.</returns>
 641    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 642    public bool TryGetVoxelIndex(Vector2d position, out VoxelIndex result) =>
 1643        TryGetVoxelIndex(position, default, out result);
 644
 645    /// <summary>
 646    /// Converts a 2D XZ-plane world position on the supplied world Y layer to a voxel index within the grid.
 647    /// </summary>
 648    /// <param name="position">The 2D position whose X component maps to world X and Y component maps to world Z.</param
 649    /// <param name="layerY">The world Y layer to resolve. Defaults to zero when omitted by paired overloads.</param>
 650    /// <param name="result">The resolved voxel index, if found.</param>
 651    /// <returns>True if the position resolved to an allocated voxel index; otherwise false.</returns>
 652    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 653    public bool TryGetVoxelIndex(Vector2d position, Fixed64 layerY, out VoxelIndex result) =>
 5654        TryGetVoxelIndex(GridPlane2d.ToWorld(position, layerY), out result);
 655
 656    /// <summary>
 657    /// Checks if a voxel at the given topology-local coordinates is allocated within the grid.
 658    /// </summary>
 659    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 660    public bool IsVoxelAllocated(int x, int y, int z) =>
 39661        IsValidVoxelIndex(x, y, z) && _storage!.TryGetVoxel(x, y, z, out _);
 662
 663    /// <summary>
 664    /// Checks whether a physical voxel is configured at the supplied grid-local index.
 665    /// </summary>
 666    /// <param name="voxelIndex">The grid-local voxel index to test.</param>
 667    /// <returns>True when the index resolves to a configured voxel; otherwise false.</returns>
 668    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 669    public bool ContainsVoxel(VoxelIndex voxelIndex) =>
 31670        IsVoxelAllocated(voxelIndex.x, voxelIndex.y, voxelIndex.z);
 671
 672    /// <summary>
 673    /// Configures a sparse voxel at runtime. Dense grids, invalid indices, and already-configured
 674    /// sparse voxels return false.
 675    /// </summary>
 676    /// <param name="voxelIndex">The grid-local voxel index to configure.</param>
 677    /// <param name="voxel">The configured voxel when the operation succeeds.</param>
 678    /// <returns>True when a new sparse voxel was configured; otherwise false.</returns>
 679    public bool TryAddVoxel(VoxelIndex voxelIndex, out Voxel? voxel)
 680    {
 34681        voxel = null;
 34682        if (!CanMutateSparseVoxel(voxelIndex))
 1683            return false;
 684
 33685        if (!_sparseStorage.TryAddVoxel(this, voxelIndex, out voxel))
 1686            return false;
 687
 32688        uint gridVersion = IncrementVersion();
 32689        voxel!.CachedGridVersion = gridVersion;
 32690        World!.NotifyActiveGridChange(this, GridEventKind.SparseVoxelAdded, voxelIndex, voxel.WorldPosition);
 32691        return true;
 692    }
 693
 694    /// <summary>
 695    /// Removes a configured sparse voxel at runtime when it has no unsafe runtime state.
 696    /// Dense grids, missing voxels, occupied voxels, voxels with obstacle tokens, partitioned voxels,
 697    /// and voxels with active event subscribers return false.
 698    /// </summary>
 699    /// <param name="voxelIndex">The grid-local voxel index to remove.</param>
 700    /// <returns>True when the sparse voxel was removed; otherwise false.</returns>
 701    public bool TryRemoveVoxel(VoxelIndex voxelIndex)
 702    {
 19703        if (!CanMutateSparseVoxel(voxelIndex)
 19704            || !TryGetVoxel(voxelIndex, out Voxel? voxel)
 19705            || !CanRemoveSparseVoxel(voxel!))
 706        {
 7707            return false;
 708        }
 709
 12710        Vector3d affectedPosition = voxel!.WorldPosition;
 12711        _sparseStorage.TryRemoveVoxel(this, voxelIndex, out _);
 712
 12713        IncrementVersion();
 12714        World!.NotifyActiveGridChange(this, GridEventKind.SparseVoxelRemoved, voxelIndex, affectedPosition);
 12715        return true;
 716    }
 717
 718    private bool CanMutateSparseVoxel(VoxelIndex voxelIndex) =>
 53719        IsActive
 53720        && StorageKind == GridStorageKind.Sparse
 53721        && IsValidVoxelIndex(voxelIndex.x, voxelIndex.y, voxelIndex.z);
 722
 723    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 724    private static bool CanRemoveSparseVoxel(Voxel voxel) =>
 18725        voxel.IsAllocated
 18726        && !voxel.IsOccupied
 18727        && voxel.ObstacleCount == 0
 18728        && !voxel.IsPartioned
 18729        && !voxel.HasEventSubscribers;
 730
 731    /// <summary>
 732    /// Retrieves the <see cref="Voxel"/> at the specified topology-local coordinates, if allocated.
 733    /// </summary>
 734    public bool TryGetVoxel(int x, int y, int z, out Voxel? result)
 735    {
 1627736        result = null;
 737
 1627738        if (!IsValidVoxelIndex(x, y, z))
 279739            return false;
 740
 1348741        return _storage!.TryGetVoxel(x, y, z, out result);
 742    }
 743
 744    /// <summary>
 745    /// Enumerates physical voxels configured in this grid in deterministic storage order.
 746    /// </summary>
 747    public IEnumerable<Voxel> EnumerateVoxels() =>
 10748        _storage?.EnumerateVoxels() ?? Array.Empty<Voxel>();
 749
 750    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 751    internal void VisitVoxels<TVisitor>(ref TVisitor visitor)
 752        where TVisitor : struct, IVoxelStorageVisitor =>
 86753        _storage?.VisitVoxels(ref visitor);
 754
 755    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 756    internal void AddVoxelsInIndexRange(
 757        VoxelIndex min,
 758        VoxelIndex max,
 759        SwiftList<Voxel> results,
 760        SwiftHashSet<Voxel> redundancy) =>
 207761        _storage?.AddVoxelsInIndexRange(min, max, results, redundancy);
 762
 763    /// <summary>
 764    /// Retrieves a grid voxel from a topology-local coordinate.
 765    /// </summary>
 766    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 767    public bool TryGetVoxel(VoxelIndex voxelIndex, out Voxel? result) =>
 828768         TryGetVoxel(voxelIndex.x, voxelIndex.y, voxelIndex.z, out result);
 769
 770    /// <summary>
 771    /// Retrieve <see cref="Voxel"/> from world <see cref="Vector3d"/> points
 772    /// </summary>
 773    /// <returns><see cref="Voxel"/> at the given position or null if the position is not valid.</returns>
 774    public bool TryGetVoxel(Vector3d position, out Voxel? result)
 775    {
 783776        result = null;
 783777        return TryGetVoxelIndex(position, out VoxelIndex coordinate)
 783778            && TryGetVoxel(coordinate.x, coordinate.y, coordinate.z, out result);
 779    }
 780
 781    /// <summary>
 782    /// Retrieves the physical voxel whose center is nearest to the supplied world position.
 783    /// Sparse grids only consider configured physical voxels.
 784    /// </summary>
 785    /// <param name="position">The world position to resolve.</param>
 786    /// <param name="result">The closest physical voxel, if found.</param>
 787    /// <returns>True if a physical voxel was resolved; otherwise false.</returns>
 788    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 789    public bool TryGetClosestVoxel(Vector3d position, out Voxel? result) =>
 14790        TryGetClosestVoxel(position, out result, out _);
 791
 792    internal bool TryGetClosestVoxel(
 793        Vector3d position,
 794        out Voxel? result,
 795        out Fixed64 distanceSquared)
 796    {
 28797        result = null;
 28798        distanceSquared = Fixed64.MaxValue;
 799
 28800        if (!IsActive)
 801        {
 3802            GridForgeLogger.Channel.Warn($"This Grid is not currently allocated.");
 3803            return false;
 804        }
 805
 25806        if (ConfiguredVoxelCount == 0)
 1807            return false;
 808
 24809        VoxelIndex closestIndex = Topology.GetClosestVoxelIndex(BoundsMin, Width, Height, Length, position);
 24810        return _storage!.TryGetClosestVoxel(this, closestIndex, position, out result, out distanceSquared);
 811    }
 812
 813    /// <summary>
 814    /// Retrieves a <see cref="Voxel"/> from a 2D XZ-plane world position on the default world Y layer.
 815    /// </summary>
 816    /// <param name="position">The 2D position whose X component maps to world X and Y component maps to world Z.</param
 817    /// <param name="result">The resolved voxel, if found.</param>
 818    /// <returns>True if the voxel was resolved; otherwise false.</returns>
 819    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 820    public bool TryGetVoxel(Vector2d position, out Voxel? result) =>
 4821        TryGetVoxel(position, default, out result);
 822
 823    /// <summary>
 824    /// Retrieves a <see cref="Voxel"/> from a 2D XZ-plane world position on the supplied world Y layer.
 825    /// </summary>
 826    /// <param name="position">The 2D position whose X component maps to world X and Y component maps to world Z.</param
 827    /// <param name="layerY">The world Y layer to resolve. Defaults to zero when omitted by paired overloads.</param>
 828    /// <param name="result">The resolved voxel, if found.</param>
 829    /// <returns>True if the voxel was resolved; otherwise false.</returns>
 830
 831    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 832    public bool TryGetVoxel(Vector2d position, Fixed64 layerY, out Voxel? result) =>
 9833        TryGetVoxel(GridPlane2d.ToWorld(position, layerY), out result);
 834
 835    /// <summary>
 836    /// Retrieves the physical voxel whose center is nearest to a 2D XZ-plane world position on the default world Y laye
 837    /// Sparse grids only consider configured physical voxels.
 838    /// </summary>
 839    /// <param name="position">The 2D position whose X component maps to world X and Y component maps to world Z.</param
 840    /// <param name="result">The closest physical voxel, if found.</param>
 841    /// <returns>True if a physical voxel was resolved; otherwise false.</returns>
 842    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 843    public bool TryGetClosestVoxel(Vector2d position, out Voxel? result) =>
 1844        TryGetClosestVoxel(position, default, out result);
 845
 846    /// <summary>
 847    /// Retrieves the physical voxel whose center is nearest to a 2D XZ-plane world position on the supplied world Y lay
 848    /// Sparse grids only consider configured physical voxels.
 849    /// </summary>
 850    /// <param name="position">The 2D position whose X component maps to world X and Y component maps to world Z.</param
 851    /// <param name="layerY">The world Y layer to resolve. Defaults to zero when omitted by paired overloads.</param>
 852    /// <param name="result">The closest physical voxel, if found.</param>
 853    /// <returns>True if a physical voxel was resolved; otherwise false.</returns>
 854    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 855    public bool TryGetClosestVoxel(Vector2d position, Fixed64 layerY, out Voxel? result) =>
 2856        TryGetClosestVoxel(GridPlane2d.ToWorld(position, layerY), out result);
 857
 858    /// <summary>
 859    /// Computes the scan cell key for a given world position.
 860    /// </summary>
 861    public int GetScanCellKey(Vector3d position)
 862    {
 23863        if (!TryGetVoxelIndex(position, out VoxelIndex voxelIndex))
 1864            return -1;
 865
 22866        return GetScanCellKey(voxelIndex);
 867    }
 868
 869    /// <summary>
 870    /// Calculates the spatial cell index for a given position.
 871    /// </summary>
 872    public int GetScanCellKey(VoxelIndex voxelIndex)
 873    {
 96031874        (int x, int y, int z) = (
 96031875                voxelIndex.x / ScanCellSize,
 96031876                voxelIndex.y / ScanCellSize,
 96031877                voxelIndex.z / ScanCellSize
 96031878            );
 879
 96031880        int scanCellKey = GetScanCellKey(x, y, z);
 96031881        if (scanCellKey == -1)
 882        {
 5883            GridForgeLogger.Channel.Warn($"Position {voxelIndex} is not in the bounds for this grids Scan Cell overlay."
 5884            return -1;
 885        }
 886
 96026887        return scanCellKey;
 888    }
 889
 890    /// <summary>
 891    /// Calculates a unique scan cell key from grid-local scan cell coordinates.
 892    /// </summary>
 893    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 894    internal int GetScanCellKey(int x, int y, int z)
 895    {
 99995896        if ((uint)x >= (uint)_scanWidth
 99995897            || (uint)y >= (uint)_scanHeight
 99995898            || (uint)z >= (uint)_scanLength)
 899        {
 6900            return -1;
 901        }
 902
 99989903        return x + y * _scanWidth + z * _scanLayerSize;
 904    }
 905
 906    /// <summary>
 907    /// Retrieves a scan cell from the grid using its key.
 908    /// </summary>
 909    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 910    public bool TryGetScanCell(int key, out ScanCell? outScanCell)
 911    {
 614912        outScanCell = null;
 614913        return _storage?.TryGetScanCell(key, out outScanCell) == true;
 914    }
 915
 916    /// <summary>
 917    /// Retrieves the scan cell corresponding to a given world position.
 918    /// </summary>
 919    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 920    public bool TryGetScanCell(Vector3d position, out ScanCell? outScanCell)
 921    {
 18922        int key = GetScanCellKey(position);
 18923        return TryGetScanCell(key, out outScanCell);
 924    }
 925
 926    /// <summary>
 927    /// Retrieves the scan cell associated with the given voxel index.
 928    /// </summary>
 929    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 930    public bool TryGetScanCell(VoxelIndex voxelIndex, out ScanCell? outScanCell)
 931    {
 7932        outScanCell = null;
 7933        return TryGetVoxel(voxelIndex, out Voxel? voxel)
 7934            && TryGetScanCell(voxel!.ScanCellKey, out outScanCell);
 935    }
 936
 937    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 938    internal void AddScanCellsInRange(
 939        int xMin,
 940        int yMin,
 941        int zMin,
 942        int xMax,
 943        int yMax,
 944        int zMax,
 945        SwiftList<ScanCell> results,
 946        SwiftHashSet<ScanCell> redundancy) =>
 546947        _storage?.AddScanCellsInRange(
 546948            this,
 546949            xMin,
 546950            yMin,
 546951            zMin,
 546952            xMax,
 546953            yMax,
 546954            zMax,
 546955            results,
 546956            redundancy);
 957
 958    /// <summary>
 959    /// Enumerates all currently active scan cells within the grid.
 960    /// </summary>
 961    public IEnumerable<ScanCell> GetActiveScanCells()
 962    {
 5963        if (!IsActive || !IsOccupied)
 4964            yield break;
 965
 6966        foreach (int activeCellKey in ActiveScanCells!)
 967        {
 2968            if (_storage!.TryGetScanCell(activeCellKey, out ScanCell? scanCell))
 2969                yield return scanCell!;
 970        }
 1971    }
 972
 973    /// <summary>
 974    /// Helper function to ceil snap a <see cref="Vector3d"/> through this grid's topology, ensuring it stays within gri
 975    /// </summary>
 976    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 977    public Vector3d CeilToGrid(Vector3d position) =>
 3978         Topology.CeilToGrid(BoundsMin, BoundsMax, Width, Height, Length, position);
 979
 980    /// <summary>
 981    /// Helper function to floor snap a <see cref="Vector3d"/> through this grid's topology, ensuring it stays within gr
 982    /// </summary>
 983    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 984    public Vector3d FloorToGrid(Vector3d position) =>
 213985        Topology.FloorToGrid(BoundsMin, BoundsMax, Width, Height, Length, position);
 986
 987    /// <summary>
 988    /// Snaps a given position to the topology-local scan cell in the grid.
 989    /// </summary>
 990    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 991    public (int x, int y, int z) SnapToScanCell(Vector3d position) =>
 1085992        Topology.SnapToScanCell(BoundsMin, position, ScanCellSize);
 993
 994    /// <summary>
 995    /// Normalizes world-space bounds to this grid's topology-aligned coverage bounds.
 996    /// </summary>
 997    /// <param name="min">The first world-space bounds corner.</param>
 998    /// <param name="max">The second world-space bounds corner.</param>
 999    /// <param name="padding">Optional non-negative padding applied before normalization.</param>
 1000    /// <returns>Topology-aligned minimum and maximum bounds suitable for deterministic coverage scans.</returns>
 1001    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 1002    public (Vector3d min, Vector3d max) NormalizeBounds(Vector3d min, Vector3d max, Fixed64? padding = null) =>
 7761003        Topology.NormalizeBounds(min, max, padding);
 1004
 1005    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 1006    internal Vector3d GetWorldPosition(VoxelIndex index) =>
 960311007        Topology.GetWorldPosition(BoundsMin, index);
 1008
 1009    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 1010    internal Vector3d GetWorldOffset((int x, int y, int z) offset) =>
 921011        Topology.GetWorldOffset(offset);
 1012
 1013    /// <inheritdoc/>
 1014    public override int GetHashCode() =>
 6221015        SwiftHashTools.CombineHashCodes(
 6221016            GridIndex.GetHashCode(),
 6221017            BoundsMin.GetHashCode(),
 6221018            BoundsMax.GetHashCode());
 1019
 1020    #endregion
 1021}

Methods/Properties

get_BoundsMin()
get_BoundsMax()
get_BoundsCenter()
get_ConfiguredVoxelCount()
get_StorageKind()
get_Voxels()
get_NeighborSlotCount()
get_TopologyKind()
get_IsConjoined()
get_ScanCellSize()
get_ScanCells()
get_IsOccupied()
.ctor()
get_Topology()
get_ScanWidth()
get_ScanHeight()
get_ScanLength()
Initialize(GridForge.Grids.GridWorld,System.UInt16,GridForge.Configuration.GridConfiguration,GridForge.Grids.Topology.IGridTopology,GridForge.Spatial.VoxelIndex[])
Reset()
ReleaseActiveScanCells()
ReleaseNeighbors()
ClearDimensions()
IncrementVersion()
ConfigureScanDimensions()
GetRectangularNeighborDirection(GridForge.Grids.VoxelGrid,GridForge.Grids.VoxelGrid)
GetHexNeighborDirection(GridForge.Grids.VoxelGrid,GridForge.Grids.VoxelGrid)
TryGetNeighborSlot(GridForge.Grids.VoxelGrid,GridForge.Grids.VoxelGrid,GridForge.Grids.Topology.GridTopologyKind,System.Int32&)
TryGetNeighborSlot(GridForge.Grids.VoxelGrid,GridForge.Grids.VoxelGrid,System.Int32&)
GetNeighborOffset(System.Int32)
TryGetNeighborSlot(GridForge.Spatial.RectangularDirection,System.Int32&)
TryGetNeighborSlot(GridForge.Spatial.HexDirection,System.Int32&)
TryAddGridNeighbor(GridForge.Grids.VoxelGrid)
TryRemoveGridNeighbor(GridForge.Grids.VoxelGrid)
TryGetGridNeighborSet(GridForge.Grids.VoxelGrid,System.Int32&,SwiftCollections.SwiftHashSet`1<System.Int32>&)
ReleaseNeighborSetIfEmpty(System.Int32,SwiftCollections.SwiftHashSet`1<System.Int32>)
IsOnBoundary(GridForge.Spatial.VoxelIndex)
IsInBounds(FixedMathSharp.Vector3d)
IsGridOverlapValid(GridForge.Grids.VoxelGrid,GridForge.Grids.VoxelGrid,System.Nullable`1<FixedMathSharp.Fixed64>)
AxisOverlaps(FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64)
GetAllGridNeighbors()
IsValidVoxelIndex(System.Int32,System.Int32,System.Int32)
IsVoxelIndexInBounds(System.Int32,System.Int32,System.Int32)
IsFacingBoundary(GridForge.Spatial.VoxelIndex,GridForge.Spatial.RectangularDirection)
IsFacingBoundary(GridForge.Spatial.VoxelIndex,GridForge.Spatial.HexDirection)
TryGetVoxelIndex(FixedMathSharp.Vector3d,GridForge.Spatial.VoxelIndex&)
TryGetVoxelIndex(FixedMathSharp.Vector2d,GridForge.Spatial.VoxelIndex&)
TryGetVoxelIndex(FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,GridForge.Spatial.VoxelIndex&)
IsVoxelAllocated(System.Int32,System.Int32,System.Int32)
ContainsVoxel(GridForge.Spatial.VoxelIndex)
TryAddVoxel(GridForge.Spatial.VoxelIndex,GridForge.Grids.Voxel&)
TryRemoveVoxel(GridForge.Spatial.VoxelIndex)
CanMutateSparseVoxel(GridForge.Spatial.VoxelIndex)
CanRemoveSparseVoxel(GridForge.Grids.Voxel)
TryGetVoxel(System.Int32,System.Int32,System.Int32,GridForge.Grids.Voxel&)
EnumerateVoxels()
VisitVoxels(TVisitor&)
AddVoxelsInIndexRange(GridForge.Spatial.VoxelIndex,GridForge.Spatial.VoxelIndex,SwiftCollections.SwiftList`1<GridForge.Grids.Voxel>,SwiftCollections.SwiftHashSet`1<GridForge.Grids.Voxel>)
TryGetVoxel(GridForge.Spatial.VoxelIndex,GridForge.Grids.Voxel&)
TryGetVoxel(FixedMathSharp.Vector3d,GridForge.Grids.Voxel&)
TryGetClosestVoxel(FixedMathSharp.Vector3d,GridForge.Grids.Voxel&)
TryGetClosestVoxel(FixedMathSharp.Vector3d,GridForge.Grids.Voxel&,FixedMathSharp.Fixed64&)
TryGetVoxel(FixedMathSharp.Vector2d,GridForge.Grids.Voxel&)
TryGetVoxel(FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,GridForge.Grids.Voxel&)
TryGetClosestVoxel(FixedMathSharp.Vector2d,GridForge.Grids.Voxel&)
TryGetClosestVoxel(FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,GridForge.Grids.Voxel&)
GetScanCellKey(FixedMathSharp.Vector3d)
GetScanCellKey(GridForge.Spatial.VoxelIndex)
GetScanCellKey(System.Int32,System.Int32,System.Int32)
TryGetScanCell(System.Int32,GridForge.Grids.ScanCell&)
TryGetScanCell(FixedMathSharp.Vector3d,GridForge.Grids.ScanCell&)
TryGetScanCell(GridForge.Spatial.VoxelIndex,GridForge.Grids.ScanCell&)
AddScanCellsInRange(System.Int32,System.Int32,System.Int32,System.Int32,System.Int32,System.Int32,SwiftCollections.SwiftList`1<GridForge.Grids.ScanCell>,SwiftCollections.SwiftHashSet`1<GridForge.Grids.ScanCell>)
GetActiveScanCells()
CeilToGrid(FixedMathSharp.Vector3d)
FloorToGrid(FixedMathSharp.Vector3d)
SnapToScanCell(FixedMathSharp.Vector3d)
NormalizeBounds(FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,System.Nullable`1<FixedMathSharp.Fixed64>)
GetWorldPosition(GridForge.Spatial.VoxelIndex)
GetWorldOffset(System.ValueTuple`3<System.Int32,System.Int32,System.Int32>)
GetHashCode()