< Summary

Information
Class: FixedMathSharp.Bounds.FixedBoundFrustum
Assembly: FixedMathSharp
File(s): /home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Bounds/FixedBoundFrustum.cs
Line coverage
100%
Covered lines: 273
Uncovered lines: 0
Coverable lines: 273
Total lines: 725
Line coverage: 100%
Branch coverage
93%
Covered branches: 156
Total branches: 166
Branch coverage: 93.9%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.cctor()100%11100%
.ctor(...)100%11100%
.ctor(...)100%11100%
.ctor(...)100%44100%
get_HasMatrix()100%11100%
get_Matrix()100%22100%
set_Matrix(...)100%11100%
get_Near()100%11100%
get_Far()100%11100%
get_Left()100%11100%
get_Right()100%11100%
get_Top()100%11100%
get_Bottom()100%11100%
Contains(...)100%1212100%
Contains(...)71.42%1414100%
Contains(...)71.42%1414100%
Contains(...)100%1010100%
Intersects(...)100%11100%
Intersects(...)100%11100%
Intersects(...)100%11100%
Intersects(...)83.33%1212100%
Intersects(...)100%44100%
ClampPoint(...)100%1010100%
GetCorners()100%11100%
GetCorners(...)100%44100%
GetPlanes()100%11100%
GetPlanes(...)100%44100%
GetCorner(...)100%99100%
GetPlane(...)100%77100%
SetMatrix(...)100%11100%
SetPlanes(...)100%11100%
SetPlanes(...)100%11100%
CreatePlanes(...)100%11100%
CreateCorners()100%11100%
UpdateBounds()100%22100%
IntersectionPoint(...)100%22100%
IsInside(...)100%44100%
UpdateNearestCandidate(...)100%22100%
IntersectsFrustum(...)100%1414100%
DisjointOrIntersects(...)100%44100%
DisjointOrIntersects(...)100%44100%
ClipRay(...)100%88100%
Separates(...)100%22100%
Project(...)100%66100%
GetEdgeStart(...)100%11100%
GetEdgeEnd(...)100%11100%
Equals(...)100%1010100%
Equals(...)100%22100%
GetHashCode()100%11100%

File(s)

/home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Bounds/FixedBoundFrustum.cs

