< Summary

Information
Class: GridForge.Grids.GridSpatialIndex
Assembly: GridForge
File(s): /home/runner/work/GridForge/GridForge/src/GridForge/Grids/Managers/GridSpatialIndex.cs
Line coverage
100%
Covered lines: 77
Uncovered lines: 0
Coverable lines: 77
Total lines: 171
Line coverage: 100%
Branch coverage
100%
Covered branches: 38
Total branches: 38
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%
.ctor(...)100%11100%
get_Count()100%11100%
get_OrdinaryCount()100%11100%
get_OversizedCount()100%11100%
Insert(...)100%66100%
Remove(...)100%22100%
Clear()100%11100%
CollectCandidates(...)100%1414100%
CollectPointCandidates(...)100%66100%
FitsHashCellBudget(...)100%66100%
GetCellRange(...)100%11100%
ShouldScanActiveGrids(...)100%44100%
GetCellCount(...)100%11100%

File(s)

/home/runner/work/GridForge/GridForge/src/GridForge/Grids/Managers/GridSpatialIndex.cs

#LineLine coverage
 1//=======================================================================
 2// GridSpatialIndex.cs
 3//=======================================================================
 4// MIT License, Copyright (c) 2024–present David Oravsky (mrdav30)
 5// See LICENSE file in the project root for full license information.
 6//=======================================================================
 7
 8using FixedMathSharp;
 9using SwiftCollections;
 10using SwiftCollections.Query;
 11
 12namespace GridForge.Grids;
 13
 14/// <summary>
 15/// Owns deterministic top-level grid spatial classification and lookup.
 16/// </summary>
 17internal sealed class GridSpatialIndex
 18{
 19    private const int InitialCapacity = 16;
 20    internal const ulong DefaultHashCellBudget = 64UL;
 21
 22    private readonly ulong _cellBudget;
 23    private readonly SwiftFixedSpatialHash<ushort> _ordinaryGrids;
 24    private readonly SwiftFixedBVH<ushort> _oversizedGrids;
 25    private readonly SwiftHashSet<ushort> _oversizedSlots;
 26
 27    internal GridSpatialIndex(int cellSize)
 55028        : this(cellSize, DefaultHashCellBudget)
 29    {
 55030    }
 31
 56832    internal GridSpatialIndex(int cellSize, ulong cellBudget)
 33    {
 56834        _cellBudget = cellBudget;
 56835        _ordinaryGrids = new SwiftFixedSpatialHash<ushort>(InitialCapacity, (Fixed64)cellSize);
 56836        _oversizedGrids = new SwiftFixedBVH<ushort>(InitialCapacity);
 56837        _oversizedSlots = new SwiftHashSet<ushort>();
 56838    }
 39
 540    internal int Count => OrdinaryCount + OversizedCount;
 41
 1042    internal int OrdinaryCount => _ordinaryGrids.Count;
 43
 1044    internal int OversizedCount => _oversizedGrids.Count;
 45
 46    internal bool Insert(ushort gridIndex, FixedBoundVolume bounds)
 47    {
 57248        if (_ordinaryGrids.Contains(gridIndex) || _oversizedSlots.Contains(gridIndex))
 249            return false;
 50
 57051        if (FitsHashCellBudget(bounds))
 54552            return _ordinaryGrids.Insert(gridIndex, bounds);
 53
 2554        _oversizedGrids.Insert(gridIndex, bounds);
 2555        _oversizedSlots.Add(gridIndex);
 2556        return true;
 57    }
 58
 59    internal bool Remove(ushort gridIndex)
 60    {
 4561        if (!_oversizedSlots.Contains(gridIndex))
 3962            return _ordinaryGrids.Remove(gridIndex);
 63
 664        _oversizedGrids.Remove(gridIndex);
 665        _oversizedSlots.Remove(gridIndex);
 666        return true;
 67    }
 68
 69    internal void Clear()
 70    {
 54371        _ordinaryGrids.Clear();
 54372        _oversizedGrids.Clear();
 54373        _oversizedSlots.Clear();
 54374    }
 75
 76    internal void CollectCandidates(
 77        FixedBoundVolume queryBounds,
 78        SwiftBucket<VoxelGrid> activeGrids,
 79        SwiftList<ushort> candidates)
 80    {
 143281        candidates.Clear();
 143282        if (activeGrids.Count == 0)
 783            return;
 84
 142585        if (ShouldScanActiveGrids(queryBounds, activeGrids.Count))
 86        {
 589287            foreach (VoxelGrid grid in activeGrids)
 88            {
 161089                var gridBounds = new FixedBoundVolume(grid.BoundsMin, grid.BoundsMax);
 161090                if (gridBounds.Intersects(queryBounds))
 147191                    candidates.Add(grid.GridIndex);
 92            }
 93        }
 94        else
 95        {
 8996            if (_ordinaryGrids.Count > 0)
 8897                _ordinaryGrids.Query(queryBounds, candidates);
 98
 8999            if (_oversizedGrids.Count > 0)
 17100                _oversizedGrids.Query(queryBounds, candidates);
 101        }
 102
 1425103        if (candidates.Count > 1)
 129104            candidates.SortInPlace();
 1425105    }
 106
 107    internal void CollectPointCandidates(
 108        Vector3d point,
 109        SwiftList<ushort> candidates)
 110    {
 153111        candidates.Clear();
 153112        if (_ordinaryGrids.Count > 0)
 151113            _ordinaryGrids.CollectPointCandidates(point, candidates);
 114
 153115        if (_oversizedGrids.Count > 0)
 4116            _oversizedGrids.Query(new FixedBoundVolume(point, point), candidates);
 117
 153118        if (candidates.Count > 1)
 16119            candidates.SortInPlace();
 153120    }
 121
 122    internal bool FitsHashCellBudget(FixedBoundVolume bounds)
 123    {
 579124        if (_cellBudget == 0UL)
 1125            return false;
 126
 578127        GetCellRange(bounds, out SwiftSpatialHashCellIndex minCell, out SwiftSpatialHashCellIndex maxCell);
 578128        ulong xCount = GetCellCount(minCell.X, maxCell.X);
 578129        if (xCount > _cellBudget)
 27130            return false;
 131
 551132        ulong yCount = GetCellCount(minCell.Y, maxCell.Y);
 551133        if (yCount > _cellBudget / xCount)
 1134            return false;
 135
 550136        ulong xyCount = xCount * yCount;
 550137        ulong zCount = GetCellCount(minCell.Z, maxCell.Z);
 550138        return zCount <= _cellBudget / xyCount;
 139    }
 140
 141    internal void GetCellRange(
 142        FixedBoundVolume bounds,
 143        out SwiftSpatialHashCellIndex minCell,
 144        out SwiftSpatialHashCellIndex maxCell)
 145    {
 2015146        minCell = _ordinaryGrids.GetCellIndex(bounds.Min);
 2015147        maxCell = _ordinaryGrids.GetCellIndex(bounds.Max);
 2015148    }
 149
 150    internal bool ShouldScanActiveGrids(
 151        FixedBoundVolume queryBounds,
 152        int activeGridCount)
 153    {
 1430154        GetCellRange(queryBounds, out SwiftSpatialHashCellIndex minCell, out SwiftSpatialHashCellIndex maxCell);
 1430155        ulong count = (ulong)activeGridCount;
 1430156        ulong xCount = GetCellCount(minCell.X, maxCell.X);
 1430157        if (xCount > count)
 1037158            return true;
 159
 393160        ulong yCount = GetCellCount(minCell.Y, maxCell.Y);
 393161        if (yCount > count / xCount)
 231162            return true;
 163
 162164        ulong xyCount = xCount * yCount;
 162165        ulong zCount = GetCellCount(minCell.Z, maxCell.Z);
 162166        return zCount > count / xyCount;
 167    }
 168
 169    private static ulong GetCellCount(int minimum, int maximum) =>
 3664170        (ulong)((long)maximum - minimum + 1L);
 171}