< 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: 276
Uncovered lines: 0
Coverable lines: 276
Total lines: 991
Line coverage: 100%
Branch coverage
100%
Covered branches: 188
Total branches: 188
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_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%
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(...)100%66100%
CanMutateSparseVoxel(...)100%44100%
CanRemoveSparseVoxel(...)100%88100%
TryGetVoxel(...)100%22100%
EnumerateVoxels()100%44100%
VisitVoxels(...)100%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(...)100%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%

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 System;
 9using System.Collections.Generic;
 10using System.Runtime.CompilerServices;
 11using FixedMathSharp;
 12using GridForge.Configuration;
 13using GridForge.Grids.Storage;
 14using GridForge.Grids.Topology;
 15using GridForge.Spatial;
 16using SwiftCollections;
 17using SwiftCollections.Dimensions;
 18using SwiftCollections.Pool;
 19
 20namespace GridForge.Grids;
 21
 22/// <summary>
 23/// Represents a 3D grid structure for spatial organization, managing voxels and scan cells.
 24/// Handles initialization, neighbor relationships, and occupancy tracking.
 25/// </summary>
 26public class VoxelGrid
 27{
 28    #region Fields & Properties
 29
 30    /// <summary>
 31    /// Nonzero 64-bit world-local allocation generation identifying this active grid instance.
 32    /// Zero indicates an inactive or unallocated grid.
 33    /// </summary>
 34    public long 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>
 13512362    public Vector3d BoundsMin => Configuration.BoundsMin;
 63
 64    /// <summary>
 65    /// Maximum bounds of the grid in world coordinates.
 66    /// </summary>
 1072067    public Vector3d BoundsMax => Configuration.BoundsMax;
 68
 69    /// <summary>
 70    /// Center position of the grid in world space.
 71    /// </summary>
 36672    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)]
 75101        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)]
 8886110        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>
 397138    internal int NeighborSlotCount => _topology?.NeighborSlotCount ?? 0;
 139
 140    /// <summary>
 141    /// The active topology kind for this grid.
 142    /// </summary>
 125143    internal GridTopologyKind? TopologyKind => _topology?.Kind;
 144
 145    /// <summary>
 146    /// Determines whether this grid has any linked neighbors.
 147    /// </summary>
 88148    public bool IsConjoined => Neighbors != null && NeighborCount > 0;
 149
 150    /// <summary>
 151    /// Size of a scan cell used for spatial partitioning.
 152    /// </summary>
 370051153    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>
 29177    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;
 59196    private readonly DenseVoxelGridStorage _denseStorage = new();
 59197    private readonly SparseVoxelGridStorage _sparseStorage = new();
 198
 130269199    internal IGridTopology Topology => _topology!;
 200
 201    internal int ScanWidth
 202    {
 203        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 1354204        get => _scanWidth;
 205    }
 206
 207    internal int ScanHeight
 208    {
 209        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 1653210        get => _scanHeight;
 211    }
 212
 213    internal int ScanLength
 214    {
 215        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 2892216        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="spawnToken">The world-local allocation generation for this grid.</param>
 229    /// <param name="configuration">The normalized configuration settings for the grid.</param>
 230    /// <param name="topology">The validated topology instance for this grid.</param>
 231    /// <param name="configuredVoxels">The validated sparse voxel indices to materialize.</param>
 232    internal void Initialize(
 233        GridWorld world,
 234        ushort gridIndex,
 235        long spawnToken,
 236        GridConfiguration configuration,
 237        IGridTopology topology,
 238        VoxelIndex[] configuredVoxels)
 239    {
 558240        Version = 1;
 241
 558242        World = world;
 558243        GridIndex = gridIndex;
 244
 558245        Configuration = configuration;
 558246        _topology = topology;
 247
 558248        SpawnToken = spawnToken;
 249
 250        // +1 to account for inclusive bounds and to ensure that even the smallest grids (1x1x1) remain valid.
 558251        GridDimensions dimensions = topology.CalculateDimensions(BoundsMin, BoundsMax);
 558252        Width = dimensions.Width;
 558253        Height = dimensions.Height;
 558254        Length = dimensions.Length;
 558255        Size = Width * Height * Length;
 256
 558257        ConfigureScanDimensions();
 558258        if (configuration.StorageKind == GridStorageKind.Sparse)
 259        {
 101260            _sparseStorage.Initialize(this, configuredVoxels);
 101261            _storage = _sparseStorage;
 262        }
 263        else
 264        {
 457265            _denseStorage.Initialize(this);
 457266            _storage = _denseStorage;
 267        }
 268
 558269        IsActive = true;
 558270    }
 271
 272    /// <summary>
 273    /// Resets the grid, clearing all voxels and scan cells.
 274    /// </summary>
 275    internal void Reset()
 276    {
 560277        if (!IsActive)
 2278            return;
 279
 558280        _storage!.Reset(this);
 558281        _storage = null;
 282
 283        // Just in case since voxels should have already cleared any registered obstacles.
 558284        ObstacleCount = 0;
 285
 558286        ReleaseActiveScanCells();
 558287        ReleaseNeighbors();
 288
 558289        Configuration = default;
 558290        World = null;
 558291        _topology = null;
 292
 558293        SpawnToken = 0;
 558294        Version = 0;
 295
 558296        GridIndex = ushort.MaxValue;
 297
 558298        ClearDimensions();
 299
 558300        IsActive = false;
 558301    }
 302
 303    private void ReleaseActiveScanCells()
 304    {
 558305        if (ActiveScanCells == null)
 511306            return;
 307
 47308        SwiftHashSetPool<int>.Shared.Release(ActiveScanCells);
 47309        ActiveScanCells = null;
 47310    }
 311
 312    private void ReleaseNeighbors()
 313    {
 558314        if (Neighbors == null)
 495315            return;
 316
 282317        foreach (SwiftHashSet<int> neighbors in Neighbors.Values)
 78318            SwiftHashSetPool<int>.Shared.Release(neighbors);
 319
 63320        Neighbors = null;
 63321        NeighborCount = 0;
 63322    }
 323
 324    private void ClearDimensions()
 325    {
 558326        Width = 0;
 558327        Height = 0;
 558328        Length = 0;
 558329        Size = 0;
 558330        _scanWidth = 0;
 558331        _scanHeight = 0;
 558332        _scanLength = 0;
 558333        _scanLayerSize = 0;
 558334    }
 335
 336    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 337    internal uint IncrementVersion()
 338    {
 1867339        Version = Version == uint.MaxValue ? 1u : Version + 1u;
 1867340        return Version;
 341    }
 342
 343    #endregion
 344
 345    #region Grid Construction
 346
 347    private void ConfigureScanDimensions()
 348    {
 558349        _scanWidth = ((Width - 1) / ScanCellSize) + 1;
 558350        _scanHeight = ((Height - 1) / ScanCellSize) + 1;
 558351        _scanLength = ((Length - 1) / ScanCellSize) + 1;
 558352        _scanLayerSize = _scanWidth * _scanHeight;
 558353    }
 354
 355    #endregion
 356
 357    #region Boundary Management
 358
 359    /// <summary>
 360    /// Determines the rectangular-prism direction from grid <paramref name="a"/> to neighboring grid <paramref name="b"
 361    /// </summary>
 362    /// <param name="a">The source rectangular-prism grid.</param>
 363    /// <param name="b">The neighboring rectangular-prism grid.</param>
 364    /// <returns>The rectangular direction from <paramref name="a"/> to <paramref name="b"/>, or <see cref="RectangularD
 365    public static RectangularDirection GetRectangularNeighborDirection(VoxelGrid a, VoxelGrid b)
 366    {
 8367        return TryGetNeighborSlot(a, b, GridTopologyKind.RectangularPrism, out int slot)
 8368            ? (RectangularDirection)slot
 8369            : RectangularDirection.None;
 370    }
 371
 372    /// <summary>
 373    /// Determines the hex-prism direction from grid <paramref name="a"/> to neighboring grid <paramref name="b"/>.
 374    /// </summary>
 375    /// <param name="a">The source hex-prism grid.</param>
 376    /// <param name="b">The neighboring hex-prism grid.</param>
 377    /// <returns>The hex direction from <paramref name="a"/> to <paramref name="b"/>, or <see cref="HexDirection.None"/>
 378    public static HexDirection GetHexNeighborDirection(VoxelGrid a, VoxelGrid b)
 379    {
 7380        return TryGetNeighborSlot(a, b, GridTopologyKind.HexPrism, out int slot)
 7381            ? (HexDirection)slot
 7382            : HexDirection.None;
 383    }
 384
 385    private static bool TryGetNeighborSlot(VoxelGrid a, VoxelGrid b, GridTopologyKind expectedKind, out int slot)
 386    {
 15387        if (a._topology?.Kind != expectedKind || b._topology?.Kind != expectedKind)
 388        {
 10389            slot = -1;
 10390            return false;
 391        }
 392
 5393        return TryGetNeighborSlot(a, b, out slot);
 394    }
 395
 396    private static bool TryGetNeighborSlot(VoxelGrid a, VoxelGrid b, out int slot)
 397    {
 217398        slot = -1;
 399
 217400        if (a._topology == null
 217401            || b._topology == null
 217402            || a._topology.Kind != b._topology.Kind)
 403        {
 34404            return false;
 405        }
 406
 183407        return a._topology.TryGetNeighborSlotFromWorldDelta(b.BoundsCenter - a.BoundsCenter, out slot)
 183408            && (uint)slot < (uint)a._topology.NeighborSlotCount;
 409    }
 410
 411    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 455412    internal VoxelIndex GetNeighborOffset(int slot) => Topology.GetNeighborOffset(slot);
 413
 414    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 415    internal bool TryGetNeighborSlot(RectangularDirection direction, out int slot)
 416    {
 131417        slot = (int)direction;
 131418        return _topology?.Kind == GridTopologyKind.RectangularPrism
 131419            && (uint)slot < (uint)_topology.NeighborSlotCount;
 420    }
 421
 422    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 423    internal bool TryGetNeighborSlot(HexDirection direction, out int slot)
 424    {
 14425        slot = (int)direction;
 14426        return _topology?.Kind == GridTopologyKind.HexPrism
 14427            && (uint)slot < (uint)_topology.NeighborSlotCount;
 428    }
 429
 430    /// <summary>
 431    /// Adds a neighboring grid and updates relationships.
 432    /// </summary>
 433    /// <param name="neighborGrid">The neighboring grid to add.</param>
 434    internal bool TryAddGridNeighbor(VoxelGrid neighborGrid)
 435    {
 186436        if (!TryGetNeighborSlot(this, neighborGrid, out int neighborSlot))
 43437            return false;
 438
 439        // Ensure the neighbor array is allocated and store the new neighbor
 143440        Neighbors ??= new SwiftSparseMap<SwiftHashSet<int>>();
 143441        if (!Neighbors.TryGetValue(neighborSlot, out SwiftHashSet<int> neighborSet))
 442        {
 92443            neighborSet = SwiftHashSetPool<int>.Shared.Rent();
 92444            Neighbors.Add(neighborSlot, neighborSet);
 445        }
 446
 143447        if (!neighborSet.Add(neighborGrid.GridIndex))
 1448            return false;
 449
 142450        NeighborCount++;
 142451        IncrementVersion();
 452
 142453        return true;
 454    }
 455
 456    /// <summary>
 457    /// Removes a neighboring grid relationship.
 458    /// </summary>
 459    /// <param name="neighborGrid">The neighboring grid to remove.</param>
 460    internal bool TryRemoveGridNeighbor(VoxelGrid neighborGrid)
 461    {
 25462        if (!TryGetGridNeighborSet(neighborGrid, out int neighborSlot, out SwiftHashSet<int>? neighborSet))
 2463            return false;
 464
 23465        if (!neighborSet!.Remove(neighborGrid.GridIndex))
 1466            return false;
 467
 22468        ReleaseNeighborSetIfEmpty(neighborSlot, neighborSet);
 469
 22470        if (--NeighborCount == 0)
 11471            Neighbors = null;
 472
 22473        IncrementVersion();
 474
 22475        return true;
 476    }
 477
 478    private bool TryGetGridNeighborSet(
 479        VoxelGrid neighborGrid,
 480        out int neighborSlot,
 481        out SwiftHashSet<int>? neighborSet)
 482    {
 25483        neighborSet = null;
 25484        neighborSlot = -1;
 485
 25486        if (!IsConjoined)
 1487            return false;
 488
 24489        return TryGetNeighborSlot(this, neighborGrid, out neighborSlot)
 24490            && Neighbors!.TryGetValue(neighborSlot, out neighborSet);
 491    }
 492
 493    private void ReleaseNeighborSetIfEmpty(int neighborIndex, SwiftHashSet<int> neighborSet)
 494    {
 22495        if (neighborSet.Count > 0)
 8496            return;
 497
 14498        GridForgeLogger.Channel.Info($"Releasing unused neighbor collection.");
 14499        SwiftHashSetPool<int>.Shared.Release(neighborSet);
 14500        Neighbors!.Remove(neighborIndex);
 14501    }
 502
 503    #endregion
 504
 505    #region Grid Queries
 506
 507    /// <summary>
 508    /// Determines if a voxel coordinate is at the boundary of the grid.
 509    /// Used to determine if a voxel should update when a neighboring grid is added/removed.
 510    /// </summary>
 511    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 512    public bool IsOnBoundary(VoxelIndex coord) =>
 122231513         coord.x == 0 || coord.x == Width - 1
 122231514      || coord.y == 0 || coord.y == Height - 1
 122231515      || coord.z == 0 || coord.z == Length - 1;
 516
 517    /// <summary>
 518    /// Checks whether a given position falls within the grid bounds.
 519    /// </summary>
 520    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 521    public bool IsInBounds(Vector3d target) =>
 89522        IsActive && Topology.IsInBounds(BoundsMin, BoundsMax, Width, Height, Length, target);
 523
 524    /// <summary>
 525    /// Retrieves all neighboring grids connected to this grid.
 526    /// </summary>
 527    /// <returns>An enumeration of all neighboring grids.</returns>
 528    public IEnumerable<VoxelGrid> GetAllGridNeighbors()
 529    {
 13530        if (!IsConjoined)
 5531            yield break;
 532
 8533        var values = Neighbors!.DenseValues;
 8534        int count = Neighbors.Count;
 535
 38536        for (int i = 0; i < count; i++)
 537        {
 11538            SwiftHashSet<int> neighborSet = values[i];
 44539            foreach (int neighborIndex in neighborSet)
 540            {
 11541                if (World!.TryGetGrid(neighborIndex, out VoxelGrid? neighborGrid))
 542                {
 11543                    yield return neighborGrid!;
 544                }
 545            }
 546        }
 8547    }
 548
 549    /// <summary>
 550    /// Determines whether the given voxel coordinates are within the valid range of the grid.
 551    /// </summary>
 552    public bool IsValidVoxelIndex(int x, int y, int z)
 553    {
 1939554        if (!IsActive)
 555        {
 6556            GridForgeLogger.Channel.Warn($"This Grid is not currently active.");
 6557            return false;
 558        }
 559
 1933560        bool result = IsVoxelIndexInBounds(x, y, z);
 561
 1933562        if (!result)
 256563            GridForgeLogger.Channel.Info($"The coordinate {(x, y, z)} is not valid for this grid.");
 564
 1933565        return result;
 566    }
 567
 568    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 569    private bool IsVoxelIndexInBounds(int x, int y, int z) =>
 1933570         (uint)x < (uint)Width
 1933571      && (uint)y < (uint)Height
 1933572      && (uint)z < (uint)Length;
 573
 574    /// <summary>
 575    /// Determines if a topology-local voxel index is facing the rectangular-prism boundary in the supplied direction.
 576    /// </summary>
 577    public bool IsFacingBoundary(VoxelIndex voxelIndex, RectangularDirection direction) =>
 56578        TryGetNeighborSlot(direction, out int slot)
 56579        && _topology!.IsFacingBoundary(voxelIndex, slot, Width, Height, Length);
 580
 581    /// <summary>
 582    /// Determines if a topology-local voxel index is facing the hex-prism boundary in the supplied direction.
 583    /// </summary>
 584    public bool IsFacingBoundary(VoxelIndex voxelIndex, HexDirection direction) =>
 5585        TryGetNeighborSlot(direction, out int slot)
 5586        && _topology!.IsFacingBoundary(voxelIndex, slot, Width, Height, Length);
 587
 588    /// <summary>
 589    /// Converts a world position to a topology-local voxel index within the grid.
 590    /// Rectangular-prism grids return X/Y/Z coordinates; hex-prism grids return axial Q, layer, and axial R in X/Y/Z fi
 591    /// </summary>
 592    public bool TryGetVoxelIndex(Vector3d position, out VoxelIndex result)
 593    {
 1857594        result = default;
 595
 1857596        if (!IsActive)
 597        {
 3598            GridForgeLogger.Channel.Warn($"This Grid is not currently allocated.");
 3599            return false;
 600        }
 601
 1854602        if (!Topology.TryGetVoxelIndex(BoundsMin, BoundsMax, Width, Height, Length, position, out VoxelIndex voxelIndex)
 603        {
 18604            GridForgeLogger.Channel.Warn($"Position does not fall in the bounds of this grid");
 18605            return false;
 606        }
 607
 1836608        result = voxelIndex;
 1836609        return true;
 610    }
 611
 612    /// <summary>
 613    /// Converts a 2D XZ-plane world position on the default world Y layer to a voxel index within the grid.
 614    /// </summary>
 615    /// <param name="position">The 2D position whose X component maps to world X and Y component maps to world Z.</param
 616    /// <param name="result">The resolved voxel index, if found.</param>
 617    /// <returns>True if the position resolved to an allocated voxel index; otherwise false.</returns>
 618    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 619    public bool TryGetVoxelIndex(Vector2d position, out VoxelIndex result) =>
 1620        TryGetVoxelIndex(position, default, out result);
 621
 622    /// <summary>
 623    /// Converts a 2D XZ-plane world position on the supplied world Y layer to a voxel index within the grid.
 624    /// </summary>
 625    /// <param name="position">The 2D position whose X component maps to world X and Y component maps to world Z.</param
 626    /// <param name="layerY">The world Y layer to resolve. Defaults to zero when omitted by paired overloads.</param>
 627    /// <param name="result">The resolved voxel index, if found.</param>
 628    /// <returns>True if the position resolved to an allocated voxel index; otherwise false.</returns>
 629    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 630    public bool TryGetVoxelIndex(Vector2d position, Fixed64 layerY, out VoxelIndex result) =>
 5631        TryGetVoxelIndex(GridPlane2d.ToWorld(position, layerY), out result);
 632
 633    /// <summary>
 634    /// Checks if a voxel at the given topology-local coordinates is allocated within the grid.
 635    /// </summary>
 636    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 637    public bool IsVoxelAllocated(int x, int y, int z) =>
 69638        IsValidVoxelIndex(x, y, z) && _storage!.TryGetVoxel(x, y, z, out _);
 639
 640    /// <summary>
 641    /// Checks whether a physical voxel is configured at the supplied grid-local index.
 642    /// </summary>
 643    /// <param name="voxelIndex">The grid-local voxel index to test.</param>
 644    /// <returns>True when the index resolves to a configured voxel; otherwise false.</returns>
 645    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 646    public bool ContainsVoxel(VoxelIndex voxelIndex) =>
 61647        IsVoxelAllocated(voxelIndex.x, voxelIndex.y, voxelIndex.z);
 648
 649    /// <summary>
 650    /// Configures a sparse voxel at runtime. Dense grids, invalid indices, and already-configured
 651    /// sparse voxels return false.
 652    /// </summary>
 653    /// <param name="voxelIndex">The grid-local voxel index to configure.</param>
 654    /// <param name="voxel">The configured voxel when the operation succeeds.</param>
 655    /// <returns>True when a new sparse voxel was configured; otherwise false.</returns>
 656    public bool TryAddVoxel(VoxelIndex voxelIndex, out Voxel? voxel)
 657    {
 36658        voxel = null;
 36659        if (!CanMutateSparseVoxel(voxelIndex))
 1660            return false;
 661
 35662        if (!_sparseStorage.TryAddVoxel(this, voxelIndex, out voxel))
 1663            return false;
 664
 34665        uint gridVersion = IncrementVersion();
 34666        voxel!.CachedGridVersion = gridVersion;
 34667        World!.NotifyActiveGridChange(this, GridEventKind.SparseVoxelAdded, voxelIndex, voxel.WorldPosition);
 34668        return true;
 669    }
 670
 671    /// <summary>
 672    /// Removes a configured sparse voxel at runtime when it has no unsafe runtime state.
 673    /// Dense grids, missing voxels, occupied voxels, voxels with obstacle tokens, partitioned voxels,
 674    /// and voxels with active event subscribers return false.
 675    /// </summary>
 676    /// <param name="voxelIndex">The grid-local voxel index to remove.</param>
 677    /// <returns>True when the sparse voxel was removed; otherwise false.</returns>
 678    public bool TryRemoveVoxel(VoxelIndex voxelIndex)
 679    {
 20680        if (!CanMutateSparseVoxel(voxelIndex)
 20681            || !TryGetVoxel(voxelIndex, out Voxel? voxel)
 20682            || !CanRemoveSparseVoxel(voxel!))
 683        {
 8684            return false;
 685        }
 686
 12687        Vector3d affectedPosition = voxel!.WorldPosition;
 12688        _sparseStorage.TryRemoveVoxel(this, voxelIndex, out _);
 689
 12690        IncrementVersion();
 12691        World!.NotifyActiveGridChange(this, GridEventKind.SparseVoxelRemoved, voxelIndex, affectedPosition);
 12692        return true;
 693    }
 694
 695    private bool CanMutateSparseVoxel(VoxelIndex voxelIndex) =>
 56696        IsActive
 56697        && StorageKind == GridStorageKind.Sparse
 56698        && IsValidVoxelIndex(voxelIndex.x, voxelIndex.y, voxelIndex.z);
 699
 700    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 701    private static bool CanRemoveSparseVoxel(Voxel voxel) =>
 18702        voxel.IsAllocated
 18703        && !voxel.IsOccupied
 18704        && voxel.ObstacleCount == 0
 18705        && !voxel.IsPartioned
 18706        && !voxel.HasEventSubscribers;
 707
 708    /// <summary>
 709    /// Retrieves the <see cref="Voxel"/> at the specified topology-local coordinates, if allocated.
 710    /// </summary>
 711    public bool TryGetVoxel(int x, int y, int z, out Voxel? result)
 712    {
 1813713        result = null;
 714
 1813715        if (!IsValidVoxelIndex(x, y, z))
 255716            return false;
 717
 1558718        return _storage!.TryGetVoxel(x, y, z, out result);
 719    }
 720
 721    /// <summary>
 722    /// Enumerates physical voxels configured in this grid in deterministic storage order.
 723    /// </summary>
 724    public IEnumerable<Voxel> EnumerateVoxels() =>
 11725        _storage?.EnumerateVoxels() ?? Array.Empty<Voxel>();
 726
 727    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 728    internal void VisitVoxels<TVisitor>(ref TVisitor visitor)
 729        where TVisitor : struct, IVoxelStorageVisitor =>
 88730        _storage?.VisitVoxels(ref visitor);
 731
 732    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 733    internal void AddVoxelsInIndexRange(
 734        VoxelIndex min,
 735        VoxelIndex max,
 736        SwiftList<Voxel> results,
 737        SwiftHashSet<Voxel> redundancy) =>
 282738        _storage?.AddVoxelsInIndexRange(min, max, results, redundancy);
 739
 740    /// <summary>
 741    /// Retrieves a grid voxel from a topology-local coordinate.
 742    /// </summary>
 743    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 744    public bool TryGetVoxel(VoxelIndex voxelIndex, out Voxel? result) =>
 820745         TryGetVoxel(voxelIndex.x, voxelIndex.y, voxelIndex.z, out result);
 746
 747    /// <summary>
 748    /// Retrieve <see cref="Voxel"/> from world <see cref="Vector3d"/> points
 749    /// </summary>
 750    /// <returns><see cref="Voxel"/> at the given position or null if the position is not valid.</returns>
 751    public bool TryGetVoxel(Vector3d position, out Voxel? result)
 752    {
 975753        result = null;
 975754        return TryGetVoxelIndex(position, out VoxelIndex coordinate)
 975755            && TryGetVoxel(coordinate.x, coordinate.y, coordinate.z, out result);
 756    }
 757
 758    /// <summary>
 759    /// Retrieves the physical voxel whose center is nearest to the supplied world position.
 760    /// Sparse grids only consider configured physical voxels.
 761    /// </summary>
 762    /// <param name="position">The world position to resolve.</param>
 763    /// <param name="result">The closest physical voxel, if found.</param>
 764    /// <returns>True if a physical voxel was resolved; otherwise false.</returns>
 765    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 766    public bool TryGetClosestVoxel(Vector3d position, out Voxel? result) =>
 14767        TryGetClosestVoxel(position, out result, out _);
 768
 769    internal bool TryGetClosestVoxel(
 770        Vector3d position,
 771        out Voxel? result,
 772        out Fixed64 distanceSquared)
 773    {
 28774        result = null;
 28775        distanceSquared = Fixed64.MaxValue;
 776
 28777        if (!IsActive)
 778        {
 3779            GridForgeLogger.Channel.Warn($"This Grid is not currently allocated.");
 3780            return false;
 781        }
 782
 25783        if (ConfiguredVoxelCount == 0)
 1784            return false;
 785
 24786        VoxelIndex closestIndex = Topology.GetClosestVoxelIndex(BoundsMin, Width, Height, Length, position);
 24787        return _storage!.TryGetClosestVoxel(this, closestIndex, position, out result, out distanceSquared);
 788    }
 789
 790    /// <summary>
 791    /// Retrieves a <see cref="Voxel"/> from a 2D XZ-plane world position on the default world Y layer.
 792    /// </summary>
 793    /// <param name="position">The 2D position whose X component maps to world X and Y component maps to world Z.</param
 794    /// <param name="result">The resolved voxel, if found.</param>
 795    /// <returns>True if the voxel was resolved; otherwise false.</returns>
 796    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 797    public bool TryGetVoxel(Vector2d position, out Voxel? result) =>
 2798        TryGetVoxel(position, default, out result);
 799
 800    /// <summary>
 801    /// Retrieves a <see cref="Voxel"/> from a 2D XZ-plane world position on the supplied world Y layer.
 802    /// </summary>
 803    /// <param name="position">The 2D position whose X component maps to world X and Y component maps to world Z.</param
 804    /// <param name="layerY">The world Y layer to resolve. Defaults to zero when omitted by paired overloads.</param>
 805    /// <param name="result">The resolved voxel, if found.</param>
 806    /// <returns>True if the voxel was resolved; otherwise false.</returns>
 807
 808    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 809    public bool TryGetVoxel(Vector2d position, Fixed64 layerY, out Voxel? result) =>
 6810        TryGetVoxel(GridPlane2d.ToWorld(position, layerY), out result);
 811
 812    /// <summary>
 813    /// Retrieves the physical voxel whose center is nearest to a 2D XZ-plane world position on the default world Y laye
 814    /// Sparse grids only consider configured physical voxels.
 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 closest physical voxel, if found.</param>
 818    /// <returns>True if a physical voxel was resolved; otherwise false.</returns>
 819    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 820    public bool TryGetClosestVoxel(Vector2d position, out Voxel? result) =>
 1821        TryGetClosestVoxel(position, default, out result);
 822
 823    /// <summary>
 824    /// Retrieves the physical voxel whose center is nearest to a 2D XZ-plane world position on the supplied world Y lay
 825    /// Sparse grids only consider configured physical voxels.
 826    /// </summary>
 827    /// <param name="position">The 2D position whose X component maps to world X and Y component maps to world Z.</param
 828    /// <param name="layerY">The world Y layer to resolve. Defaults to zero when omitted by paired overloads.</param>
 829    /// <param name="result">The closest physical voxel, if found.</param>
 830    /// <returns>True if a physical voxel was resolved; otherwise false.</returns>
 831    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 832    public bool TryGetClosestVoxel(Vector2d position, Fixed64 layerY, out Voxel? result) =>
 2833        TryGetClosestVoxel(GridPlane2d.ToWorld(position, layerY), out result);
 834
 835    /// <summary>
 836    /// Computes the scan cell key for a given world position.
 837    /// </summary>
 838    public int GetScanCellKey(Vector3d position)
 839    {
 33840        if (!TryGetVoxelIndex(position, out VoxelIndex voxelIndex))
 1841            return -1;
 842
 32843        return GetScanCellKey(voxelIndex);
 844    }
 845
 846    /// <summary>
 847    /// Calculates the spatial cell index for a given position.
 848    /// </summary>
 849    public int GetScanCellKey(VoxelIndex voxelIndex)
 850    {
 122351851        (int x, int y, int z) = (
 122351852                voxelIndex.x / ScanCellSize,
 122351853                voxelIndex.y / ScanCellSize,
 122351854                voxelIndex.z / ScanCellSize
 122351855            );
 856
 122351857        int scanCellKey = GetScanCellKey(x, y, z);
 122351858        if (scanCellKey == -1)
 859        {
 5860            GridForgeLogger.Channel.Warn($"Position {voxelIndex} is not in the bounds for this grids Scan Cell overlay."
 5861            return -1;
 862        }
 863
 122346864        return scanCellKey;
 865    }
 866
 867    /// <summary>
 868    /// Calculates a unique scan cell key from grid-local scan cell coordinates.
 869    /// </summary>
 870    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 871    internal int GetScanCellKey(int x, int y, int z)
 872    {
 126663873        if ((uint)x >= (uint)_scanWidth
 126663874            || (uint)y >= (uint)_scanHeight
 126663875            || (uint)z >= (uint)_scanLength)
 876        {
 9877            return -1;
 878        }
 879
 126654880        return x + y * _scanWidth + z * _scanLayerSize;
 881    }
 882
 883    /// <summary>
 884    /// Retrieves a scan cell from the grid using its key.
 885    /// </summary>
 886    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 887    public bool TryGetScanCell(int key, out ScanCell? outScanCell)
 888    {
 964889        outScanCell = null;
 964890        return _storage?.TryGetScanCell(key, out outScanCell) == true;
 891    }
 892
 893    /// <summary>
 894    /// Retrieves the scan cell corresponding to a given world position.
 895    /// </summary>
 896    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 897    public bool TryGetScanCell(Vector3d position, out ScanCell? outScanCell)
 898    {
 28899        int key = GetScanCellKey(position);
 28900        return TryGetScanCell(key, out outScanCell);
 901    }
 902
 903    /// <summary>
 904    /// Retrieves the scan cell associated with the given voxel index.
 905    /// </summary>
 906    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 907    public bool TryGetScanCell(VoxelIndex voxelIndex, out ScanCell? outScanCell)
 908    {
 7909        outScanCell = null;
 7910        return TryGetVoxel(voxelIndex, out Voxel? voxel)
 7911            && TryGetScanCell(voxel!.ScanCellKey, out outScanCell);
 912    }
 913
 914    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 915    internal void AddScanCellsInRange(
 916        int xMin,
 917        int yMin,
 918        int zMin,
 919        int xMax,
 920        int yMax,
 921        int zMax,
 922        SwiftList<ScanCell> results,
 923        SwiftHashSet<ScanCell> redundancy) =>
 600924        _storage?.AddScanCellsInRange(
 600925            this,
 600926            xMin,
 600927            yMin,
 600928            zMin,
 600929            xMax,
 600930            yMax,
 600931            zMax,
 600932            results,
 600933            redundancy);
 934
 935    /// <summary>
 936    /// Enumerates all currently active scan cells within the grid.
 937    /// </summary>
 938    public IEnumerable<ScanCell> GetActiveScanCells()
 939    {
 5940        if (!IsActive || !IsOccupied)
 4941            yield break;
 942
 6943        foreach (int activeCellKey in ActiveScanCells!)
 944        {
 2945            if (_storage!.TryGetScanCell(activeCellKey, out ScanCell? scanCell))
 2946                yield return scanCell!;
 947        }
 1948    }
 949
 950    /// <summary>
 951    /// Helper function to ceil snap a <see cref="Vector3d"/> through this grid's topology, ensuring it stays within gri
 952    /// </summary>
 953    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 954    public Vector3d CeilToGrid(Vector3d position) =>
 3955         Topology.CeilToGrid(BoundsMin, BoundsMax, Width, Height, Length, position);
 956
 957    /// <summary>
 958    /// Helper function to floor snap a <see cref="Vector3d"/> through this grid's topology, ensuring it stays within gr
 959    /// </summary>
 960    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 961    public Vector3d FloorToGrid(Vector3d position) =>
 382962        Topology.FloorToGrid(BoundsMin, BoundsMax, Width, Height, Length, position);
 963
 964    /// <summary>
 965    /// Snaps a given position to the topology-local scan cell in the grid.
 966    /// </summary>
 967    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 968    public (int x, int y, int z) SnapToScanCell(Vector3d position) =>
 1185969        Topology.SnapToScanCell(BoundsMin, position, ScanCellSize);
 970
 971    /// <summary>
 972    /// Normalizes world-space bounds to this grid's topology-aligned coverage bounds.
 973    /// </summary>
 974    /// <param name="min">The first world-space bounds corner.</param>
 975    /// <param name="max">The second world-space bounds corner.</param>
 976    /// <param name="padding">Optional non-negative padding applied before normalization.</param>
 977    /// <returns>Topology-aligned minimum and maximum bounds suitable for deterministic coverage scans.</returns>
 978    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 979    public (Vector3d min, Vector3d max) NormalizeBounds(Vector3d min, Vector3d max, Fixed64? padding = null) =>
 948980        Topology.NormalizeBounds(min, max, padding);
 981
 982    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 983    internal Vector3d GetWorldPosition(VoxelIndex index) =>
 122404984        Topology.GetWorldPosition(BoundsMin, index);
 985
 986    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 987    internal Vector3d GetWorldOffset((int x, int y, int z) offset) =>
 92988        Topology.GetWorldOffset(offset);
 989
 990    #endregion
 991}

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,System.Int64,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)
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>)