#LineLine coverage
 1//=======================================================================
 2// FixedBoundFrustum.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;
 10
 11namespace FixedMathSharp.Bounds;
 12
 13/// <summary>
 14/// Represents a frustum bounded by six clipping planes.
 15/// </summary>
 16public struct FixedBoundFrustum : IEquatable<FixedBoundFrustum>
 17{
 18    #region Constants
 19
 20    /// <summary>
 21    /// The number of planes in a frustum.
 22    /// </summary>
 23    public const int PlaneCount = 6;
 24
 25    /// <summary>
 26    /// The number of corner points in a frustum.
 27    /// </summary>
 28    public const int CornerCount = 8;
 29
 30    #endregion
 31
 32    #region Fields
 33
 34    private const int EdgeCount = 12;
 135    private static readonly int[] s_edgeStarts = { 0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3 };
 136    private static readonly int[] s_edgeEnds = { 1, 2, 3, 0, 5, 6, 7, 4, 4, 5, 6, 7 };
 37
 38    private bool _hasMatrix;
 39    private Fixed4x4 _matrix;
 40    private FixedPlane _near;
 41    private FixedPlane _far;
 42    private FixedPlane _left;
 43    private FixedPlane _right;
 44    private FixedPlane _top;
 45    private FixedPlane _bottom;
 46    private Vector3d _nearTopLeft;
 47    private Vector3d _nearTopRight;
 48    private Vector3d _nearBottomRight;
 49    private Vector3d _nearBottomLeft;
 50    private Vector3d _farTopLeft;
 51    private Vector3d _farTopRight;
 52    private Vector3d _farBottomRight;
 53    private Vector3d _farBottomLeft;
 54
 55    #endregion
 56
 57    #region Constructors
 58
 59    /// <summary>
 60    /// Initializes a new frustum by extracting the planes and corners from a combined view-projection matrix.
 61    /// </summary>
 62    public FixedBoundFrustum(Fixed4x4 matrix)
 63    {
 4764        this = default;
 4765        SetMatrix(matrix);
 4766    }
 67
 68    /// <summary>
 69    /// Initializes a new frustum from six clipping planes.
 70    /// </summary>
 71    public FixedBoundFrustum(
 72        FixedPlane near,
 73        FixedPlane far,
 74        FixedPlane left,
 75        FixedPlane right,
 76        FixedPlane top,
 77        FixedPlane bottom)
 78    {
 879        this = default;
 880        SetPlanes(near, far, left, right, top, bottom);
 781    }
 82
 83    /// <summary>
 84    /// Initializes a new frustum from six clipping planes in near, far, left, right, top, bottom order.
 85    /// </summary>
 86    public FixedBoundFrustum(FixedPlane[] planes)
 87    {
 388        if (planes is null)
 189            throw new ArgumentNullException(nameof(planes), "Cannot create a frustum from a null plane array.");
 90
 291        if (planes.Length != PlaneCount)
 192            throw new ArgumentException($"A frustum must be defined by exactly {PlaneCount} planes.");
 93
 194        this = default;
 195        SetPlanes(planes);
 196    }
 97
 98    #endregion
 99
 100    #region Properties
 101
 102    /// <summary>
 103    /// Gets a value indicating whether this frustum was created from a matrix source.
 104    /// </summary>
 105    public bool HasMatrix
 106    {
 107        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 2108        get => _hasMatrix;
 109    }
 110
 111    /// <summary>
 112    /// Gets or sets the matrix source used to define this frustum.
 113    /// </summary>
 114    /// <exception cref="InvalidOperationException">
 115    /// Thrown when reading the matrix from a frustum that was created from planes.
 116    /// </exception>
 117    public Fixed4x4 Matrix
 118    {
 119        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 2120        get => _hasMatrix ? _matrix : throw new InvalidOperationException("This frustum was not created from a matrix.")
 1121        set => SetMatrix(value);
 122    }
 123
 124    /// <summary>
 125    /// Gets the near clipping plane.
 126    /// </summary>
 127    public FixedPlane Near
 128    {
 129        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 2130        get => _near;
 131    }
 132
 133    /// <summary>
 134    /// Gets the far clipping plane.
 135    /// </summary>
 136    public FixedPlane Far
 137    {
 138        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 1139        get => _far;
 140    }
 141
 142    /// <summary>
 143    /// Gets the left clipping plane.
 144    /// </summary>
 145    public FixedPlane Left
 146    {
 147        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 1148        get => _left;
 149    }
 150
 151    /// <summary>
 152    /// Gets the right clipping plane.
 153    /// </summary>
 154    public FixedPlane Right
 155    {
 156        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 1157        get => _right;
 158    }
 159
 160    /// <summary>
 161    /// Gets the top clipping plane.
 162    /// </summary>
 163    public FixedPlane Top
 164    {
 165        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 1166        get => _top;
 167    }
 168
 169    /// <summary>
 170    /// Gets the bottom clipping plane.
 171    /// </summary>
 172    public FixedPlane Bottom
 173    {
 174        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 1175        get => _bottom;
 176    }
 177
 178    /// <summary>
 179    /// Gets the minimum corner of the axis-aligned box that encloses the frustum.
 180    /// </summary>
 181    public Vector3d Min { get; private set; }
 182
 183    /// <summary>
 184    /// Gets the maximum corner of the axis-aligned box that encloses the frustum.
 185    /// </summary>
 186    public Vector3d Max { get; private set; }
 187
 188    #endregion
 189
 190    #region Methods
 191
 192    /// <summary>
 193    /// Tests a point against this frustum.
 194    /// </summary>
 195    public FixedEnclosureType Contains(Vector3d point)
 196    {
 44197        return _near.DotCoordinate(point) > Fixed64.Zero
 44198            || _far.DotCoordinate(point) > Fixed64.Zero
 44199            || _left.DotCoordinate(point) > Fixed64.Zero
 44200            || _right.DotCoordinate(point) > Fixed64.Zero
 44201            || _top.DotCoordinate(point) > Fixed64.Zero
 44202            || _bottom.DotCoordinate(point) > Fixed64.Zero
 44203                ? FixedEnclosureType.Disjoint
 44204                : FixedEnclosureType.Contains;
 205    }
 206
 207    /// <summary>
 208    /// Tests a bounding box against this frustum.
 209    /// </summary>
 210    public FixedEnclosureType Contains(FixedBoundBox box)
 211    {
 11212        bool intersects = false;
 213
 11214        if (DisjointOrIntersects(_near, box, ref intersects)
 11215            || DisjointOrIntersects(_far, box, ref intersects)
 11216            || DisjointOrIntersects(_left, box, ref intersects)
 11217            || DisjointOrIntersects(_right, box, ref intersects)
 11218            || DisjointOrIntersects(_top, box, ref intersects)
 11219            || DisjointOrIntersects(_bottom, box, ref intersects))
 3220            return FixedEnclosureType.Disjoint;
 221
 8222        return intersects ? FixedEnclosureType.Intersects : FixedEnclosureType.Contains;
 223    }
 224
 225    /// <summary>
 226    /// Tests a bounding sphere against this frustum.
 227    /// </summary>
 228    public FixedEnclosureType Contains(FixedBoundSphere sphere)
 229    {
 8230        bool intersects = false;
 231
 8232        if (DisjointOrIntersects(_near, sphere, ref intersects)
 8233            || DisjointOrIntersects(_far, sphere, ref intersects)
 8234            || DisjointOrIntersects(_left, sphere, ref intersects)
 8235            || DisjointOrIntersects(_right, sphere, ref intersects)
 8236            || DisjointOrIntersects(_top, sphere, ref intersects)
 8237            || DisjointOrIntersects(_bottom, sphere, ref intersects))
 2238            return FixedEnclosureType.Disjoint;
 239
 6240        return intersects ? FixedEnclosureType.Intersects : FixedEnclosureType.Contains;
 241    }
 242
 243    /// <summary>
 244    /// Tests another frustum against this frustum.
 245    /// </summary>
 246    public FixedEnclosureType Contains(FixedBoundFrustum frustum)
 247    {
 13248        if (Equals(frustum))
 1249            return FixedEnclosureType.Contains;
 250
 12251        bool containsAllCorners = true;
 56252        for (int i = 0; i < CornerCount; i++)
 253        {
 26254            if (Contains(frustum.GetCorner(i)) == FixedEnclosureType.Disjoint)
 255            {
 10256                containsAllCorners = false;
 10257                break;
 258            }
 259        }
 260
 12261        if (containsAllCorners)
 2262            return FixedEnclosureType.Contains;
 263
 10264        return IntersectsFrustum(frustum)
 10265            ? FixedEnclosureType.Intersects
 10266            : FixedEnclosureType.Disjoint;
 267    }
 268
 269    /// <summary>
 270    /// Checks whether a bounding box intersects this frustum.
 271    /// </summary>
 272    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 7273    public bool Intersects(FixedBoundBox box) => Contains(box) != FixedEnclosureType.Disjoint;
 274
 275    /// <summary>
 276    /// Checks whether a bounding sphere intersects this frustum.
 277    /// </summary>
 278    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 6279    public bool Intersects(FixedBoundSphere sphere) => Contains(sphere) != FixedEnclosureType.Disjoint;
 280
 281    /// <summary>
 282    /// Checks whether another frustum intersects this frustum.
 283    /// </summary>
 284    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 6285    public bool Intersects(FixedBoundFrustum frustum) => Contains(frustum) != FixedEnclosureType.Disjoint;
 286
 287    /// <summary>
 288    /// Finds the first forward intersection between the specified ray and this frustum.
 289    /// </summary>
 290    public Fixed64? Intersects(FixedRay ray)
 291    {
 7292        Fixed64 tEnter = Fixed64.Zero;
 7293        Fixed64 tExit = Fixed64.MaxValue;
 294
 7295        if (!ClipRay(_near, ray, ref tEnter, ref tExit)
 7296            || !ClipRay(_far, ray, ref tEnter, ref tExit)
 7297            || !ClipRay(_left, ray, ref tEnter, ref tExit)
 7298            || !ClipRay(_right, ray, ref tEnter, ref tExit)
 7299            || !ClipRay(_top, ray, ref tEnter, ref tExit)
 7300            || !ClipRay(_bottom, ray, ref tEnter, ref tExit))
 3301            return null;
 302
 4303        return tEnter;
 304    }
 305
 306    /// <summary>
 307    /// Classifies this frustum relative to a plane.
 308    /// </summary>
 309    public FixedPlaneIntersectionType Intersects(FixedPlane plane)
 310    {
 4311        FixedPlaneIntersectionType result = plane.Intersects(_nearTopLeft);
 312
 36313        for (int i = 1; i < CornerCount; i++)
 314        {
 16315            if (plane.Intersects(GetCorner(i)) != result)
 2316                return FixedPlaneIntersectionType.Intersecting;
 317        }
 318
 2319        return result;
 320    }
 321
 322    /// <summary>
 323    /// Clamps a point to this frustum, returning the point unchanged when it is already inside.
 324    /// </summary>
 325    public Vector3d ClampPoint(Vector3d point)
 326    {
 5327        if (Contains(point) != FixedEnclosureType.Disjoint)
 1328            return point;
 329
 4330        Vector3d best = _nearTopLeft;
 4331        Fixed64 bestDistance = Vector3d.DistanceSquared(point, best);
 332
 64333        for (int i = 1; i < CornerCount; i++)
 28334            UpdateNearestCandidate(point, GetCorner(i), ref best, ref bestDistance);
 335
 56336        for (int i = 0; i < PlaneCount; i++)
 337        {
 24338            Vector3d candidate = Vector3d.ProjectOnPlane(point, GetPlane(i));
 24339            if (IsInside(candidate))
 4340                UpdateNearestCandidate(point, candidate, ref best, ref bestDistance);
 341        }
 342
 104343        for (int i = 0; i < EdgeCount; i++)
 344        {
 48345            Vector3d candidate = Vector3d.ClosestPointOnLineSegment(point, GetCorner(GetEdgeStart(i)), GetCorner(GetEdge
 48346            UpdateNearestCandidate(point, candidate, ref best, ref bestDistance);
 347        }
 348
 4349        return best;
 350    }
 351
 352    /// <summary>
 353    /// Returns a copy of the frustum corner array.
 354    /// </summary>
 355    public Vector3d[] GetCorners()
 356    {
 14357        var corners = new Vector3d[CornerCount];
 14358        GetCorners(corners);
 14359        return corners;
 360    }
 361
 362    /// <summary>
 363    /// Copies this frustum's corners into the specified array.
 364    /// </summary>
 365    public void GetCorners(Vector3d[] corners)
 366    {
 19367        if (corners is null)
 1368            throw new ArgumentNullException(nameof(corners), "Cannot copy corners to a null array.");
 369
 18370        if (corners.Length < CornerCount)
 1371            throw new ArgumentOutOfRangeException(nameof(corners), $"The destination array must have at least {CornerCou
 372
 17373        corners[0] = _nearTopLeft;
 17374        corners[1] = _nearTopRight;
 17375        corners[2] = _nearBottomRight;
 17376        corners[3] = _nearBottomLeft;
 17377        corners[4] = _farTopLeft;
 17378        corners[5] = _farTopRight;
 17379        corners[6] = _farBottomRight;
 17380        corners[7] = _farBottomLeft;
 17381    }
 382
 383    /// <summary>
 384    /// Returns a copy of the frustum plane array in near, far, left, right, top, bottom order.
 385    /// </summary>
 386    public FixedPlane[] GetPlanes()
 387    {
 2388        var planes = new FixedPlane[PlaneCount];
 2389        GetPlanes(planes);
 2390        return planes;
 391    }
 392
 393    /// <summary>
 394    /// Copies this frustum's planes into the specified array in near, far, left, right, top, bottom order.
 395    /// </summary>
 396    public void GetPlanes(FixedPlane[] planes)
 397    {
 7398        if (planes is null)
 1399            throw new ArgumentNullException(nameof(planes), "Cannot copy planes to a null array.");
 400
 6401        if (planes.Length < PlaneCount)
 1402            throw new ArgumentOutOfRangeException(nameof(planes), $"The destination array must have at least {PlaneCount
 403
 5404        planes[0] = _near;
 5405        planes[1] = _far;
 5406        planes[2] = _left;
 5407        planes[3] = _right;
 5408        planes[4] = _top;
 5409        planes[5] = _bottom;
 5410    }
 411
 412    /// <summary>
 413    /// Gets the corner at the specified stable index without allocating.
 414    /// </summary>
 415    public Vector3d GetCorner(int index)
 416    {
 417        switch (index)
 418        {
 123419            case 0: return _nearTopLeft;
 707420            case 1: return _nearTopRight;
 701421            case 2: return _nearBottomRight;
 701422            case 3: return _nearBottomLeft;
 701423            case 4: return _farTopLeft;
 701424            case 5: return _farTopRight;
 701425            case 6: return _farBottomRight;
 701426            case 7: return _farBottomLeft;
 427            default:
 2428                throw new ArgumentOutOfRangeException(nameof(index), $"Corner index must be between 0 and {CornerCount -
 429        }
 430    }
 431
 432    /// <summary>
 433    /// Gets the plane at the specified stable index in near, far, left, right, top, bottom order without allocating.
 434    /// </summary>
 435    public FixedPlane GetPlane(int index)
 436    {
 437        switch (index)
 438        {
 48439            case 0: return _near;
 43440            case 1: return _far;
 35441            case 2: return _left;
 31442            case 3: return _right;
 18443            case 4: return _top;
 16444            case 5: return _bottom;
 445            default:
 2446                throw new ArgumentOutOfRangeException(nameof(index), $"Plane index must be between 0 and {PlaneCount - 1
 447        }
 448    }
 449
 450    private void SetMatrix(Fixed4x4 matrix)
 451    {
 48452        _matrix = matrix;
 48453        _hasMatrix = true;
 48454        CreatePlanes(matrix);
 48455        CreateCorners();
 48456        UpdateBounds();
 48457    }
 458
 459    private void SetPlanes(FixedPlane[] planes)
 460    {
 1461        _near = FixedPlane.GetNormalized(planes[0]);
 1462        _far = FixedPlane.GetNormalized(planes[1]);
 1463        _left = FixedPlane.GetNormalized(planes[2]);
 1464        _right = FixedPlane.GetNormalized(planes[3]);
 1465        _top = FixedPlane.GetNormalized(planes[4]);
 1466        _bottom = FixedPlane.GetNormalized(planes[5]);
 467
 1468        _hasMatrix = false;
 1469        _matrix = default;
 1470        CreateCorners();
 1471        UpdateBounds();
 1472    }
 473
 474    private void SetPlanes(
 475        FixedPlane near,
 476        FixedPlane far,
 477        FixedPlane left,
 478        FixedPlane right,
 479        FixedPlane top,
 480        FixedPlane bottom)
 481    {
 8482        _near = FixedPlane.GetNormalized(near);
 8483        _far = FixedPlane.GetNormalized(far);
 8484        _left = FixedPlane.GetNormalized(left);
 8485        _right = FixedPlane.GetNormalized(right);
 8486        _top = FixedPlane.GetNormalized(top);
 8487        _bottom = FixedPlane.GetNormalized(bottom);
 488
 8489        _hasMatrix = false;
 8490        _matrix = default;
 8491        CreateCorners();
 7492        UpdateBounds();
 7493    }
 494
 495    private void CreatePlanes(Fixed4x4 matrix)
 496    {
 48497        _near = FixedPlane.GetNormalized(new FixedPlane(-matrix.M13, -matrix.M23, -matrix.M33, -matrix.M43));
 48498        _far = FixedPlane.GetNormalized(new FixedPlane(matrix.M13 - matrix.M14, matrix.M23 - matrix.M24, matrix.M33 - ma
 48499        _left = FixedPlane.GetNormalized(new FixedPlane(-matrix.M14 - matrix.M11, -matrix.M24 - matrix.M21, -matrix.M34 
 48500        _right = FixedPlane.GetNormalized(new FixedPlane(matrix.M11 - matrix.M14, matrix.M21 - matrix.M24, matrix.M31 - 
 48501        _top = FixedPlane.GetNormalized(new FixedPlane(matrix.M12 - matrix.M14, matrix.M22 - matrix.M24, matrix.M32 - ma
 48502        _bottom = FixedPlane.GetNormalized(new FixedPlane(-matrix.M14 - matrix.M12, -matrix.M24 - matrix.M22, -matrix.M3
 48503    }
 504
 505    private void CreateCorners()
 506    {
 57507        _nearTopLeft = IntersectionPoint(_near, _left, _top);
 56508        _nearTopRight = IntersectionPoint(_near, _right, _top);
 56509        _nearBottomRight = IntersectionPoint(_near, _right, _bottom);
 56510        _nearBottomLeft = IntersectionPoint(_near, _left, _bottom);
 56511        _farTopLeft = IntersectionPoint(_far, _left, _top);
 56512        _farTopRight = IntersectionPoint(_far, _right, _top);
 56513        _farBottomRight = IntersectionPoint(_far, _right, _bottom);
 56514        _farBottomLeft = IntersectionPoint(_far, _left, _bottom);
 56515    }
 516
 517    private void UpdateBounds()
 518    {
 56519        Vector3d min = _nearTopLeft;
 56520        Vector3d max = _nearTopLeft;
 521
 896522        for (int i = 1; i < CornerCount; i++)
 523        {
 392524            Vector3d corner = GetCorner(i);
 392525            min = Vector3d.Min(min, corner);
 392526            max = Vector3d.Max(max, corner);
 527        }
 528
 56529        Min = min;
 56530        Max = max;
 56531    }
 532
 533    private static Vector3d IntersectionPoint(FixedPlane a, FixedPlane b, FixedPlane c)
 534    {
 449535        Vector3d cross = Vector3d.Cross(b.Normal, c.Normal);
 449536        Fixed64 denominator = Vector3d.Dot(a.Normal, cross);
 537
 449538        if (denominator == Fixed64.Zero)
 1539            throw new InvalidOperationException("Frustum planes do not intersect at a unique point.");
 540
 448541        Vector3d v1 = cross * a.D;
 448542        Vector3d v2 = Vector3d.Cross(c.Normal, a.Normal) * b.D;
 448543        Vector3d v3 = Vector3d.Cross(a.Normal, b.Normal) * c.D;
 544
 448545        return -(v1 + v2 + v3) / denominator;
 546    }
 547
 548    private bool IsInside(Vector3d point)
 549    {
 198550        for (int i = 0; i < PlaneCount; i++)
 551        {
 95552            if (GetPlane(i).DotCoordinate(point) > Fixed64.Zero)
 20553                return false;
 554        }
 555
 4556        return true;
 557    }
 558
 559    private static void UpdateNearestCandidate(
 560        Vector3d point,
 561        Vector3d candidate,
 562        ref Vector3d best,
 563        ref Fixed64 bestDistance)
 564    {
 80565        Fixed64 candidateDistance = Vector3d.DistanceSquared(point, candidate);
 80566        if (candidateDistance >= bestDistance)
 71567            return;
 568
 9569        best = candidate;
 9570        bestDistance = candidateDistance;
 9571    }
 572
 573    private bool IntersectsFrustum(in FixedBoundFrustum other)
 574    {
 84575        for (int i = 0; i < PlaneCount; i++)
 576        {
 38577            if (Separates(GetPlane(i).Normal, this, other))
 4578                return false;
 579
 34580            if (Separates(other.GetPlane(i).Normal, this, other))
 2581                return false;
 582        }
 583
 56584        for (int i = 0; i < EdgeCount; i++)
 585        {
 26586            Vector3d edgeA = GetCorner(GetEdgeEnd(i)) - GetCorner(GetEdgeStart(i));
 587
 628588            for (int j = 0; j < EdgeCount; j++)
 589            {
 290590                Vector3d edgeB = other.GetCorner(GetEdgeEnd(j)) - other.GetCorner(GetEdgeStart(j));
 290591                Vector3d axis = Vector3d.Cross(edgeA, edgeB);
 592
 290593                if (axis.MagnitudeSquared <= Fixed64.Epsilon)
 594                    continue;
 595
 194596                if (Separates(axis, this, other))
 2597                    return false;
 598            }
 599        }
 600
 2601        return true;
 602    }
 603
 604    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 605    private static bool DisjointOrIntersects(FixedPlane plane, FixedBoundBox box, ref bool intersects)
 606    {
 60607        switch (plane.Intersects(box))
 608        {
 609            case FixedPlaneIntersectionType.Front:
 3610                return true;
 611            case FixedPlaneIntersectionType.Intersecting:
 18612                intersects = true;
 613                break;
 614        }
 615
 57616        return false;
 617    }
 618
 619    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 620    private static bool DisjointOrIntersects(FixedPlane plane, FixedBoundSphere sphere, ref bool intersects)
 621    {
 44622        switch (plane.Intersects(sphere))
 623        {
 624            case FixedPlaneIntersectionType.Front:
 2625                return true;
 626            case FixedPlaneIntersectionType.Intersecting:
 19627                intersects = true;
 628                break;
 629        }
 630
 42631        return false;
 632    }
 633
 634    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 635    private static bool ClipRay(FixedPlane plane, FixedRay ray, ref Fixed64 tEnter, ref Fixed64 tExit)
 636    {
 31637        Fixed64 distance = plane.DotCoordinate(ray.Position);
 31638        Fixed64 denominator = plane.DotNormal(ray.Direction);
 639
 31640        if (FixedRay.IsNearlyZero(denominator))
 14641            return distance <= Fixed64.Zero;
 642
 17643        Fixed64 t = -distance / denominator;
 17644        if (denominator < Fixed64.Zero)
 645        {
 8646            if (t > tEnter)
 3647                tEnter = t;
 648        }
 9649        else if (t < tExit)
 650        {
 7651            tExit = t;
 652        }
 653
 17654        return tEnter <= tExit;
 655    }
 656
 657    private static bool Separates(Vector3d axis, in FixedBoundFrustum a, in FixedBoundFrustum b)
 658    {
 266659        Project(axis, a, out Fixed64 minA, out Fixed64 maxA);
 266660        Project(axis, b, out Fixed64 minB, out Fixed64 maxB);
 661
 266662        return maxA < minB || maxB < minA;
 663    }
 664
 665    private static void Project(Vector3d axis, in FixedBoundFrustum frustum, out Fixed64 min, out Fixed64 max)
 666    {
 532667        min = Vector3d.Dot(axis, frustum._nearTopLeft);
 532668        max = min;
 669
 8512670        for (int i = 1; i < CornerCount; i++)
 671        {
 3724672            Fixed64 projected = Vector3d.Dot(axis, frustum.GetCorner(i));
 3724673            if (projected < min)
 336674                min = projected;
 3388675            else if (projected > max)
 322676                max = projected;
 677        }
 532678    }
 679
 680    private static int GetEdgeStart(int edge)
 681    {
 364682        return s_edgeStarts[edge];
 683    }
 684
 685    private static int GetEdgeEnd(int edge)
 686    {
 364687        return s_edgeEnds[edge];
 688    }
 689
 690    #endregion
 691
 692    #region Equality
 693
 694    /// <inheritdoc/>
 695    public bool Equals(FixedBoundFrustum other)
 696    {
 15697        return _near == other._near
 15698            && _far == other._far
 15699            && _left == other._left
 15700            && _right == other._right
 15701            && _top == other._top
 15702            && _bottom == other._bottom;
 703    }
 704
 705    /// <inheritdoc/>
 3706    public override bool Equals(object? obj) => obj is FixedBoundFrustum other && Equals(other);
 707
 708    /// <inheritdoc/>
 709    public override int GetHashCode()
 710    {
 711        unchecked
 712        {
 3713            int hash = 17;
 3714            hash = (hash * 31) + _near.GetHashCode();
 3715            hash = (hash * 31) + _far.GetHashCode();
 3716            hash = (hash * 31) + _left.GetHashCode();
 3717            hash = (hash * 31) + _right.GetHashCode();
 3718            hash = (hash * 31) + _top.GetHashCode();
 3719            hash = (hash * 31) + _bottom.GetHashCode();
 3720            return hash;
 721        }
 722    }
 723
 724    #endregion
 725}

Methods/Properties

.cctor()
.ctor(FixedMathSharp.Fixed4x4)
.ctor(FixedMathSharp.Bounds.FixedPlane,FixedMathSharp.Bounds.FixedPlane,FixedMathSharp.Bounds.FixedPlane,FixedMathSharp.Bounds.FixedPlane,FixedMathSharp.Bounds.FixedPlane,FixedMathSharp.Bounds.FixedPlane)
.ctor(FixedMathSharp.Bounds.FixedPlane[])
get_HasMatrix()
get_Matrix()
set_Matrix(FixedMathSharp.Fixed4x4)
get_Near()
get_Far()
get_Left()
get_Right()
get_Top()
get_Bottom()
Contains(FixedMathSharp.Vector3d)
Contains(FixedMathSharp.Bounds.FixedBoundBox)
Contains(FixedMathSharp.Bounds.FixedBoundSphere)
Contains(FixedMathSharp.Bounds.FixedBoundFrustum)
Intersects(FixedMathSharp.Bounds.FixedBoundBox)
Intersects(FixedMathSharp.Bounds.FixedBoundSphere)
Intersects(FixedMathSharp.Bounds.FixedBoundFrustum)
Intersects(FixedMathSharp.Bounds.FixedRay)
Intersects(FixedMathSharp.Bounds.FixedPlane)
ClampPoint(FixedMathSharp.Vector3d)
GetCorners()
GetCorners(FixedMathSharp.Vector3d[])
GetPlanes()
GetPlanes(FixedMathSharp.Bounds.FixedPlane[])
GetCorner(System.Int32)
GetPlane(System.Int32)
SetMatrix(FixedMathSharp.Fixed4x4)
SetPlanes(FixedMathSharp.Bounds.FixedPlane[])
SetPlanes(FixedMathSharp.Bounds.FixedPlane,FixedMathSharp.Bounds.FixedPlane,FixedMathSharp.Bounds.FixedPlane,FixedMathSharp.Bounds.FixedPlane,FixedMathSharp.Bounds.FixedPlane,FixedMathSharp.Bounds.FixedPlane)
CreatePlanes(FixedMathSharp.Fixed4x4)
CreateCorners()
UpdateBounds()
IntersectionPoint(FixedMathSharp.Bounds.FixedPlane,FixedMathSharp.Bounds.FixedPlane,FixedMathSharp.Bounds.FixedPlane)
IsInside(FixedMathSharp.Vector3d)
UpdateNearestCandidate(FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d&,FixedMathSharp.Fixed64&)
IntersectsFrustum(FixedMathSharp.Bounds.FixedBoundFrustum&)
DisjointOrIntersects(FixedMathSharp.Bounds.FixedPlane,FixedMathSharp.Bounds.FixedBoundBox,System.Boolean&)
DisjointOrIntersects(FixedMathSharp.Bounds.FixedPlane,FixedMathSharp.Bounds.FixedBoundSphere,System.Boolean&)
ClipRay(FixedMathSharp.Bounds.FixedPlane,FixedMathSharp.Bounds.FixedRay,FixedMathSharp.Fixed64&,FixedMathSharp.Fixed64&)
Separates(FixedMathSharp.Vector3d,FixedMathSharp.Bounds.FixedBoundFrustum&,FixedMathSharp.Bounds.FixedBoundFrustum&)
Project(FixedMathSharp.Vector3d,FixedMathSharp.Bounds.FixedBoundFrustum&,FixedMathSharp.Fixed64&,FixedMathSharp.Fixed64&)
GetEdgeStart(System.Int32)
GetEdgeEnd(System.Int32)
Equals(FixedMathSharp.Bounds.FixedBoundFrustum)
Equals(System.Object)
GetHashCode()