< Summary

Information
Class: Gravitas.Colliders.LSCylinderCollider
Assembly: Gravitas
File(s): /home/runner/work/Gravitas/Gravitas/src/Gravitas/Colliders/3D/LSCylinderCollider.cs
Line coverage
100%
Covered lines: 95
Uncovered lines: 0
Coverable lines: 95
Total lines: 191
Line coverage: 100%
Branch coverage
100%
Covered branches: 6
Total branches: 6
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_Shape()100%11100%
get_Priority()100%11100%
get_ScaledRadius()100%11100%
OnRadiusChanged()100%11100%
NormalizeSize(...)100%11100%
CalculateMassPropertyWeight()100%11100%
CalculatePreparedMassPropertyWeight()100%11100%
CalculateCenterOfMassInertiaTensor(...)100%11100%
ColliderOverlapsRay(...)100%11100%
ClosestPointOnSurface(...)100%22100%
GetNormalAtPoint(...)100%11100%
GetClosestSurfaceAnchor(...)100%11100%
PrepareShape(...)100%11100%
PublishShape()100%11100%
GetFrontalArea(...)100%44100%

File(s)

/home/runner/work/Gravitas/Gravitas/src/Gravitas/Colliders/3D/LSCylinderCollider.cs

#LineLine coverage
 1//=======================================================================
 2// LSCylinderCollider.cs
 3//=======================================================================
 4// MIT License, Copyright (c) 2026–present David Oravsky (mrdav30)
 5// See LICENSE file in the project root for full license information.
 6//=======================================================================
 7
 8using FixedMathSharp;
 9using FixedMathSharp.Geometry;
 10using Gravitas.Queries;
 11using SwiftCollections;
 12using System;
 13
 14namespace Gravitas.Colliders;
 15
 16/// <summary>Represents a finite runtime 3D cylinder whose local axis follows Y.</summary>
 17public sealed class LSCylinderCollider : LSCollider
 18{
 56719    private Fixed64 _scaledRadius = Fixed64.Half;
 20    private Fixed64 _preparedRadius;
 21    private Fixed64 _preparedHeight;
 22    private Vector3d _preparedAxis;
 23    private Fixed64 _preparedArea;
 24
 25    /// <summary>Creates a cylinder collider with default dimensions.</summary>
 108426    public LSCylinderCollider() { }
 27
 28    /// <summary>Creates a runtime cylinder from an authored shape definition.</summary>
 2529    public LSCylinderCollider(ColliderShapeDefinition definition)
 30    {
 2531        definition.EnsureKind(ColliderShapeDefinitionKind.Cylinder);
 2532        Material = definition.Material;
 2533        Radius = definition.Radius;
 2534        Size = definition.Size;
 2535    }
 36
 37    /// <inheritdoc/>
 67338    public override ColliderType Shape => ColliderType.Cylinder;
 39    /// <inheritdoc/>
 9640    public override int Priority => ColliderSettings.GetPriority(Shape);
 41
 42    /// <inheritdoc/>
 853343    public override Fixed64 ScaledRadius => _scaledRadius;
 44
 45    /// <summary>
 46    /// Gets the cylinder's full physical length along <see cref="WorldAxis"/>.
 47    /// </summary>
 48    public Fixed64 Height { get; private set; }
 49
 50    /// <summary>
 51    /// Gets the derived normalized world-space cylinder axis. Exact geometry
 52    /// remains authoritative in the collider's rigid frame.
 53    /// </summary>
 54    public Vector3d WorldAxis { get; private set; } = Vector3d.Up;
 55
 56    /// <inheritdoc/>
 57    protected override void OnRadiusChanged()
 58    {
 1959        Fixed64 diameter = _radius * 2;
 1960        _size = new Vector3d(diameter, _size.Y, diameter);
 1961    }
 62
 63    /// <inheritdoc/>
 64    protected override Vector3d NormalizeSize(Vector3d value) =>
 48965        new(_radius * 2, value.Y, _radius * 2);
 66
 67    internal override ExactMassWeight CalculateMassPropertyWeight() =>
 4568        ExactMassWeight.FromProduct(
 4569            Fixed64.Pi,
 4570            ScaledRadius,
 4571            ScaledRadius,
 4572            Height);
 73
 74    internal override ExactMassWeight CalculatePreparedMassPropertyWeight() =>
 6075        ExactMassWeight.FromProduct(
 6076            Fixed64.Pi,
 6077            _preparedRadius,
 6078            _preparedRadius,
 6079            _preparedHeight);
 80
 81    internal override Fixed3x3 CalculateCenterOfMassInertiaTensor(Fixed64 mass)
 82    {
 50383        Fixed64 radiusSqr = ScaledRadiusSqr;
 50384        Fixed64 heightSqr = Height * Height;
 50385        Fixed64 inertiaXZ = Fixed64.FromFraction(1, 12) * mass * ((3 * radiusSqr) + heightSqr);
 50386        Fixed64 inertiaY = Fixed64.Half * mass * radiusSqr;
 87
 50388        Fixed3x3 tensor = new(
 50389            inertiaXZ, Fixed64.Zero, Fixed64.Zero,
 50390            Fixed64.Zero, inertiaY, Fixed64.Zero,
 50391            Fixed64.Zero, Fixed64.Zero, inertiaXZ
 50392        );
 50393        return tensor;
 94    }
 95
 96    /// <inheritdoc/>
 97    public override bool ColliderOverlapsRay(RaycastSegmentWorker worker, ref SwiftList<Vector3d> outputIntersectionPoin
 98    {
 1099        return worker.CheckCylinderOverlaps(this, ref outputIntersectionPoints);
 100    }
 101
 102    /// <inheritdoc/>
 103    public override Vector3d ClosestPointOnSurface(Vector3d other)
 104    {
 86105        FixedPointAnchor surfaceAnchor =
 86106            GetClosestSurfaceAnchor(other, out _);
 86107        if (!surfaceAnchor.TryGetPoint(out Vector3d surfacePoint))
 108        {
 1109            throw new InvalidOperationException(
 1110                "The closest cylinder surface point is outside the representable coordinate domain.");
 111        }
 112
 85113        return surfacePoint;
 114    }
 115
 116    /// <inheritdoc/>
 117    public override Vector3d GetNormalAtPoint(Vector3d point)
 118    {
 29119        _ = GetClosestSurfaceAnchor(
 29120            point,
 29121            out Vector3d outwardNormal);
 29122        return outwardNormal;
 123    }
 124
 125    internal override FixedPointAnchor GetClosestSurfaceAnchor(
 126        Vector3d point,
 127        out Vector3d normal) =>
 329128        WideFiniteAxisIntersection
 329129            .GetClosestCenteredFiniteCylinderSurfaceAnchor(
 329130                point,
 329131                Center,
 329132                Rotation,
 329133                Vector3d.Up,
 329134                Height,
 329135                ScaledRadius,
 329136                Vector3d.Right,
 329137                out normal,
 329138                out _);
 139
 140    private protected override void PrepareShape(in ColliderShapeSnapshot snapshot)
 141    {
 578142        Fixed64 radiusX = ColliderScalePolicy.ScalePositive(
 578143            snapshot.Radius,
 578144            snapshot.OwnerScale.X,
 578145            snapshot.PartScale.X);
 578146        Fixed64 radiusZ = ColliderScalePolicy.ScalePositive(
 578147            snapshot.Radius,
 578148            snapshot.OwnerScale.Z,
 578149            snapshot.PartScale.Z);
 578150        _preparedRadius = FixedMath.Max(radiusX, radiusZ);
 578151        _preparedHeight = ColliderScalePolicy.ScalePositive(
 578152            snapshot.Size.Y,
 578153            snapshot.OwnerScale.Y,
 578154            snapshot.PartScale.Y);
 578155        _preparedAxis = (snapshot.Rotation * Vector3d.Up).Normalized;
 578156        _preparedArea = Fixed64.Two * Fixed64.Pi * _preparedRadius
 578157            * (_preparedHeight + _preparedRadius);
 578158        SetPreparedBounds(FixedBoundBox.FromCenteredFiniteCylinderClippedToDomain(
 578159            snapshot.Center,
 578160            snapshot.Rotation,
 578161            Vector3d.Up,
 578162            _preparedHeight,
 578163            _preparedRadius));
 578164    }
 165
 166    private protected override void PublishShape()
 167    {
 578168        _scaledRadius = _preparedRadius;
 578169        Height = _preparedHeight;
 578170        WorldAxis = _preparedAxis;
 578171        Area = _preparedArea;
 578172    }
 173
 174    /// <inheritdoc/>
 175    public override Fixed64 GetFrontalArea(Vector3d direction)
 176    {
 4177        Fixed64 directionMagnitude = direction.Magnitude;
 4178        if (directionMagnitude <= Fixed64.Epsilon)
 1179            return Area;
 180
 3181        Vector3d normalizedDirection = direction / directionMagnitude;
 3182        Fixed64 axial = Rotation.Inverse()
 3183            .Rotate(normalizedDirection).Y.Abs();
 3184        Fixed64 radialFactorSqr = Fixed64.One - axial * axial;
 3185        Fixed64 radialFactor = radialFactorSqr <= Fixed64.Zero ? Fixed64.Zero : FixedMath.Sqrt(radialFactorSqr);
 186
 3187        return axial * Fixed64.Pi * ScaledRadiusSqr
 3188            + radialFactor * 2 * ScaledRadius * Height;
 189    }
 190
 191}