< Summary

Information
Class: GridForge.Utility.GridTraversalState
Assembly: GridForge
File(s): /home/runner/work/GridForge/GridForge/src/GridForge/Utility/GridTraversal.cs
Line coverage
100%
Covered lines: 47
Uncovered lines: 0
Coverable lines: 47
Total lines: 195
Line coverage: 100%
Branch coverage
100%
Covered branches: 30
Total branches: 30
Branch coverage: 100%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%11100%
TryVisitUnique(...)100%44100%
GetCellEdge(...)100%11100%
GetCellEdge(...)100%88100%
TryResolveGrid(...)100%1818100%

File(s)

/home/runner/work/GridForge/GridForge/src/GridForge/Utility/GridTraversal.cs

#LineLine coverage
 1//=======================================================================
 2// GridTraversal.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.Runtime.CompilerServices;
 10using FixedMathSharp;
 11using GridForge.Grids;
 12using GridForge.Grids.Topology;
 13using GridForge.Spatial;
 14using SwiftCollections;
 15
 16namespace GridForge.Utility;
 17
 18/// <summary>
 19/// Selects which topology edge measurement a grid traversal should use for padding.
 20/// </summary>
 21public enum GridTraversalPaddingMode
 22{
 23    /// <summary>
 24    /// Use the largest three-dimensional cell edge.
 25    /// </summary>
 26    MaxCellEdge,
 27
 28    /// <summary>
 29    /// Use the largest X/Z-plane cell edge.
 30    /// </summary>
 31    PlanarMaxCellEdge
 32}
 33
 34/// <summary>
 35/// Tracks per-grid traversal padding while suppressing duplicate voxel visits.
 36/// </summary>
 37public struct GridTraversalState
 38{
 39    private readonly GridWorld _world;
 40    private readonly GridTraversalPaddingMode _paddingMode;
 41    private ushort _currentGridIndex;
 42    private long _currentGridSpawnToken;
 43    private VoxelGrid? _currentGrid;
 44    private Fixed64 _cellEdge;
 45    private bool _hasCachedGrid;
 46
 47    /// <summary>
 48    /// Initializes traversal state for one world and padding mode.
 49    /// </summary>
 50    public GridTraversalState(GridWorld world, GridTraversalPaddingMode paddingMode)
 51    {
 104552        _world = world;
 104553        _paddingMode = paddingMode;
 104554        _currentGridIndex = 0;
 104555        _currentGridSpawnToken = 0;
 104556        _currentGrid = null;
 104557        _cellEdge = Fixed64.Zero;
 104558        _hasCachedGrid = false;
 104559    }
 60
 61    /// <summary>
 62    /// Visits a voxel only once and returns the selected cell-edge measurement for its grid.
 63    /// </summary>
 64    /// <returns>True when the voxel belongs to an active grid generation and was not already visited; otherwise false.<
 65    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 66    public bool TryVisitUnique(Voxel voxel, SwiftHashSet<WorldVoxelIndex> visited, out Fixed64 cellEdge)
 67    {
 208968        cellEdge = Fixed64.Zero;
 208969        WorldVoxelIndex voxelIndex = voxel.WorldIndex;
 208970        if (!visited.Add(voxelIndex))
 104271            return false;
 72
 104773        if (!TryResolveGrid(voxelIndex, out VoxelGrid? grid))
 74        {
 175            visited.Remove(voxelIndex);
 176            return false;
 77        }
 78
 104679        cellEdge = GetCellEdge(grid!);
 104680        return true;
 81    }
 82
 83    /// <summary>
 84    /// Gets the selected cell-edge measurement for a voxel's grid, caching repeated grid lookups.
 85    /// </summary>
 86    /// <exception cref="InvalidOperationException">The voxel does not belong to an active grid generation in this trave
 87    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 88    public Fixed64 GetCellEdge(Voxel voxel)
 89    {
 290        bool isCurrent = TryResolveGrid(voxel.WorldIndex, out VoxelGrid? grid);
 291        SwiftThrowHelper.ThrowIfTrue(
 292            !isCurrent,
 293            nameof(voxel),
 294            "The voxel does not belong to an active grid generation in this traversal's world.");
 95
 196        return GetCellEdge(grid!);
 97    }
 98
 99    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 100    private Fixed64 GetCellEdge(VoxelGrid grid)
 101    {
 1047102        if (_hasCachedGrid
 1047103            && grid.GridIndex == _currentGridIndex
 1047104            && grid.SpawnToken == _currentGridSpawnToken)
 105        {
 1106            return _cellEdge;
 107        }
 108
 1046109        _currentGridIndex = grid.GridIndex;
 1046110        _currentGridSpawnToken = grid.SpawnToken;
 1046111        _currentGrid = grid;
 1046112        _hasCachedGrid = true;
 1046113        _cellEdge = _paddingMode == GridTraversalPaddingMode.PlanarMaxCellEdge
 1046114            ? GridTopologyMetricUtility.GetPlanarMaxCellEdge(grid)
 1046115            : GridTopologyMetricUtility.GetMaxCellEdge(grid);
 1046116        return _cellEdge;
 117    }
 118
 119    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 120    private bool TryResolveGrid(WorldVoxelIndex voxelIndex, out VoxelGrid? grid)
 121    {
 1049122        grid = _currentGrid;
 1049123        if (_hasCachedGrid
 1049124            && voxelIndex.WorldSpawnToken == _world.SpawnToken
 1049125            && voxelIndex.GridIndex == _currentGridIndex
 1049126            && voxelIndex.GridSpawnToken == _currentGridSpawnToken
 1049127            && grid != null
 1049128            && grid.IsActive
 1049129            && ReferenceEquals(grid.World, _world)
 1049130            && grid.GridIndex == _currentGridIndex
 1049131            && grid.SpawnToken == _currentGridSpawnToken)
 132        {
 1133            return true;
 134        }
 135
 1048136        return _world.TryGetGrid(voxelIndex, out grid);
 137    }
 138}
 139
 140/// <summary>
 141/// Provides deterministic helpers for duplicate-safe voxel traversal.
 142/// </summary>
 143public static class GridTraversal
 144{
 145    /// <summary>
 146    /// Gets a voxel partition once per exact world-scoped voxel identity.
 147    /// </summary>
 148    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 149    public static bool TryGetUniquePartition<TPartition>(
 150        Voxel voxel,
 151        SwiftHashSet<WorldVoxelIndex> visited,
 152        out TPartition? partition)
 153        where TPartition : class, IVoxelPartition
 154    {
 155        partition = null;
 156        return visited.Add(voxel.WorldIndex)
 157            && voxel.TryGetPartition(out partition);
 158    }
 159
 160    /// <summary>
 161    /// Tests whether a 3D world position lies inside bounds expanded by half of a cell edge.
 162    /// </summary>
 163    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 164    public static bool IsWorldPositionInPaddedBounds(
 165        Vector3d min,
 166        Vector3d max,
 167        Fixed64 cellEdge,
 168        Vector3d worldPosition)
 169    {
 170        Fixed64 padding = cellEdge * Fixed64.Half;
 171        return worldPosition.X >= min.X - padding
 172            && worldPosition.X <= max.X + padding
 173            && worldPosition.Y >= min.Y - padding
 174            && worldPosition.Y <= max.Y + padding
 175            && worldPosition.Z >= min.Z - padding
 176            && worldPosition.Z <= max.Z + padding;
 177    }
 178
 179    /// <summary>
 180    /// Tests whether a world position's X/Z projection lies inside bounds expanded by half of a cell edge.
 181    /// </summary>
 182    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 183    public static bool IsPlanarPositionInPaddedBounds(
 184        Vector2d min,
 185        Vector2d max,
 186        Fixed64 cellEdge,
 187        Vector3d worldPosition)
 188    {
 189        Fixed64 padding = cellEdge * Fixed64.Half;
 190        return worldPosition.X >= min.X - padding
 191            && worldPosition.X <= max.X + padding
 192            && worldPosition.Z >= min.Y - padding
 193            && worldPosition.Z <= max.Y + padding;
 194    }
 195}