< 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: 318
Uncovered lines: 0
Coverable lines: 318
Total lines: 1052
Line coverage: 100%
Branch coverage
100%
Covered branches: 196
Total branches: 196
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%88100%
TryRemoveVoxel(...)100%1010100%
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>
 14167962    public Vector3d BoundsMin => Configuration.BoundsMin;
 63
 64    /// <summary>
 65    /// Maximum bounds of the grid in world coordinates.
 66    /// </summary>
 1475767    public Vector3d BoundsMax => Configuration.BoundsMax;
 68
 69    /// <summary>
 70    /// Center position of the grid in world space.
 71    /// </summary>
 51072    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)]
 78101        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)]
 9293110        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>
 103148    public bool IsConjoined => Neighbors != null && NeighborCount > 0;
 149
 150    /// <summary>
 151    /// Size of a scan cell used for spatial partitioning.
 152    /// </summary>
 375051153    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    internal ulong LastChangeSequence { get; set; }
 190
 191    private int _scanWidth;
 192    private int _scanHeight;
 193    private int _scanLength;
 194    private int _scanLayerSize;
 195
 196    private IGridTopology? _topology;
 197    private IVoxelGridStorage? _storage;
 75198    private readonly DenseVoxelGridStorage _denseStorage = new();
 75199    private readonly SparseVoxelGridStorage _sparseStorage = new();
 200
 146959201    internal IGridTopology Topology => _topology!;
 202
 203    internal int ScanWidth
 204    {
 205        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 2078206        get => _scanWidth;
 207    }
 208
 209    internal int ScanHeight
 210    {
 211        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 2379212        get => _scanHeight;
 213    }
 214
 215    internal int ScanLength
 216    {
 217        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 3599218        get => _scanLength;
 219    }
 220
 221    #endregion
 222
 223    #region Initialization & Reset
 224
 225    /// <summary>
 226    /// Initializes the grid with an explicit owning world and configured sparse voxel set.
 227    /// </summary>
 228    /// <param name="world">The world that will own this grid.</param>
 229    /// <param name="gridIndex">The unique index of this grid in the world.</param>
 230    /// <param name="spawnToken">The world-local allocation generation for this grid.</param>
 231    /// <param name="configuration">The normalized configuration settings for the grid.</param>
 232    /// <param name="topology">The validated topology instance for this grid.</param>
 233    /// <param name="configuredVoxels">The validated sparse voxel indices to materialize.</param>
 234    internal void Initialize(
 235        GridWorld world,
 236        ushort gridIndex,
 237        long spawnToken,
 238        GridConfiguration configuration,
 239        IGridTopology topology,
 240        VoxelIndex[] configuredVoxels)
 241    {
 919242        Version = 1;
 243
 919244        World = world;
 919245        GridIndex = gridIndex;
 246
 919247        Configuration = configuration;
 919248        _topology = topology;
 249
 919250        SpawnToken = spawnToken;
 251
 252        // +1 to account for inclusive bounds and to ensure that even the smallest grids (1x1x1) remain valid.
 919253        GridDimensions dimensions = topology.CalculateDimensions(BoundsMin, BoundsMax);
 919254        Width = dimensions.Width;
 919255        Height = dimensions.Height;
 919256        Length = dimensions.Length;
 919257        Size = Width * Height * Length;
 258
 919259        ConfigureScanDimensions();
 919260        if (configuration.StorageKind == GridStorageKind.Sparse)
 261        {
 124262            _sparseStorage.Initialize(this, configuredVoxels);
 124263            _storage = _sparseStorage;
 264        }
 265        else
 266        {
 795267            _denseStorage.Initialize(this);
 795268            _storage = _denseStorage;
 269        }
 270
 919271        IsActive = true;
 919272    }
 273
 274    /// <summary>
 275    /// Resets the grid, clearing all voxels and scan cells.
 276    /// </summary>
 277    internal void Reset()
 278    {
 921279        if (!IsActive)
 2280            return;
 281
 919282        _storage!.Reset(this);
 919283        _storage = null;
 284
 285        // Just in case since voxels should have already cleared any registered obstacles.
 919286        ObstacleCount = 0;
 287
 919288        ReleaseActiveScanCells();
 919289        ReleaseNeighbors();
 290
 919291        Configuration = default;
 919292        World = null;
 919293        _topology = null;
 294
 919295        SpawnToken = 0;
 919296        Version = 0;
 919297        LastChangeSequence = 0;
 298
 919299        GridIndex = ushort.MaxValue;
 300
 919301        ClearDimensions();
 302
 919303        IsActive = false;
 919304    }
 305
 306    private void ReleaseActiveScanCells()
 307    {
 919308        if (ActiveScanCells == null)
 872309            return;
 310
 47311        SwiftHashSetPool<int>.Shared.Release(ActiveScanCells);
 47312        ActiveScanCells = null;
 47313    }
 314
 315    private void ReleaseNeighbors()
 316    {
 919317        if (Neighbors == null)
 820318            return;
 319
 426320        foreach (SwiftHashSet<int> neighbors in Neighbors.Values)
 114321            SwiftHashSetPool<int>.Shared.Release(neighbors);
 322
 99323        Neighbors = null;
 99324        NeighborCount = 0;
 99325    }
 326
 327    private void ClearDimensions()
 328    {
 919329        Width = 0;
 919330        Height = 0;
 919331        Length = 0;
 919332        Size = 0;
 919333        _scanWidth = 0;
 919334        _scanHeight = 0;
 919335        _scanLength = 0;
 919336        _scanLayerSize = 0;
 919337    }
 338
 339    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 340    internal uint IncrementVersion()
 341    {
 1932342        Version = Version == uint.MaxValue ? 1u : Version + 1u;
 1932343        return Version;
 344    }
 345
 346    #endregion
 347
 348    #region Grid Construction
 349
 350    private void ConfigureScanDimensions()
 351    {
 919352        _scanWidth = ((Width - 1) / ScanCellSize) + 1;
 919353        _scanHeight = ((Height - 1) / ScanCellSize) + 1;
 919354        _scanLength = ((Length - 1) / ScanCellSize) + 1;
 919355        _scanLayerSize = _scanWidth * _scanHeight;
 919356    }
 357
 358    #endregion
 359
 360    #region Boundary Management
 361
 362    /// <summary>
 363    /// Determines the rectangular-prism direction from grid <paramref name="a"/> to neighboring grid <paramref name="b"
 364    /// </summary>
 365    /// <param name="a">The source rectangular-prism grid.</param>
 366    /// <param name="b">The neighboring rectangular-prism grid.</param>
 367    /// <returns>The rectangular direction from <paramref name="a"/> to <paramref name="b"/>, or <see cref="RectangularD
 368    public static RectangularDirection GetRectangularNeighborDirection(VoxelGrid a, VoxelGrid b)
 369    {
 8370        return TryGetNeighborSlot(a, b, GridTopologyKind.RectangularPrism, out int slot)
 8371            ? (RectangularDirection)slot
 8372            : RectangularDirection.None;
 373    }
 374
 375    /// <summary>
 376    /// Determines the hex-prism direction from grid <paramref name="a"/> to neighboring grid <paramref name="b"/>.
 377    /// </summary>
 378    /// <param name="a">The source hex-prism grid.</param>
 379    /// <param name="b">The neighboring hex-prism grid.</param>
 380    /// <returns>The hex direction from <paramref name="a"/> to <paramref name="b"/>, or <see cref="HexDirection.None"/>
 381    public static HexDirection GetHexNeighborDirection(VoxelGrid a, VoxelGrid b)
 382    {
 7383        return TryGetNeighborSlot(a, b, GridTopologyKind.HexPrism, out int slot)
 7384            ? (HexDirection)slot
 7385            : HexDirection.None;
 386    }
 387
 388    private static bool TryGetNeighborSlot(VoxelGrid a, VoxelGrid b, GridTopologyKind expectedKind, out int slot)
 389    {
 15390        if (a._topology?.Kind != expectedKind || b._topology?.Kind != expectedKind)
 391        {
 10392            slot = -1;
 10393            return false;
 394        }
 395
 5396        return TryGetNeighborSlot(a, b, out slot);
 397    }
 398
 399    private static bool TryGetNeighborSlot(VoxelGrid a, VoxelGrid b, out int slot)
 400    {
 295401        slot = -1;
 402
 295403        if (a._topology == null
 295404            || b._topology == null
 295405            || a._topology.Kind != b._topology.Kind)
 406        {
 40407            return false;
 408        }
 409
 255410        return a._topology.TryGetNeighborSlotFromWorldDelta(b.BoundsCenter - a.BoundsCenter, out slot)
 255411            && (uint)slot < (uint)a._topology.NeighborSlotCount;
 412    }
 413
 414    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 455415    internal VoxelIndex GetNeighborOffset(int slot) => Topology.GetNeighborOffset(slot);
 416
 417    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 418    internal bool TryGetNeighborSlot(RectangularDirection direction, out int slot)
 419    {
 131420        slot = (int)direction;
 131421        return _topology?.Kind == GridTopologyKind.RectangularPrism
 131422            && (uint)slot < (uint)_topology.NeighborSlotCount;
 423    }
 424
 425    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 426    internal bool TryGetNeighborSlot(HexDirection direction, out int slot)
 427    {
 14428        slot = (int)direction;
 14429        return _topology?.Kind == GridTopologyKind.HexPrism
 14430            && (uint)slot < (uint)_topology.NeighborSlotCount;
 431    }
 432
 433    /// <summary>
 434    /// Adds a neighboring grid and updates relationships.
 435    /// </summary>
 436    /// <param name="neighborGrid">The neighboring grid to add.</param>
 437    internal bool TryAddGridNeighbor(VoxelGrid neighborGrid)
 438    {
 264439        if (!TryGetNeighborSlot(this, neighborGrid, out int neighborSlot))
 85440            return false;
 441
 442        // Ensure the neighbor array is allocated and store the new neighbor
 179443        Neighbors ??= new SwiftSparseMap<SwiftHashSet<int>>();
 179444        if (!Neighbors.TryGetValue(neighborSlot, out SwiftHashSet<int> neighborSet))
 445        {
 128446            neighborSet = SwiftHashSetPool<int>.Shared.Rent();
 128447            Neighbors.Add(neighborSlot, neighborSet);
 448        }
 449
 179450        if (!neighborSet.Add(neighborGrid.GridIndex))
 1451            return false;
 452
 178453        NeighborCount++;
 178454        IncrementVersion();
 455
 178456        return true;
 457    }
 458
 459    /// <summary>
 460    /// Removes a neighboring grid relationship.
 461    /// </summary>
 462    /// <param name="neighborGrid">The neighboring grid to remove.</param>
 463    internal bool TryRemoveGridNeighbor(VoxelGrid neighborGrid)
 464    {
 25465        if (!TryGetGridNeighborSet(neighborGrid, out int neighborSlot, out SwiftHashSet<int>? neighborSet))
 2466            return false;
 467
 23468        if (!neighborSet!.Remove(neighborGrid.GridIndex))
 1469            return false;
 470
 22471        ReleaseNeighborSetIfEmpty(neighborSlot, neighborSet);
 472
 22473        if (--NeighborCount == 0)
 11474            Neighbors = null;
 475
 22476        IncrementVersion();
 477
 22478        return true;
 479    }
 480
 481    private bool TryGetGridNeighborSet(
 482        VoxelGrid neighborGrid,
 483        out int neighborSlot,
 484        out SwiftHashSet<int>? neighborSet)
 485    {
 25486        neighborSet = null;
 25487        neighborSlot = -1;
 488
 25489        if (!IsConjoined)
 1490            return false;
 491
 24492        return TryGetNeighborSlot(this, neighborGrid, out neighborSlot)
 24493            && Neighbors!.TryGetValue(neighborSlot, out neighborSet);
 494    }
 495
 496    private void ReleaseNeighborSetIfEmpty(int neighborIndex, SwiftHashSet<int> neighborSet)
 497    {
 22498        if (neighborSet.Count > 0)
 8499            return;
 500
 14501        GridForgeLogger.Channel.Info($"Releasing unused neighbor collection.");
 14502        SwiftHashSetPool<int>.Shared.Release(neighborSet);
 14503        Neighbors!.Remove(neighborIndex);
 14504    }
 505
 506    #endregion
 507
 508    #region Grid Queries
 509
 510    /// <summary>
 511    /// Determines if a voxel coordinate is at the boundary of the grid.
 512    /// Used to determine if a voxel should update when a neighboring grid is added/removed.
 513    /// </summary>
 514    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 515    public bool IsOnBoundary(VoxelIndex coord) =>
 123494516         coord.x == 0 || coord.x == Width - 1
 123494517      || coord.y == 0 || coord.y == Height - 1
 123494518      || coord.z == 0 || coord.z == Length - 1;
 519
 520    /// <summary>
 521    /// Checks whether a given position falls within the grid bounds.
 522    /// </summary>
 523    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 524    public bool IsInBounds(Vector3d target) =>
 89525        IsActive && Topology.IsInBounds(BoundsMin, BoundsMax, Width, Height, Length, target);
 526
 527    /// <summary>
 528    /// Retrieves all neighboring grids connected to this grid.
 529    /// </summary>
 530    /// <returns>An enumeration of all neighboring grids.</returns>
 531    public IEnumerable<VoxelGrid> GetAllGridNeighbors()
 532    {
 13533        if (!IsConjoined)
 5534            yield break;
 535
 8536        var values = Neighbors!.DenseValues;
 8537        int count = Neighbors.Count;
 538
 38539        for (int i = 0; i < count; i++)
 540        {
 11541            SwiftHashSet<int> neighborSet = values[i];
 44542            foreach (int neighborIndex in neighborSet)
 543            {
 11544                if (World!.TryGetGrid(neighborIndex, out VoxelGrid? neighborGrid))
 545                {
 11546                    yield return neighborGrid!;
 547                }
 548            }
 549        }
 8550    }
 551
 552    /// <summary>
 553    /// Determines whether the given voxel coordinates are within the valid range of the grid.
 554    /// </summary>
 555    public bool IsValidVoxelIndex(int x, int y, int z)
 556    {
 3009557        if (!IsActive)
 558        {
 6559            GridForgeLogger.Channel.Warn($"This Grid is not currently active.");
 6560            return false;
 561        }
 562
 3003563        bool result = IsVoxelIndexInBounds(x, y, z);
 564
 3003565        if (!result)
 260566            GridForgeLogger.Channel.Info($"The coordinate {(x, y, z)} is not valid for this grid.");
 567
 3003568        return result;
 569    }
 570
 571    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 572    private bool IsVoxelIndexInBounds(int x, int y, int z) =>
 3003573         (uint)x < (uint)Width
 3003574      && (uint)y < (uint)Height
 3003575      && (uint)z < (uint)Length;
 576
 577    /// <summary>
 578    /// Determines if a topology-local voxel index is facing the rectangular-prism boundary in the supplied direction.
 579    /// </summary>
 580    public bool IsFacingBoundary(VoxelIndex voxelIndex, RectangularDirection direction) =>
 56581        TryGetNeighborSlot(direction, out int slot)
 56582        && _topology!.IsFacingBoundary(voxelIndex, slot, Width, Height, Length);
 583
 584    /// <summary>
 585    /// Determines if a topology-local voxel index is facing the hex-prism boundary in the supplied direction.
 586    /// </summary>
 587    public bool IsFacingBoundary(VoxelIndex voxelIndex, HexDirection direction) =>
 5588        TryGetNeighborSlot(direction, out int slot)
 5589        && _topology!.IsFacingBoundary(voxelIndex, slot, Width, Height, Length);
 590
 591    /// <summary>
 592    /// Converts a world position to a topology-local voxel index within the grid.
 593    /// Rectangular-prism grids return X/Y/Z coordinates; hex-prism grids return axial Q, layer, and axial R in X/Y/Z fi
 594    /// </summary>
 595    public bool TryGetVoxelIndex(Vector3d position, out VoxelIndex result)
 596    {
 2855597        result = default;
 598
 2855599        if (!IsActive)
 600        {
 3601            GridForgeLogger.Channel.Warn($"This Grid is not currently allocated.");
 3602            return false;
 603        }
 604
 2852605        if (!Topology.TryGetVoxelIndex(BoundsMin, BoundsMax, Width, Height, Length, position, out VoxelIndex voxelIndex)
 606        {
 18607            GridForgeLogger.Channel.Warn($"Position does not fall in the bounds of this grid");
 18608            return false;
 609        }
 610
 2834611        result = voxelIndex;
 2834612        return true;
 613    }
 614
 615    /// <summary>
 616    /// Converts a 2D XZ-plane world position on the default world Y layer to a voxel index within the grid.
 617    /// </summary>
 618    /// <param name="position">The 2D position whose X component maps to world X and Y component maps to world Z.</param
 619    /// <param name="result">The resolved voxel index, if found.</param>
 620    /// <returns>True if the position resolved to an allocated voxel index; otherwise false.</returns>
 621    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 622    public bool TryGetVoxelIndex(Vector2d position, out VoxelIndex result) =>
 1623        TryGetVoxelIndex(position, default, out result);
 624
 625    /// <summary>
 626    /// Converts a 2D XZ-plane world position on the supplied world Y layer to a voxel index within the grid.
 627    /// </summary>
 628    /// <param name="position">The 2D position whose X component maps to world X and Y component maps to world Z.</param
 629    /// <param name="layerY">The world Y layer to resolve. Defaults to zero when omitted by paired overloads.</param>
 630    /// <param name="result">The resolved voxel index, if found.</param>
 631    /// <returns>True if the position resolved to an allocated voxel index; otherwise false.</returns>
 632    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 633    public bool TryGetVoxelIndex(Vector2d position, Fixed64 layerY, out VoxelIndex result) =>
 5634        TryGetVoxelIndex(GridPlane2d.ToWorld(position, layerY), out result);
 635
 636    /// <summary>
 637    /// Checks if a voxel at the given topology-local coordinates is allocated within the grid.
 638    /// </summary>
 639    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 640    public bool IsVoxelAllocated(int x, int y, int z) =>
 69641        IsValidVoxelIndex(x, y, z) && _storage!.TryGetVoxel(x, y, z, out _);
 642
 643    /// <summary>
 644    /// Checks whether a physical voxel is configured at the supplied grid-local index.
 645    /// </summary>
 646    /// <param name="voxelIndex">The grid-local voxel index to test.</param>
 647    /// <returns>True when the index resolves to a configured voxel; otherwise false.</returns>
 648    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 649    public bool ContainsVoxel(VoxelIndex voxelIndex) =>
 61650        IsVoxelAllocated(voxelIndex.x, voxelIndex.y, voxelIndex.z);
 651
 652    /// <summary>
 653    /// Configures a sparse voxel at runtime. Dense grids, invalid indices, and already-configured
 654    /// sparse voxels return false.
 655    /// </summary>
 656    /// <param name="voxelIndex">The grid-local voxel index to configure.</param>
 657    /// <param name="voxel">The configured voxel when the operation succeeds.</param>
 658    /// <returns>True when a new sparse voxel was configured; otherwise false.</returns>
 659    public bool TryAddVoxel(VoxelIndex voxelIndex, out Voxel? voxel)
 660    {
 41661        voxel = null;
 662        bool drainCommittedChanges;
 41663        GridWorld? world = World;
 41664        if (world == null)
 1665            return false;
 666
 40667        world.EnterReadLock();
 668        try
 669        {
 40670            lock (world.ChangeSyncRoot)
 671            {
 40672                if (!CanMutateSparseVoxel(voxelIndex)
 40673                    || !_sparseStorage.TryAddVoxel(this, voxelIndex, out voxel))
 674                {
 2675                    return false;
 676                }
 677
 38678                uint gridVersion = IncrementVersion();
 38679                voxel!.CachedGridVersion = gridVersion;
 38680                GridEventInfo eventInfo = world.CreateGridEventInfo(
 38681                    this,
 38682                    GridEventKind.SparseVoxelAdded,
 38683                    voxelIndex,
 38684                    voxel.WorldPosition,
 38685                    voxel.WorldPosition,
 38686                    world.AllocateChangeStamp(),
 38687                    hasVoxelState: true,
 38688                    isVoxelPresent: true,
 38689                    obstacleCount: 0);
 38690                drainCommittedChanges = world.EnqueueCommittedChange(new GridCommittedChange(eventInfo));
 38691            }
 692        }
 693        finally
 694        {
 40695            world.ExitReadLock();
 40696        }
 697
 38698        if (drainCommittedChanges)
 37699            world.DrainCommittedChanges();
 38700        return true;
 2701    }
 702
 703    /// <summary>
 704    /// Removes a configured sparse voxel at runtime when it has no unsafe runtime state.
 705    /// Dense grids, missing voxels, occupied voxels, voxels with obstacle tokens, partitioned voxels,
 706    /// and voxels with active event subscribers return false.
 707    /// </summary>
 708    /// <param name="voxelIndex">The grid-local voxel index to remove.</param>
 709    /// <returns>True when the sparse voxel was removed; otherwise false.</returns>
 710    public bool TryRemoveVoxel(VoxelIndex voxelIndex)
 711    {
 712        bool drainCommittedChanges;
 23713        GridWorld? world = World;
 23714        if (world == null)
 1715            return false;
 716
 22717        world.EnterReadLock();
 718        try
 719        {
 22720            lock (world.ChangeSyncRoot)
 721            {
 22722                if (!CanMutateSparseVoxel(voxelIndex)
 22723                    || !TryGetVoxel(voxelIndex, out Voxel? voxel)
 22724                    || !CanRemoveSparseVoxel(voxel!))
 725                {
 8726                    return false;
 727                }
 728
 14729                Vector3d affectedPosition = voxel!.WorldPosition;
 14730                _sparseStorage.TryRemoveVoxel(this, voxelIndex, out _);
 731
 14732                IncrementVersion();
 14733                GridEventInfo eventInfo = world.CreateGridEventInfo(
 14734                    this,
 14735                    GridEventKind.SparseVoxelRemoved,
 14736                    voxelIndex,
 14737                    affectedPosition,
 14738                    affectedPosition,
 14739                    world.AllocateChangeStamp(),
 14740                    hasVoxelState: true,
 14741                    isVoxelPresent: false,
 14742                    obstacleCount: 0);
 14743                drainCommittedChanges = world.EnqueueCommittedChange(new GridCommittedChange(eventInfo));
 14744            }
 745        }
 746        finally
 747        {
 22748            world.ExitReadLock();
 22749        }
 750
 14751        if (drainCommittedChanges)
 13752            world.DrainCommittedChanges();
 14753        return true;
 8754    }
 755
 756    private bool CanMutateSparseVoxel(VoxelIndex voxelIndex) =>
 62757        IsActive
 62758        && StorageKind == GridStorageKind.Sparse
 62759        && IsValidVoxelIndex(voxelIndex.x, voxelIndex.y, voxelIndex.z);
 760
 761    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 762    private static bool CanRemoveSparseVoxel(Voxel voxel) =>
 20763        voxel.IsAllocated
 20764        && !voxel.IsOccupied
 20765        && voxel.ObstacleCount == 0
 20766        && !voxel.IsPartioned
 20767        && !voxel.HasEventSubscribers;
 768
 769    /// <summary>
 770    /// Retrieves the <see cref="Voxel"/> at the specified topology-local coordinates, if allocated.
 771    /// </summary>
 772    public bool TryGetVoxel(int x, int y, int z, out Voxel? result)
 773    {
 2864774        result = null;
 775
 2864776        if (!IsValidVoxelIndex(x, y, z))
 258777            return false;
 778
 2606779        return _storage!.TryGetVoxel(x, y, z, out result);
 780    }
 781
 782    /// <summary>
 783    /// Enumerates physical voxels configured in this grid in deterministic storage order.
 784    /// </summary>
 785    public IEnumerable<Voxel> EnumerateVoxels() =>
 11786        _storage?.EnumerateVoxels() ?? Array.Empty<Voxel>();
 787
 788    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 789    internal void VisitVoxels<TVisitor>(ref TVisitor visitor)
 790        where TVisitor : struct, IVoxelStorageVisitor =>
 91791        _storage?.VisitVoxels(ref visitor);
 792
 793    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 794    internal void AddVoxelsInIndexRange(
 795        VoxelIndex min,
 796        VoxelIndex max,
 797        SwiftList<Voxel> results,
 798        SwiftHashSet<Voxel> redundancy) =>
 549799        _storage?.AddVoxelsInIndexRange(min, max, results, redundancy);
 800
 801    /// <summary>
 802    /// Retrieves a grid voxel from a topology-local coordinate.
 803    /// </summary>
 804    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 805    public bool TryGetVoxel(VoxelIndex voxelIndex, out Voxel? result) =>
 1867806         TryGetVoxel(voxelIndex.x, voxelIndex.y, voxelIndex.z, out result);
 807
 808    /// <summary>
 809    /// Retrieve <see cref="Voxel"/> from world <see cref="Vector3d"/> points
 810    /// </summary>
 811    /// <returns><see cref="Voxel"/> at the given position or null if the position is not valid.</returns>
 812    public bool TryGetVoxel(Vector3d position, out Voxel? result)
 813    {
 979814        result = null;
 979815        return TryGetVoxelIndex(position, out VoxelIndex coordinate)
 979816            && TryGetVoxel(coordinate.x, coordinate.y, coordinate.z, out result);
 817    }
 818
 819    /// <summary>
 820    /// Retrieves the physical voxel whose center is nearest to the supplied world position.
 821    /// Sparse grids only consider configured physical voxels.
 822    /// </summary>
 823    /// <param name="position">The world position to resolve.</param>
 824    /// <param name="result">The closest physical voxel, if found.</param>
 825    /// <returns>True if a physical voxel was resolved; otherwise false.</returns>
 826    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 827    public bool TryGetClosestVoxel(Vector3d position, out Voxel? result) =>
 14828        TryGetClosestVoxel(position, out result, out _);
 829
 830    internal bool TryGetClosestVoxel(
 831        Vector3d position,
 832        out Voxel? result,
 833        out Fixed64 distanceSquared)
 834    {
 28835        result = null;
 28836        distanceSquared = Fixed64.MaxValue;
 837
 28838        if (!IsActive)
 839        {
 3840            GridForgeLogger.Channel.Warn($"This Grid is not currently allocated.");
 3841            return false;
 842        }
 843
 25844        if (ConfiguredVoxelCount == 0)
 1845            return false;
 846
 24847        VoxelIndex closestIndex = Topology.GetClosestVoxelIndex(BoundsMin, Width, Height, Length, position);
 24848        return _storage!.TryGetClosestVoxel(this, closestIndex, position, out result, out distanceSquared);
 849    }
 850
 851    /// <summary>
 852    /// Retrieves a <see cref="Voxel"/> from a 2D XZ-plane world position on the default world Y layer.
 853    /// </summary>
 854    /// <param name="position">The 2D position whose X component maps to world X and Y component maps to world Z.</param
 855    /// <param name="result">The resolved voxel, if found.</param>
 856    /// <returns>True if the voxel was resolved; otherwise false.</returns>
 857    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 858    public bool TryGetVoxel(Vector2d position, out Voxel? result) =>
 2859        TryGetVoxel(position, default, out result);
 860
 861    /// <summary>
 862    /// Retrieves a <see cref="Voxel"/> from a 2D XZ-plane world position on the supplied world Y layer.
 863    /// </summary>
 864    /// <param name="position">The 2D position whose X component maps to world X and Y component maps to world Z.</param
 865    /// <param name="layerY">The world Y layer to resolve. Defaults to zero when omitted by paired overloads.</param>
 866    /// <param name="result">The resolved voxel, if found.</param>
 867    /// <returns>True if the voxel was resolved; otherwise false.</returns>
 868
 869    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 870    public bool TryGetVoxel(Vector2d position, Fixed64 layerY, out Voxel? result) =>
 6871        TryGetVoxel(GridPlane2d.ToWorld(position, layerY), out result);
 872
 873    /// <summary>
 874    /// Retrieves the physical voxel whose center is nearest to a 2D XZ-plane world position on the default world Y laye
 875    /// Sparse grids only consider configured physical voxels.
 876    /// </summary>
 877    /// <param name="position">The 2D position whose X component maps to world X and Y component maps to world Z.</param
 878    /// <param name="result">The closest physical voxel, if found.</param>
 879    /// <returns>True if a physical voxel was resolved; otherwise false.</returns>
 880    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 881    public bool TryGetClosestVoxel(Vector2d position, out Voxel? result) =>
 1882        TryGetClosestVoxel(position, default, out result);
 883
 884    /// <summary>
 885    /// Retrieves the physical voxel whose center is nearest to a 2D XZ-plane world position on the supplied world Y lay
 886    /// Sparse grids only consider configured physical voxels.
 887    /// </summary>
 888    /// <param name="position">The 2D position whose X component maps to world X and Y component maps to world Z.</param
 889    /// <param name="layerY">The world Y layer to resolve. Defaults to zero when omitted by paired overloads.</param>
 890    /// <param name="result">The closest physical voxel, if found.</param>
 891    /// <returns>True if a physical voxel was resolved; otherwise false.</returns>
 892    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 893    public bool TryGetClosestVoxel(Vector2d position, Fixed64 layerY, out Voxel? result) =>
 2894        TryGetClosestVoxel(GridPlane2d.ToWorld(position, layerY), out result);
 895
 896    /// <summary>
 897    /// Computes the scan cell key for a given world position.
 898    /// </summary>
 899    public int GetScanCellKey(Vector3d position)
 900    {
 33901        if (!TryGetVoxelIndex(position, out VoxelIndex voxelIndex))
 1902            return -1;
 903
 32904        return GetScanCellKey(voxelIndex);
 905    }
 906
 907    /// <summary>
 908    /// Calculates the spatial cell index for a given position.
 909    /// </summary>
 910    public int GetScanCellKey(VoxelIndex voxelIndex)
 911    {
 123649912        (int x, int y, int z) = (
 123649913                voxelIndex.x / ScanCellSize,
 123649914                voxelIndex.y / ScanCellSize,
 123649915                voxelIndex.z / ScanCellSize
 123649916            );
 917
 123649918        int scanCellKey = GetScanCellKey(x, y, z);
 123649919        if (scanCellKey == -1)
 920        {
 5921            GridForgeLogger.Channel.Warn($"Position {voxelIndex} is not in the bounds for this grids Scan Cell overlay."
 5922            return -1;
 923        }
 924
 123644925        return scanCellKey;
 926    }
 927
 928    /// <summary>
 929    /// Calculates a unique scan cell key from grid-local scan cell coordinates.
 930    /// </summary>
 931    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 932    internal int GetScanCellKey(int x, int y, int z)
 933    {
 128305934        if ((uint)x >= (uint)_scanWidth
 128305935            || (uint)y >= (uint)_scanHeight
 128305936            || (uint)z >= (uint)_scanLength)
 937        {
 9938            return -1;
 939        }
 940
 128296941        return x + y * _scanWidth + z * _scanLayerSize;
 942    }
 943
 944    /// <summary>
 945    /// Retrieves a scan cell from the grid using its key.
 946    /// </summary>
 947    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 948    public bool TryGetScanCell(int key, out ScanCell? outScanCell)
 949    {
 964950        outScanCell = null;
 964951        return _storage?.TryGetScanCell(key, out outScanCell) == true;
 952    }
 953
 954    /// <summary>
 955    /// Retrieves the scan cell corresponding to a given world position.
 956    /// </summary>
 957    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 958    public bool TryGetScanCell(Vector3d position, out ScanCell? outScanCell)
 959    {
 28960        int key = GetScanCellKey(position);
 28961        return TryGetScanCell(key, out outScanCell);
 962    }
 963
 964    /// <summary>
 965    /// Retrieves the scan cell associated with the given voxel index.
 966    /// </summary>
 967    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 968    public bool TryGetScanCell(VoxelIndex voxelIndex, out ScanCell? outScanCell)
 969    {
 7970        outScanCell = null;
 7971        return TryGetVoxel(voxelIndex, out Voxel? voxel)
 7972            && TryGetScanCell(voxel!.ScanCellKey, out outScanCell);
 973    }
 974
 975    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 976    internal void AddScanCellsInRange(
 977        int xMin,
 978        int yMin,
 979        int zMin,
 980        int xMax,
 981        int yMax,
 982        int zMax,
 983        SwiftList<ScanCell> results,
 984        SwiftHashSet<ScanCell> redundancy) =>
 600985        _storage?.AddScanCellsInRange(
 600986            this,
 600987            xMin,
 600988            yMin,
 600989            zMin,
 600990            xMax,
 600991            yMax,
 600992            zMax,
 600993            results,
 600994            redundancy);
 995
 996    /// <summary>
 997    /// Enumerates all currently active scan cells within the grid.
 998    /// </summary>
 999    public IEnumerable<ScanCell> GetActiveScanCells()
 1000    {
 51001        if (!IsActive || !IsOccupied)
 41002            yield break;
 1003
 61004        foreach (int activeCellKey in ActiveScanCells!)
 1005        {
 21006            if (_storage!.TryGetScanCell(activeCellKey, out ScanCell? scanCell))
 21007                yield return scanCell!;
 1008        }
 11009    }
 1010
 1011    /// <summary>
 1012    /// Helper function to ceil snap a <see cref="Vector3d"/> through this grid's topology, ensuring it stays within gri
 1013    /// </summary>
 1014    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 1015    public Vector3d CeilToGrid(Vector3d position) =>
 31016         Topology.CeilToGrid(BoundsMin, BoundsMax, Width, Height, Length, position);
 1017
 1018    /// <summary>
 1019    /// Helper function to floor snap a <see cref="Vector3d"/> through this grid's topology, ensuring it stays within gr
 1020    /// </summary>
 1021    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 1022    public Vector3d FloorToGrid(Vector3d position) =>
 3821023        Topology.FloorToGrid(BoundsMin, BoundsMax, Width, Height, Length, position);
 1024
 1025    /// <summary>
 1026    /// Snaps a given position to the topology-local scan cell in the grid.
 1027    /// </summary>
 1028    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 1029    public (int x, int y, int z) SnapToScanCell(Vector3d position) =>
 11851030        Topology.SnapToScanCell(BoundsMin, position, ScanCellSize);
 1031
 1032    /// <summary>
 1033    /// Normalizes world-space bounds to this grid's topology-aligned coverage bounds.
 1034    /// </summary>
 1035    /// <param name="min">The first world-space bounds corner.</param>
 1036    /// <param name="max">The second world-space bounds corner.</param>
 1037    /// <param name="padding">Optional non-negative padding applied before normalization.</param>
 1038    /// <returns>Topology-aligned minimum and maximum bounds suitable for deterministic coverage scans.</returns>
 1039    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 1040    public (Vector3d min, Vector3d max) NormalizeBounds(Vector3d min, Vector3d max, Fixed64? padding = null) =>
 14461041        Topology.NormalizeBounds(min, max, padding);
 1042
 1043    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 1044    internal Vector3d GetWorldPosition(VoxelIndex index) =>
 1245061045        Topology.GetWorldPosition(BoundsMin, index);
 1046
 1047    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 1048    internal Vector3d GetWorldOffset((int x, int y, int z) offset) =>
 921049        Topology.GetWorldOffset(offset);
 1050
 1051    #endregion
 1052}

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>)