| | | 1 | | //======================================================================= |
| | | 2 | | // CylinderPolytopeFrame.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 | | |
| | | 8 | | namespace FixedMathSharp.Geometry; |
| | | 9 | | |
| | | 10 | | /// <summary>Exact shared cylinder-local coordinates for polytope geometry.</summary> |
| | | 11 | | internal readonly struct CylinderPolytopeFrame |
| | | 12 | | { |
| | | 13 | | internal readonly WideRationalBasis3d Basis; |
| | | 14 | | internal readonly WideAxis3 Translation; |
| | | 15 | | internal readonly Signed192 Denominator; |
| | | 16 | | internal readonly Signed320 Cap; |
| | | 17 | | internal readonly Signed192 Radius; |
| | | 18 | | internal readonly Signed320 CoordinateDenominator; |
| | | 19 | | internal readonly bool HasExactScale; |
| | | 20 | | private readonly ScaledRigidFrame3d _sourceFrame; |
| | | 21 | | private readonly Vector3d _cylinderCenter; |
| | | 22 | | private readonly FixedQuaternion _cylinderRotation; |
| | 1572 | 23 | | internal ScaledRigidFrame3d SourceFrame => _sourceFrame; |
| | | 24 | | |
| | | 25 | | /// <summary>Exact capsule-local identity chart at a retained rational coordinate denominator.</summary> |
| | | 26 | | internal CylinderPolytopeFrame(Fixed64 height, Fixed64 radius, Signed320 coordinateDenominator) |
| | | 27 | | { |
| | 120 | 28 | | this = default; |
| | 120 | 29 | | CoordinateDenominator = coordinateDenominator; |
| | 120 | 30 | | Cap = Signed320.NarrowValue(WideArithmetic.MultiplySigned320(coordinateDenominator, Signed320.ExtendValue(Signed |
| | 120 | 31 | | Radius = WideArithmetic.AddSigned192(Signed192.Raw(radius), Signed192.Raw(radius)); |
| | 120 | 32 | | HasExactScale = !Signed192.TryNarrowSigned(coordinateDenominator, out Signed192 denominator); |
| | 120 | 33 | | if (HasExactScale) |
| | | 34 | | { |
| | 5 | 35 | | Basis = new WideRationalBasis3d(FixedQuaternion.Identity); |
| | 5 | 36 | | Denominator = Signed192.Signed(1); |
| | 5 | 37 | | _sourceFrame = ScaledRigidFrame3d.Rigid(Vector3d.Zero, FixedQuaternion.Identity); |
| | 5 | 38 | | _cylinderRotation = FixedQuaternion.Identity; |
| | | 39 | | } |
| | | 40 | | else |
| | | 41 | | { |
| | 115 | 42 | | Denominator = denominator; |
| | 115 | 43 | | Basis = WideRationalBasis3d.ScaledIdentity(denominator); |
| | | 44 | | } |
| | 115 | 45 | | } |
| | | 46 | | |
| | | 47 | | internal CylinderPolytopeFrame(Vector3d cylinderCenter, FixedQuaternion cylinderRotation, |
| | | 48 | | Fixed64 height, Fixed64 radius, Vector3d origin, FixedQuaternion rotation) |
| | 4110 | 49 | | : this(cylinderCenter, cylinderRotation, Signed192.Raw(height), radius, origin, rotation) |
| | | 50 | | { |
| | 4110 | 51 | | } |
| | | 52 | | |
| | | 53 | | internal CylinderPolytopeFrame(Vector3d cylinderCenter, FixedQuaternion cylinderRotation, |
| | | 54 | | Signed192 height, Fixed64 radius, Vector3d origin, FixedQuaternion rotation) |
| | | 55 | | { |
| | 4788 | 56 | | this = default; |
| | 4788 | 57 | | WideRationalBasis3d cylinderBasis = new(cylinderRotation); |
| | 4788 | 58 | | WideRationalBasis3d shapeBasis = new(rotation); |
| | 4788 | 59 | | Basis = WideRationalBasis3d.CreateRelative(cylinderBasis, shapeBasis); |
| | 4788 | 60 | | Denominator = Basis.Denominator; |
| | 4788 | 61 | | CoordinateDenominator = Signed320.ExtendValue(Denominator); |
| | 4788 | 62 | | WideOrientedBox.GetRelativeLocalPointNumerators(origin, cylinderCenter, cylinderBasis, |
| | 4788 | 63 | | out Signed192 x, out Signed192 y, out Signed192 z); |
| | 4788 | 64 | | Translation = new WideAxis3( |
| | 4788 | 65 | | WideArithmetic.MultiplySigned192(x, shapeBasis.Denominator), |
| | 4788 | 66 | | WideArithmetic.MultiplySigned192(y, shapeBasis.Denominator), |
| | 4788 | 67 | | WideArithmetic.MultiplySigned192(z, shapeBasis.Denominator)); |
| | | 68 | | // Work with doubled cylinder-local coordinates so odd raw full |
| | | 69 | | // heights need no rounded half-height. All vertices share D. |
| | 4788 | 70 | | Cap = WideArithmetic.MultiplySigned192(height, Denominator); |
| | 4788 | 71 | | Radius = WideArithmetic.AddSigned192(Signed192.Raw(radius), Signed192.Raw(radius)); |
| | 4788 | 72 | | } |
| | | 73 | | |
| | | 74 | | /// <summary> |
| | | 75 | | /// Retains an affine source for finite near-field geometry. Callers admit |
| | | 76 | | /// source/target reach at most 4096 and relative coordinates at most 16384. |
| | | 77 | | /// </summary> |
| | | 78 | | internal CylinderPolytopeFrame(in ScaledRigidFrame3d sourceFrame, |
| | | 79 | | Vector3d cylinderCenter, FixedQuaternion cylinderRotation, Signed192 height, Fixed64 radius) |
| | | 80 | | { |
| | | 81 | | // Finite-section and triangle owners dispatch rigid source frames |
| | | 82 | | // before reaching this affine arithmetic owner. |
| | 813 | 83 | | this = default; |
| | 813 | 84 | | _sourceFrame = sourceFrame; |
| | 813 | 85 | | _cylinderCenter = cylinderCenter; |
| | 813 | 86 | | _cylinderRotation = cylinderRotation; |
| | 813 | 87 | | HasExactScale = true; |
| | 813 | 88 | | WideRationalBasis3d cylinderBasis = new(cylinderRotation); |
| | 813 | 89 | | Basis = WideRationalBasis3d.CreateRelative(cylinderBasis, sourceFrame.GeometryBasis); |
| | 813 | 90 | | CoordinateDenominator = Signed320.NarrowValue( |
| | 813 | 91 | | WideArithmetic.MultiplySigned320(sourceFrame.Denominator, cylinderBasis.Denominator)); |
| | 813 | 92 | | Cap = Signed320.NarrowValue(WideArithmetic.MultiplySigned320(CoordinateDenominator, height)); |
| | 813 | 93 | | Radius = WideArithmetic.AddSigned192(Signed192.Raw(radius), Signed192.Raw(radius)); |
| | 813 | 94 | | } |
| | | 95 | | |
| | | 96 | | internal WideAxis3 Transform(Vector3d point) |
| | | 97 | | { |
| | 495035 | 98 | | if (HasExactScale) |
| | | 99 | | { |
| | | 100 | | // Existing affine sources are nonrigid. The local identity chart |
| | | 101 | | // retains a wider rational denominator without changing its mapping. |
| | 148842 | 102 | | if (_sourceFrame.IsRigid) |
| | | 103 | | { |
| | 17 | 104 | | Signed320 chartX = Signed320.NarrowValue(WideArithmetic.MultiplySigned320(CoordinateDenominator, Signed3 |
| | 17 | 105 | | Signed320 chartY = Signed320.NarrowValue(WideArithmetic.MultiplySigned320(CoordinateDenominator, Signed3 |
| | 17 | 106 | | Signed320 chartZ = Signed320.NarrowValue(WideArithmetic.MultiplySigned320(CoordinateDenominator, Signed3 |
| | 17 | 107 | | return new WideAxis3(WideArithmetic.AddSigned320(chartX, chartX), WideArithmetic.AddSigned320(chartY, ch |
| | | 108 | | } |
| | 148825 | 109 | | _sourceFrame.GetPoint(point).GetLocalPointNumerators(_cylinderCenter, _cylinderRotation, |
| | 148825 | 110 | | out Signed576 px, out Signed576 py, out Signed576 pz, out _); |
| | | 111 | | // Near-field raw coordinates <2^46 and the common denominator |
| | | 112 | | // <2^259 leave doubled numerators below 306 magnitude bits. |
| | 148825 | 113 | | return new WideAxis3(Signed320.NarrowValue(WideArithmetic.AddSigned576(px, px)), |
| | 148825 | 114 | | Signed320.NarrowValue(WideArithmetic.AddSigned576(py, py)), |
| | 148825 | 115 | | Signed320.NarrowValue(WideArithmetic.AddSigned576(pz, pz))); |
| | | 116 | | } |
| | 346193 | 117 | | WideAxis3 local = WideRigidProjection.TransformLocalAxis(Basis, |
| | 346193 | 118 | | Signed192.Raw(point.X), Signed192.Raw(point.Y), Signed192.Raw(point.Z)); |
| | 346193 | 119 | | Signed320 x = WideArithmetic.AddSigned320(local.X, Translation.X); |
| | 346193 | 120 | | Signed320 y = WideArithmetic.AddSigned320(local.Y, Translation.Y); |
| | 346193 | 121 | | Signed320 z = WideArithmetic.AddSigned320(local.Z, Translation.Z); |
| | 346193 | 122 | | return new WideAxis3(WideArithmetic.AddSigned320(x, x), |
| | 346193 | 123 | | WideArithmetic.AddSigned320(y, y), WideArithmetic.AddSigned320(z, z)); |
| | | 124 | | } |
| | | 125 | | } |