< Summary

Information
Class: SwiftCollections.Query.SwiftOctree<T>
Assembly: SwiftCollections
File(s): /home/runner/work/SwiftCollections/SwiftCollections/src/SwiftCollections/Query/Octree/SwiftOctree.BoundVolume.cs
Line coverage
100%
Covered lines: 50
Uncovered lines: 0
Coverable lines: 50
Total lines: 117
Line coverage: 100%
Branch coverage
100%
Covered branches: 44
Total branches: 44
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%66100%
ContainsBounds(...)100%1010100%
CanSubdivide(...)100%44100%
TryGetContainingChildIndex(...)100%1212100%
CreateChildBounds(...)100%1212100%

File(s)

/home/runner/work/SwiftCollections/SwiftCollections/src/SwiftCollections/Query/Octree/SwiftOctree.BoundVolume.cs

#LineLine coverage
 1//=======================================================================
 2// SwiftOctree.BoundVolume.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.Numerics;
 10
 11namespace SwiftCollections.Query;
 12
 13/// <summary>
 14/// Represents a numerics-backed octree optimized for hierarchical spatial queries.
 15/// </summary>
 16public sealed class SwiftOctree<TKey> : SwiftOctree<TKey, BoundVolume>
 17    where TKey : notnull, IEquatable<TKey>
 18{
 19    /// <summary>
 20    /// Initializes a new instance of the <see cref="SwiftOctree{TKey}"/> class.
 21    /// </summary>
 22    /// <param name="worldBounds">The immutable world bounds covered by the octree.</param>
 23    /// <param name="options">Backend-neutral octree options.</param>
 24    /// <param name="minNodeSize">The minimum child-node axis length allowed for numerics subdivision.</param>
 25    public SwiftOctree(BoundVolume worldBounds, SwiftOctreeOptions options, float minNodeSize)
 3026        : base(worldBounds, options, new BoundVolumeOctreePartitioner(minNodeSize)) { }
 27
 28    private sealed class BoundVolumeOctreePartitioner : IOctreeBoundsPartitioner<BoundVolume>
 29    {
 30        private readonly float _minNodeSize;
 31
 1732        public BoundVolumeOctreePartitioner(float minNodeSize)
 33        {
 1734            if (float.IsNaN(minNodeSize) || float.IsInfinity(minNodeSize) || minNodeSize <= 0f)
 435                throw new ArgumentOutOfRangeException(nameof(minNodeSize), minNodeSize, "Minimum node size must be a fin
 36
 1337            _minNodeSize = minNodeSize;
 1338        }
 39
 40        public bool ContainsBounds(BoundVolume outer, BoundVolume inner)
 41        {
 3242            return inner.Min.X >= outer.Min.X &&
 3243                   inner.Min.Y >= outer.Min.Y &&
 3244                   inner.Min.Z >= outer.Min.Z &&
 3245                   inner.Max.X <= outer.Max.X &&
 3246                   inner.Max.Y <= outer.Max.Y &&
 3247                   inner.Max.Z <= outer.Max.Z;
 48        }
 49
 50        public bool CanSubdivide(BoundVolume bounds)
 51        {
 752            Vector3 childSize = bounds.Size * 0.5f;
 753            return childSize.X >= _minNodeSize &&
 754                   childSize.Y >= _minNodeSize &&
 755                   childSize.Z >= _minNodeSize;
 56        }
 57
 58        public bool TryGetContainingChildIndex(BoundVolume nodeBounds, BoundVolume entryBounds, out int childIndex)
 59        {
 3060            Vector3 midpoint = (nodeBounds.Min + nodeBounds.Max) * 0.5f;
 61
 62            int xBit;
 3063            if (entryBounds.Min.X >= midpoint.X)
 864                xBit = 1;
 2265            else if (entryBounds.Max.X <= midpoint.X)
 2166                xBit = 0;
 67            else
 68            {
 169                childIndex = -1;
 170                return false;
 71            }
 72
 73            int yBit;
 2974            if (entryBounds.Min.Y >= midpoint.Y)
 875                yBit = 1;
 2176            else if (entryBounds.Max.Y <= midpoint.Y)
 2077                yBit = 0;
 78            else
 79            {
 180                childIndex = -1;
 181                return false;
 82            }
 83
 84            int zBit;
 2885            if (entryBounds.Min.Z >= midpoint.Z)
 886                zBit = 1;
 2087            else if (entryBounds.Max.Z <= midpoint.Z)
 1988                zBit = 0;
 89            else
 90            {
 191                childIndex = -1;
 192                return false;
 93            }
 94
 2795            childIndex = xBit | (yBit << 1) | (zBit << 2);
 2796            return true;
 97        }
 98
 99        public BoundVolume CreateChildBounds(BoundVolume parentBounds, int childIndex)
 100        {
 48101            Vector3 midpoint = (parentBounds.Min + parentBounds.Max) * 0.5f;
 48102            bool upperX = (childIndex & 1) != 0;
 48103            bool upperY = (childIndex & 2) != 0;
 48104            bool upperZ = (childIndex & 4) != 0;
 105
 48106            return new BoundVolume(
 48107                new Vector3(
 48108                    upperX ? midpoint.X : parentBounds.Min.X,
 48109                    upperY ? midpoint.Y : parentBounds.Min.Y,
 48110                    upperZ ? midpoint.Z : parentBounds.Min.Z),
 48111                new Vector3(
 48112                    upperX ? parentBounds.Max.X : midpoint.X,
 48113                    upperY ? parentBounds.Max.Y : midpoint.Y,
 48114                    upperZ ? parentBounds.Max.Z : midpoint.Z));
 115        }
 116    }
 117}