< Summary

Information
Class: Trailblazer.Pathing.FlowFieldSamplingGrid
Assembly: Trailblazer
File(s): /home/runner/work/Trailblazer/Trailblazer/src/Trailblazer/Pathing/Search/FlowField/FlowFieldSamplingGrid.cs
Line coverage
100%
Covered lines: 65
Uncovered lines: 0
Coverable lines: 65
Total lines: 136
Line coverage: 100%
Branch coverage
85%
Covered branches: 29
Total branches: 34
Branch coverage: 85.2%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)87.5%88100%
MatchesGrid(...)100%44100%
AddDirection(...)100%44100%
TryGetDirection(...)77.77%1818100%
GetDenseIndex(...)100%11100%

File(s)

/home/runner/work/Trailblazer/Trailblazer/src/Trailblazer/Pathing/Search/FlowField/FlowFieldSamplingGrid.cs

#LineLine coverage
 1using FixedMathSharp;
 2using GridForge.Spatial;
 3using SwiftCollections;
 4using System;
 5using System.Runtime.CompilerServices;
 6
 7namespace Trailblazer.Pathing;
 8
 9/// <summary>
 10/// Stores the grid-space transform required to sample a flow-field result without resolving voxels through the world ma
 11/// </summary>
 12internal sealed class FlowFieldSamplingGrid
 13{
 14    private const int DenseSparsityFactor = 4;
 15
 16    private readonly int _worldSpawnToken;
 17    private readonly ushort _gridIndex;
 18    private readonly int _gridSpawnToken;
 19    private readonly Vector3d _originWorldPosition;
 20    private readonly Fixed64 _voxelSize;
 21    private readonly int _minX;
 22    private readonly int _minY;
 23    private readonly int _minZ;
 24    private readonly int _sizeX;
 25    private readonly int _sizeY;
 26    private readonly int _sizeZ;
 27    private readonly Vector3d[]? _denseDirections;
 28    private readonly bool[]? _denseOccupied;
 29    private readonly SwiftDictionary<FlowFieldLocalIndex, Vector3d>? _sparseDirections;
 30
 12431    public FlowFieldSamplingGrid(
 12432        WorldVoxelIndex sampleIndex,
 12433        Vector3d originWorldPosition,
 12434        Fixed64 voxelSize,
 12435        int minX,
 12436        int minY,
 12437        int minZ,
 12438        int maxX,
 12439        int maxY,
 12440        int maxZ,
 12441        int fieldCount)
 42    {
 12443        _worldSpawnToken = sampleIndex.WorldSpawnToken;
 12444        _gridIndex = sampleIndex.GridIndex;
 12445        _gridSpawnToken = sampleIndex.GridSpawnToken;
 12446        _originWorldPosition = originWorldPosition;
 12447        _voxelSize = voxelSize;
 12448        _minX = minX;
 12449        _minY = minY;
 12450        _minZ = minZ;
 12451        _sizeX = maxX - minX + 1;
 12452        _sizeY = maxY - minY + 1;
 12453        _sizeZ = maxZ - minZ + 1;
 54
 12455        long denseLength = (long)_sizeX * _sizeY * _sizeZ;
 12456        long denseLimit = Math.Max((long)fieldCount + 32L, (long)fieldCount * DenseSparsityFactor);
 12457        if (denseLength > 0 && denseLength <= denseLimit && denseLength <= int.MaxValue)
 58        {
 12359            _denseDirections = new Vector3d[(int)denseLength];
 12360            _denseOccupied = new bool[(int)denseLength];
 61        }
 62        else
 63        {
 164            _sparseDirections = fieldCount > 0
 165                ? new SwiftDictionary<FlowFieldLocalIndex, Vector3d>(fieldCount)
 166                : new SwiftDictionary<FlowFieldLocalIndex, Vector3d>();
 67        }
 168    }
 69
 70    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 71    public bool MatchesGrid(WorldVoxelIndex index)
 72    {
 181873        return index.WorldSpawnToken == _worldSpawnToken
 181874            && index.GridIndex == _gridIndex
 181875            && index.GridSpawnToken == _gridSpawnToken;
 76    }
 77
 78    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 79    public void AddDirection(WorldVoxelIndex index, Vector3d direction)
 80    {
 181881        FlowFieldLocalIndex localIndex = FlowFieldLocalIndex.FromVoxelIndex(index.VoxelIndex);
 181882        if (_denseDirections != null && _denseOccupied != null)
 83        {
 181784            int denseIndex = GetDenseIndex(localIndex.X, localIndex.Y, localIndex.Z);
 181785            _denseDirections[denseIndex] = direction;
 181786            _denseOccupied[denseIndex] = true;
 181787            return;
 88        }
 89
 190        _sparseDirections!.Add(localIndex, direction);
 191    }
 92
 93    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 94    public bool TryGetDirection(Vector3d worldPosition, out Vector3d direction)
 95    {
 4796        Fixed64 localX = (worldPosition.x - _originWorldPosition.x) / _voxelSize;
 4797        Fixed64 localY = (worldPosition.y - _originWorldPosition.y) / _voxelSize;
 4798        Fixed64 localZ = (worldPosition.z - _originWorldPosition.z) / _voxelSize;
 99
 47100        int x = localX.FloorToInt();
 47101        int y = localY.FloorToInt();
 47102        int z = localZ.FloorToInt();
 103
 47104        if (_denseDirections != null && _denseOccupied != null)
 105        {
 45106            if (x < _minX
 45107                || x >= _minX + _sizeX
 45108                || y < _minY
 45109                || y >= _minY + _sizeY
 45110                || z < _minZ
 45111                || z >= _minZ + _sizeZ)
 112            {
 4113                direction = Vector3d.Zero;
 4114                return false;
 115            }
 116
 41117            int denseIndex = GetDenseIndex(x, y, z);
 41118            if (!_denseOccupied[denseIndex])
 119            {
 1120                direction = Vector3d.Zero;
 1121                return false;
 122            }
 123
 40124            direction = _denseDirections[denseIndex];
 40125            return true;
 126        }
 127
 2128        return _sparseDirections!.TryGetValue(new FlowFieldLocalIndex(x, y, z), out direction);
 129    }
 130
 131    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 132    private int GetDenseIndex(int x, int y, int z)
 133    {
 1858134        return (((y - _minY) * _sizeZ) + (z - _minZ)) * _sizeX + (x - _minX);
 135    }
 136}