| | | 1 | | //======================================================================= |
| | | 2 | | // FixedSegment.CenteredAxis.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 | | using System; |
| | | 9 | | |
| | | 10 | | namespace FixedMathSharp.Geometry; |
| | | 11 | | |
| | | 12 | | /// <content> |
| | | 13 | | /// Contains methods for computing the distance, support, and point containment |
| | | 14 | | /// of centered 3D capsules, finite cylinders, and finite cones without narrowing their conceptual axes. |
| | | 15 | | /// </content> |
| | | 16 | | public partial struct FixedSegment |
| | | 17 | | { |
| | | 18 | | /// <summary> |
| | | 19 | | /// Returns whether two centered capsules in normalized rigid frames have |
| | | 20 | | /// strictly positive radial overlap, excluding exact tangency. |
| | | 21 | | /// </summary> |
| | | 22 | | /// <remarks> |
| | | 23 | | /// Each axis is expressed in its capsule's local frame. The exact rational |
| | | 24 | | /// quaternion rotation remains authoritative; derived rounded world axes, |
| | | 25 | | /// endpoint coordinates, and contact depths do not affect classification. |
| | | 26 | | /// Zero-length axes are points; a zero radius sum has no strict overlap. |
| | | 27 | | /// </remarks> |
| | | 28 | | public static bool DoCenteredCapsulesOverlapStrict( |
| | | 29 | | Vector3d firstCenter, |
| | | 30 | | FixedQuaternion firstRotation, |
| | | 31 | | Vector3d firstLocalAxisDirection, |
| | | 32 | | Fixed64 firstAxisLength, |
| | | 33 | | Fixed64 firstRadius, |
| | | 34 | | Vector3d secondCenter, |
| | | 35 | | FixedQuaternion secondRotation, |
| | | 36 | | Vector3d secondLocalAxisDirection, |
| | | 37 | | Fixed64 secondAxisLength, |
| | | 38 | | Fixed64 secondRadius) |
| | | 39 | | { |
| | 33 | 40 | | ValidateNormalizedRotation(firstRotation, nameof(firstRotation)); |
| | 33 | 41 | | ValidateNormalizedRotation(secondRotation, nameof(secondRotation)); |
| | 33 | 42 | | ValidateCenteredAxis(firstLocalAxisDirection, firstAxisLength, |
| | 33 | 43 | | nameof(firstLocalAxisDirection), nameof(firstAxisLength)); |
| | 33 | 44 | | if (firstRadius < Fixed64.Zero) |
| | 1 | 45 | | throw new ArgumentOutOfRangeException(nameof(firstRadius)); |
| | 32 | 46 | | ValidateCenteredAxis(secondLocalAxisDirection, secondAxisLength, |
| | 32 | 47 | | nameof(secondLocalAxisDirection), nameof(secondAxisLength)); |
| | 32 | 48 | | if (secondRadius < Fixed64.Zero) |
| | 1 | 49 | | throw new ArgumentOutOfRangeException(nameof(secondRadius)); |
| | | 50 | | |
| | 31 | 51 | | return WideOrientedBox.DoCenteredRigidCapsulesOverlap( |
| | 31 | 52 | | firstCenter, firstRotation, firstLocalAxisDirection, firstAxisLength, firstRadius, |
| | 31 | 53 | | secondCenter, secondRotation, secondLocalAxisDirection, secondAxisLength, secondRadius, |
| | 31 | 54 | | strict: true); |
| | | 55 | | } |
| | | 56 | | |
| | | 57 | | /// <summary> |
| | | 58 | | /// Returns whether the exact distance between two centered capsule axes is |
| | | 59 | | /// strictly less than their radius sum. Exact tangency is excluded. |
| | | 60 | | /// </summary> |
| | | 61 | | /// <remarks> |
| | | 62 | | /// Classification precedes endpoint, distance, and contact-depth rounding. |
| | | 63 | | /// Zero-length axes are points; a zero radius sum has no strict overlap. |
| | | 64 | | /// </remarks> |
| | | 65 | | public static bool DoCenteredCapsulesOverlapStrict( |
| | | 66 | | Vector3d firstCenter, |
| | | 67 | | Vector3d firstAxisDirection, |
| | | 68 | | Fixed64 firstAxisLength, |
| | | 69 | | Fixed64 firstRadius, |
| | | 70 | | Vector3d secondCenter, |
| | | 71 | | Vector3d secondAxisDirection, |
| | | 72 | | Fixed64 secondAxisLength, |
| | | 73 | | Fixed64 secondRadius) |
| | | 74 | | { |
| | 332 | 75 | | ValidateCenteredAxis(firstAxisDirection, firstAxisLength, |
| | 332 | 76 | | nameof(firstAxisDirection), nameof(firstAxisLength)); |
| | 332 | 77 | | if (firstRadius < Fixed64.Zero) |
| | 2 | 78 | | throw new ArgumentOutOfRangeException(nameof(firstRadius)); |
| | 330 | 79 | | ValidateCenteredAxis(secondAxisDirection, secondAxisLength, |
| | 330 | 80 | | nameof(secondAxisDirection), nameof(secondAxisLength)); |
| | 330 | 81 | | if (secondRadius < Fixed64.Zero) |
| | 1 | 82 | | throw new ArgumentOutOfRangeException(nameof(secondRadius)); |
| | | 83 | | |
| | 329 | 84 | | return WideFiniteAxisIntersection.DoCenteredCapsulesOverlap( |
| | 329 | 85 | | firstCenter, firstAxisDirection, firstAxisLength, firstRadius, |
| | 329 | 86 | | secondCenter, secondAxisDirection, secondAxisLength, secondRadius, |
| | 329 | 87 | | strict: true); |
| | | 88 | | } |
| | | 89 | | |
| | | 90 | | /// <summary> |
| | | 91 | | /// Attempts to return the rounded distance from a point to a conceptual |
| | | 92 | | /// centered finite axis without materializing its endpoints. |
| | | 93 | | /// </summary> |
| | | 94 | | /// <returns> |
| | | 95 | | /// True when the final distance is representable; otherwise false and |
| | | 96 | | /// <paramref name="distance"/> is <see cref="Fixed64.MaxValue"/>. |
| | | 97 | | /// </returns> |
| | | 98 | | public static bool TryGetDistanceToCenteredAxis( |
| | | 99 | | Vector3d point, |
| | | 100 | | Vector3d center, |
| | | 101 | | Vector3d axisDirection, |
| | | 102 | | Fixed64 axisLength, |
| | | 103 | | out Fixed64 distance) |
| | | 104 | | { |
| | 3 | 105 | | ValidateCenteredAxis(axisDirection, axisLength); |
| | 3 | 106 | | return WideFiniteAxisIntersection.TryGetDistanceToCenteredAxis( |
| | 3 | 107 | | point, |
| | 3 | 108 | | center, |
| | 3 | 109 | | axisDirection, |
| | 3 | 110 | | axisLength, |
| | 3 | 111 | | out distance); |
| | | 112 | | } |
| | | 113 | | |
| | | 114 | | /// <summary> |
| | | 115 | | /// Attempts to return the rounded distance between two conceptual |
| | | 116 | | /// centered finite axes without materializing either pair of endpoints. |
| | | 117 | | /// </summary> |
| | | 118 | | /// <returns> |
| | | 119 | | /// True when the final distance is representable; otherwise false and |
| | | 120 | | /// <paramref name="distance"/> is <see cref="Fixed64.MaxValue"/>. |
| | | 121 | | /// </returns> |
| | | 122 | | public static bool TryGetDistanceBetweenCenteredAxes( |
| | | 123 | | Vector3d firstCenter, |
| | | 124 | | Vector3d firstAxisDirection, |
| | | 125 | | Fixed64 firstAxisLength, |
| | | 126 | | Vector3d secondCenter, |
| | | 127 | | Vector3d secondAxisDirection, |
| | | 128 | | Fixed64 secondAxisLength, |
| | | 129 | | out Fixed64 distance) |
| | | 130 | | { |
| | 263 | 131 | | ValidateCenteredAxis( |
| | 263 | 132 | | firstAxisDirection, |
| | 263 | 133 | | firstAxisLength, |
| | 263 | 134 | | nameof(firstAxisDirection), |
| | 263 | 135 | | nameof(firstAxisLength)); |
| | 263 | 136 | | ValidateCenteredAxis( |
| | 263 | 137 | | secondAxisDirection, |
| | 263 | 138 | | secondAxisLength, |
| | 263 | 139 | | nameof(secondAxisDirection), |
| | 263 | 140 | | nameof(secondAxisLength)); |
| | 263 | 141 | | return WideFiniteAxisIntersection.TryGetDistanceBetweenCenteredAxes( |
| | 263 | 142 | | firstCenter, |
| | 263 | 143 | | firstAxisDirection, |
| | 263 | 144 | | firstAxisLength, |
| | 263 | 145 | | secondCenter, |
| | 263 | 146 | | secondAxisDirection, |
| | 263 | 147 | | secondAxisLength, |
| | 263 | 148 | | out distance); |
| | | 149 | | } |
| | | 150 | | |
| | | 151 | | /// <summary> |
| | | 152 | | /// Returns whether two conceptual centered capsules overlap, including |
| | | 153 | | /// exact tangency, without narrowing their axis distance or radius sum. |
| | | 154 | | /// </summary> |
| | | 155 | | public static bool DoCenteredCapsulesOverlap( |
| | | 156 | | Vector3d firstCenter, |
| | | 157 | | Vector3d firstAxisDirection, |
| | | 158 | | Fixed64 firstAxisLength, |
| | | 159 | | Fixed64 firstRadius, |
| | | 160 | | Vector3d secondCenter, |
| | | 161 | | Vector3d secondAxisDirection, |
| | | 162 | | Fixed64 secondAxisLength, |
| | | 163 | | Fixed64 secondRadius) |
| | | 164 | | { |
| | 262 | 165 | | ValidateCenteredAxis( |
| | 262 | 166 | | firstAxisDirection, |
| | 262 | 167 | | firstAxisLength, |
| | 262 | 168 | | nameof(firstAxisDirection), |
| | 262 | 169 | | nameof(firstAxisLength)); |
| | 262 | 170 | | if (firstRadius < Fixed64.Zero) |
| | 1 | 171 | | throw new ArgumentOutOfRangeException(nameof(firstRadius)); |
| | 261 | 172 | | ValidateCenteredAxis( |
| | 261 | 173 | | secondAxisDirection, |
| | 261 | 174 | | secondAxisLength, |
| | 261 | 175 | | nameof(secondAxisDirection), |
| | 261 | 176 | | nameof(secondAxisLength)); |
| | 261 | 177 | | if (secondRadius < Fixed64.Zero) |
| | 1 | 178 | | throw new ArgumentOutOfRangeException(nameof(secondRadius)); |
| | | 179 | | |
| | 260 | 180 | | return WideFiniteAxisIntersection.DoCenteredCapsulesOverlap( |
| | 260 | 181 | | firstCenter, |
| | 260 | 182 | | firstAxisDirection, |
| | 260 | 183 | | firstAxisLength, |
| | 260 | 184 | | firstRadius, |
| | 260 | 185 | | secondCenter, |
| | 260 | 186 | | secondAxisDirection, |
| | 260 | 187 | | secondAxisLength, |
| | 260 | 188 | | secondRadius); |
| | | 189 | | } |
| | | 190 | | |
| | | 191 | | /// <summary> |
| | | 192 | | /// Attempts to materialize one endpoint of a conceptual centered finite |
| | | 193 | | /// axis from its normalized direction and full length. |
| | | 194 | | /// </summary> |
| | | 195 | | /// <remarks> |
| | | 196 | | /// The endpoint is rounded only after combining its center and half-length |
| | | 197 | | /// contribution. Failure is atomic. |
| | | 198 | | /// </remarks> |
| | | 199 | | public static bool TryGetCenteredAxisEndpoint( |
| | | 200 | | Vector3d center, |
| | | 201 | | Vector3d axisDirection, |
| | | 202 | | Fixed64 axisLength, |
| | | 203 | | bool positive, |
| | | 204 | | out Vector3d endpoint) |
| | | 205 | | { |
| | 267 | 206 | | ValidateCenteredAxis(axisDirection, axisLength); |
| | 265 | 207 | | return WideFiniteAxisIntersection.TryGetCenteredAxisEndpoint( |
| | 265 | 208 | | center, |
| | 265 | 209 | | axisDirection, |
| | 265 | 210 | | axisLength, |
| | 265 | 211 | | positive, |
| | 265 | 212 | | out endpoint); |
| | | 213 | | } |
| | | 214 | | |
| | | 215 | | /// <summary> |
| | | 216 | | /// Attempts to materialize the support point of a conceptual centered |
| | | 217 | | /// capsule in a world-space direction. |
| | | 218 | | /// </summary> |
| | | 219 | | /// <remarks> |
| | | 220 | | /// The direction need not be normalized. A zero direction and an exact |
| | | 221 | | /// axial tie select the axis center. |
| | | 222 | | /// </remarks> |
| | | 223 | | public static bool TryGetCenteredCapsuleSupport( |
| | | 224 | | Vector3d center, |
| | | 225 | | Vector3d axisDirection, |
| | | 226 | | Fixed64 axisLength, |
| | | 227 | | Fixed64 radius, |
| | | 228 | | Vector3d direction, |
| | | 229 | | out Vector3d support) |
| | | 230 | | { |
| | 268 | 231 | | ValidateCenteredAxis(axisDirection, axisLength); |
| | 268 | 232 | | if (radius < Fixed64.Zero) |
| | 1 | 233 | | throw new ArgumentOutOfRangeException(nameof(radius)); |
| | | 234 | | |
| | 267 | 235 | | return WideFiniteAxisIntersection.TryGetCenteredCapsuleSupport( |
| | 267 | 236 | | center, |
| | 267 | 237 | | axisDirection, |
| | 267 | 238 | | axisLength, |
| | 267 | 239 | | radius, |
| | 267 | 240 | | direction, |
| | 267 | 241 | | out support); |
| | | 242 | | } |
| | | 243 | | |
| | | 244 | | /// <summary> |
| | | 245 | | /// Attempts to return the support offset of a conceptual centered capsule |
| | | 246 | | /// relative to its center. |
| | | 247 | | /// </summary> |
| | | 248 | | /// <remarks> |
| | | 249 | | /// The direction need not be normalized. A zero direction and an exact |
| | | 250 | | /// axial tie select the axis center. |
| | | 251 | | /// </remarks> |
| | | 252 | | public static bool TryGetCenteredCapsuleSupportOffset( |
| | | 253 | | Vector3d axisDirection, |
| | | 254 | | Fixed64 axisLength, |
| | | 255 | | Fixed64 radius, |
| | | 256 | | Vector3d direction, |
| | | 257 | | out Vector3d supportOffset) |
| | | 258 | | { |
| | 2 | 259 | | ValidateCenteredAxis(axisDirection, axisLength); |
| | 2 | 260 | | if (radius < Fixed64.Zero) |
| | 1 | 261 | | throw new ArgumentOutOfRangeException(nameof(radius)); |
| | | 262 | | |
| | 1 | 263 | | return WideFiniteAxisIntersection.TryGetCenteredCapsuleSupport( |
| | 1 | 264 | | Vector3d.Zero, |
| | 1 | 265 | | axisDirection, |
| | 1 | 266 | | axisLength, |
| | 1 | 267 | | radius, |
| | 1 | 268 | | direction, |
| | 1 | 269 | | out supportOffset); |
| | | 270 | | } |
| | | 271 | | |
| | | 272 | | /// <summary> |
| | | 273 | | /// Returns the support anchor of a centered capsule whose local positive Y |
| | | 274 | | /// axis is its conceptual center axis. |
| | | 275 | | /// </summary> |
| | | 276 | | /// <remarks> |
| | | 277 | | /// The rigid frame remains authoritative, so support construction does not |
| | | 278 | | /// feed the rounded derived world axis back into the geometry. The |
| | | 279 | | /// direction need not be normalized. A zero direction and an exact axial |
| | | 280 | | /// tie select the axis center. |
| | | 281 | | /// </remarks> |
| | | 282 | | public static FixedPointAnchor GetCenteredCapsuleSupportAnchor( |
| | | 283 | | Vector3d center, |
| | | 284 | | FixedQuaternion rotation, |
| | | 285 | | Fixed64 axisLength, |
| | | 286 | | Fixed64 radius, |
| | | 287 | | Vector3d direction) |
| | | 288 | | { |
| | 9 | 289 | | if (!rotation.IsNormalized()) |
| | | 290 | | { |
| | 1 | 291 | | throw new ArgumentException( |
| | 1 | 292 | | "Capsule rotation must be normalized.", |
| | 1 | 293 | | nameof(rotation)); |
| | | 294 | | } |
| | 8 | 295 | | if (axisLength < Fixed64.Zero) |
| | 1 | 296 | | throw new ArgumentOutOfRangeException(nameof(axisLength)); |
| | 7 | 297 | | if (radius < Fixed64.Zero) |
| | 1 | 298 | | throw new ArgumentOutOfRangeException(nameof(radius)); |
| | | 299 | | |
| | 6 | 300 | | return WideGeometry.GetCenteredCapsuleSupportAnchor( |
| | 6 | 301 | | center, |
| | 6 | 302 | | rotation, |
| | 6 | 303 | | axisLength, |
| | 6 | 304 | | radius, |
| | 6 | 305 | | direction); |
| | | 306 | | } |
| | | 307 | | |
| | | 308 | | /// <summary> |
| | | 309 | | /// Attempts to materialize the support point of a conceptual centered |
| | | 310 | | /// finite cylinder in a world-space direction. |
| | | 311 | | /// </summary> |
| | | 312 | | /// <remarks> |
| | | 313 | | /// The direction need not be normalized. A zero direction and an exact |
| | | 314 | | /// axial tie select the negative cap center. A direction parallel to the |
| | | 315 | | /// axis selects the cap center rather than an arbitrary rim point. |
| | | 316 | | /// </remarks> |
| | | 317 | | public static bool TryGetCenteredFiniteCylinderSupport( |
| | | 318 | | Vector3d center, |
| | | 319 | | Vector3d axisDirection, |
| | | 320 | | Fixed64 axisLength, |
| | | 321 | | Fixed64 radius, |
| | | 322 | | Vector3d direction, |
| | | 323 | | out Vector3d support) |
| | | 324 | | { |
| | 266 | 325 | | if (!axisDirection.IsNormalized()) |
| | 1 | 326 | | throw new ArgumentException("Finite cylinder axis direction must be normalized.", nameof(axisDirection)); |
| | 265 | 327 | | if (axisLength <= Fixed64.Zero) |
| | 1 | 328 | | throw new ArgumentOutOfRangeException(nameof(axisLength)); |
| | 264 | 329 | | if (radius < Fixed64.Zero) |
| | 1 | 330 | | throw new ArgumentOutOfRangeException(nameof(radius)); |
| | | 331 | | |
| | 263 | 332 | | return WideFiniteAxisIntersection.TryGetCenteredFiniteCylinderSupport( |
| | 263 | 333 | | center, |
| | 263 | 334 | | axisDirection, |
| | 263 | 335 | | axisLength, |
| | 263 | 336 | | radius, |
| | 263 | 337 | | direction, |
| | 263 | 338 | | out support); |
| | | 339 | | } |
| | | 340 | | |
| | | 341 | | /// <summary> |
| | | 342 | | /// Attempts to return the support offset of a conceptual centered finite |
| | | 343 | | /// cylinder relative to its center. |
| | | 344 | | /// </summary> |
| | | 345 | | public static bool TryGetCenteredFiniteCylinderSupportOffset( |
| | | 346 | | Vector3d axisDirection, |
| | | 347 | | Fixed64 axisLength, |
| | | 348 | | Fixed64 radius, |
| | | 349 | | Vector3d direction, |
| | | 350 | | out Vector3d supportOffset) |
| | | 351 | | { |
| | 4 | 352 | | if (!axisDirection.IsNormalized()) |
| | 1 | 353 | | throw new ArgumentException("Finite cylinder axis direction must be normalized.", nameof(axisDirection)); |
| | 3 | 354 | | if (axisLength <= Fixed64.Zero) |
| | 1 | 355 | | throw new ArgumentOutOfRangeException(nameof(axisLength)); |
| | 2 | 356 | | if (radius < Fixed64.Zero) |
| | 1 | 357 | | throw new ArgumentOutOfRangeException(nameof(radius)); |
| | | 358 | | |
| | 1 | 359 | | return WideFiniteAxisIntersection.TryGetCenteredFiniteCylinderSupport( |
| | 1 | 360 | | Vector3d.Zero, |
| | 1 | 361 | | axisDirection, |
| | 1 | 362 | | axisLength, |
| | 1 | 363 | | radius, |
| | 1 | 364 | | direction, |
| | 1 | 365 | | out supportOffset); |
| | | 366 | | } |
| | | 367 | | |
| | | 368 | | /// <summary> |
| | | 369 | | /// Returns the support anchor of a centered finite cylinder whose local |
| | | 370 | | /// positive Y axis is its conceptual center axis. |
| | | 371 | | /// </summary> |
| | | 372 | | /// <remarks> |
| | | 373 | | /// The rigid frame remains authoritative. Axial full-length/2 and radial |
| | | 374 | | /// direction-times-radius terms remain exact through final world-point or |
| | | 375 | | /// relative-offset materialization. |
| | | 376 | | /// </remarks> |
| | | 377 | | public static FixedPointAnchor GetCenteredFiniteCylinderSupportAnchor( |
| | | 378 | | Vector3d center, |
| | | 379 | | FixedQuaternion rotation, |
| | | 380 | | Fixed64 axisLength, |
| | | 381 | | Fixed64 radius, |
| | | 382 | | Vector3d direction) |
| | | 383 | | { |
| | 10 | 384 | | if (!rotation.IsNormalized()) |
| | | 385 | | { |
| | 1 | 386 | | throw new ArgumentException( |
| | 1 | 387 | | "Finite cylinder rotation must be normalized.", |
| | 1 | 388 | | nameof(rotation)); |
| | | 389 | | } |
| | 9 | 390 | | if (axisLength <= Fixed64.Zero) |
| | 1 | 391 | | throw new ArgumentOutOfRangeException(nameof(axisLength)); |
| | 8 | 392 | | if (radius < Fixed64.Zero) |
| | 1 | 393 | | throw new ArgumentOutOfRangeException(nameof(radius)); |
| | | 394 | | |
| | 7 | 395 | | return WideGeometry.GetCenteredCylinderSupportAnchor( |
| | 7 | 396 | | center, |
| | 7 | 397 | | rotation, |
| | 7 | 398 | | axisLength, |
| | 7 | 399 | | radius, |
| | 7 | 400 | | direction); |
| | | 401 | | } |
| | | 402 | | |
| | | 403 | | /// <summary> |
| | | 404 | | /// Attempts to materialize the support point of a conceptual centered |
| | | 405 | | /// finite cone in a world-space direction. |
| | | 406 | | /// </summary> |
| | | 407 | | /// <remarks> |
| | | 408 | | /// The axis points from the base toward the apex. The direction need not |
| | | 409 | | /// be normalized. Equal apex and base projections, including a zero |
| | | 410 | | /// direction, select the base. |
| | | 411 | | /// </remarks> |
| | | 412 | | public static bool TryGetCenteredFiniteConeSupport( |
| | | 413 | | Vector3d center, |
| | | 414 | | Vector3d axisDirection, |
| | | 415 | | Fixed64 height, |
| | | 416 | | Fixed64 radius, |
| | | 417 | | Vector3d direction, |
| | | 418 | | out Vector3d support) |
| | | 419 | | { |
| | 265 | 420 | | if (!axisDirection.IsNormalized()) |
| | 1 | 421 | | throw new ArgumentException("Finite cone axis direction must be normalized.", nameof(axisDirection)); |
| | 264 | 422 | | if (height <= Fixed64.Zero) |
| | 1 | 423 | | throw new ArgumentOutOfRangeException(nameof(height)); |
| | 263 | 424 | | if (radius < Fixed64.Zero) |
| | 1 | 425 | | throw new ArgumentOutOfRangeException(nameof(radius)); |
| | | 426 | | |
| | 262 | 427 | | return WideFiniteAxisIntersection.TryGetCenteredFiniteConeSupport( |
| | 262 | 428 | | center, |
| | 262 | 429 | | axisDirection, |
| | 262 | 430 | | height, |
| | 262 | 431 | | radius, |
| | 262 | 432 | | direction, |
| | 262 | 433 | | out support); |
| | | 434 | | } |
| | | 435 | | |
| | | 436 | | /// <summary> |
| | | 437 | | /// Attempts to return the support offset of a conceptual centered finite |
| | | 438 | | /// cone relative to its center. |
| | | 439 | | /// </summary> |
| | | 440 | | public static bool TryGetCenteredFiniteConeSupportOffset( |
| | | 441 | | Vector3d axisDirection, |
| | | 442 | | Fixed64 height, |
| | | 443 | | Fixed64 radius, |
| | | 444 | | Vector3d direction, |
| | | 445 | | out Vector3d supportOffset) |
| | | 446 | | { |
| | 4 | 447 | | if (!axisDirection.IsNormalized()) |
| | 1 | 448 | | throw new ArgumentException("Finite cone axis direction must be normalized.", nameof(axisDirection)); |
| | 3 | 449 | | if (height <= Fixed64.Zero) |
| | 1 | 450 | | throw new ArgumentOutOfRangeException(nameof(height)); |
| | 2 | 451 | | if (radius < Fixed64.Zero) |
| | 1 | 452 | | throw new ArgumentOutOfRangeException(nameof(radius)); |
| | | 453 | | |
| | 1 | 454 | | return WideFiniteAxisIntersection.TryGetCenteredFiniteConeSupport( |
| | 1 | 455 | | Vector3d.Zero, |
| | 1 | 456 | | axisDirection, |
| | 1 | 457 | | height, |
| | 1 | 458 | | radius, |
| | 1 | 459 | | direction, |
| | 1 | 460 | | out supportOffset); |
| | | 461 | | } |
| | | 462 | | |
| | | 463 | | /// <summary> |
| | | 464 | | /// Returns the support point of a centered finite cone as a local point in |
| | | 465 | | /// its rigid frame without materializing an absolute world coordinate. |
| | | 466 | | /// </summary> |
| | | 467 | | /// <remarks> |
| | | 468 | | /// The cone's local positive Y axis points from the base toward the apex. |
| | | 469 | | /// The direction need not be normalized. Equal apex and base projections, |
| | | 470 | | /// including a zero direction, select the base. |
| | | 471 | | /// </remarks> |
| | | 472 | | public static FixedPointAnchor GetCenteredFiniteConeSupportAnchor( |
| | | 473 | | Vector3d center, |
| | | 474 | | FixedQuaternion rotation, |
| | | 475 | | Fixed64 height, |
| | | 476 | | Fixed64 radius, |
| | | 477 | | Vector3d direction) |
| | | 478 | | { |
| | 6 | 479 | | if (!rotation.IsNormalized()) |
| | | 480 | | { |
| | 1 | 481 | | throw new ArgumentException( |
| | 1 | 482 | | "Finite cone rotation must be normalized.", |
| | 1 | 483 | | nameof(rotation)); |
| | | 484 | | } |
| | 5 | 485 | | if (height <= Fixed64.Zero) |
| | 1 | 486 | | throw new ArgumentOutOfRangeException(nameof(height)); |
| | 4 | 487 | | if (radius < Fixed64.Zero) |
| | 1 | 488 | | throw new ArgumentOutOfRangeException(nameof(radius)); |
| | | 489 | | |
| | 3 | 490 | | return WideGeometry.GetCenteredConeSupportAnchor( |
| | 3 | 491 | | center, |
| | 3 | 492 | | rotation, |
| | 3 | 493 | | height, |
| | 3 | 494 | | radius, |
| | 3 | 495 | | direction); |
| | | 496 | | } |
| | | 497 | | |
| | | 498 | | /// <summary> |
| | | 499 | | /// Returns the support point of a centered finite cone in a deterministic |
| | | 500 | | /// canonical axis frame without materializing an absolute world |
| | | 501 | | /// coordinate. |
| | | 502 | | /// </summary> |
| | | 503 | | public static FixedPointAnchor GetCenteredFiniteConeSupportAnchor( |
| | | 504 | | Vector3d center, |
| | | 505 | | Vector3d axisDirection, |
| | | 506 | | Fixed64 height, |
| | | 507 | | Fixed64 radius, |
| | | 508 | | Vector3d direction) |
| | | 509 | | { |
| | 6 | 510 | | if (!axisDirection.IsNormalized()) |
| | | 511 | | { |
| | 1 | 512 | | throw new ArgumentException( |
| | 1 | 513 | | "Finite cone axis direction must be normalized.", |
| | 1 | 514 | | nameof(axisDirection)); |
| | | 515 | | } |
| | 5 | 516 | | if (height <= Fixed64.Zero) |
| | 1 | 517 | | throw new ArgumentOutOfRangeException(nameof(height)); |
| | 4 | 518 | | if (radius < Fixed64.Zero) |
| | 1 | 519 | | throw new ArgumentOutOfRangeException(nameof(radius)); |
| | | 520 | | |
| | 3 | 521 | | FixedQuaternion rotation = |
| | 3 | 522 | | WideGeometry.GetCanonicalAxisRotation(axisDirection); |
| | 3 | 523 | | return WideGeometry.GetCenteredConeSupportAnchor( |
| | 3 | 524 | | center, |
| | 3 | 525 | | rotation, |
| | 3 | 526 | | height, |
| | 3 | 527 | | radius, |
| | 3 | 528 | | direction); |
| | | 529 | | } |
| | | 530 | | |
| | | 531 | | /// <summary> |
| | | 532 | | /// Returns whether a point lies in a centered finite cylinder whose flat |
| | | 533 | | /// caps are defined without constructing scalar coordinates. |
| | | 534 | | /// </summary> |
| | | 535 | | /// <param name="point">The point to classify.</param> |
| | | 536 | | /// <param name="center">The cylinder center.</param> |
| | | 537 | | /// <param name="axisDirection">The normalized cap-normal direction.</param> |
| | | 538 | | /// <param name="axisLength">The positive full physical axis length.</param> |
| | | 539 | | /// <param name="radius">The nonnegative radial extent.</param> |
| | | 540 | | /// <param name="strict"> |
| | | 541 | | /// <see langword="true"/> to exclude the side and both flat caps; |
| | | 542 | | /// otherwise, boundaries are included. |
| | | 543 | | /// </param> |
| | | 544 | | /// <exception cref="ArgumentException"> |
| | | 545 | | /// <paramref name="axisDirection"/> is zero or not normalized. |
| | | 546 | | /// </exception> |
| | | 547 | | /// <exception cref="ArgumentOutOfRangeException"> |
| | | 548 | | /// <paramref name="axisLength"/> is not positive or |
| | | 549 | | /// <paramref name="radius"/> is negative. |
| | | 550 | | /// </exception> |
| | | 551 | | public static bool ContainsPointInCenteredFiniteCylinder( |
| | | 552 | | Vector3d point, |
| | | 553 | | Vector3d center, |
| | | 554 | | Vector3d axisDirection, |
| | | 555 | | Fixed64 axisLength, |
| | | 556 | | Fixed64 radius, |
| | | 557 | | bool strict = false) |
| | | 558 | | { |
| | 13 | 559 | | if (!axisDirection.IsNormalized()) |
| | 1 | 560 | | throw new ArgumentException("Finite cylinder axis direction must be normalized.", nameof(axisDirection)); |
| | 12 | 561 | | if (axisLength <= Fixed64.Zero) |
| | 1 | 562 | | throw new ArgumentOutOfRangeException(nameof(axisLength)); |
| | 11 | 563 | | if (radius < Fixed64.Zero) |
| | 1 | 564 | | throw new ArgumentOutOfRangeException(nameof(radius)); |
| | | 565 | | |
| | 10 | 566 | | return WideFiniteAxisIntersection.ContainsPointInCenteredFiniteCylinder( |
| | 10 | 567 | | point, |
| | 10 | 568 | | center, |
| | 10 | 569 | | axisDirection, |
| | 10 | 570 | | axisLength, |
| | 10 | 571 | | radius, |
| | 10 | 572 | | strict); |
| | | 573 | | } |
| | | 574 | | |
| | | 575 | | /// <summary> |
| | | 576 | | /// Returns whether a point lies in a centered finite cylinder after |
| | | 577 | | /// independently expanding its flat caps and radial side. |
| | | 578 | | /// </summary> |
| | | 579 | | /// <param name="point">The point to classify.</param> |
| | | 580 | | /// <param name="center">The cylinder center.</param> |
| | | 581 | | /// <param name="axisDirection">The normalized cylinder axis.</param> |
| | | 582 | | /// <param name="axisLength">The positive full cylinder length.</param> |
| | | 583 | | /// <param name="radius">The nonnegative cylinder radius.</param> |
| | | 584 | | /// <param name="axialTolerance"> |
| | | 585 | | /// The nonnegative distance added beyond each flat cap. |
| | | 586 | | /// </param> |
| | | 587 | | /// <param name="radialTolerance"> |
| | | 588 | | /// The nonnegative distance added to the radial extent. |
| | | 589 | | /// </param> |
| | | 590 | | /// <param name="strict"> |
| | | 591 | | /// <see langword="true"/> to exclude every expanded boundary. |
| | | 592 | | /// </param> |
| | | 593 | | public static bool ContainsPointInCenteredFiniteCylinder( |
| | | 594 | | Vector3d point, |
| | | 595 | | Vector3d center, |
| | | 596 | | Vector3d axisDirection, |
| | | 597 | | Fixed64 axisLength, |
| | | 598 | | Fixed64 radius, |
| | | 599 | | Fixed64 axialTolerance, |
| | | 600 | | Fixed64 radialTolerance, |
| | | 601 | | bool strict = false) |
| | | 602 | | { |
| | 8 | 603 | | if (!axisDirection.IsNormalized()) |
| | 1 | 604 | | throw new ArgumentException("Finite cylinder axis direction must be normalized.", nameof(axisDirection)); |
| | 7 | 605 | | if (axisLength <= Fixed64.Zero) |
| | 1 | 606 | | throw new ArgumentOutOfRangeException(nameof(axisLength)); |
| | 6 | 607 | | if (radius < Fixed64.Zero) |
| | 1 | 608 | | throw new ArgumentOutOfRangeException(nameof(radius)); |
| | 5 | 609 | | if (axialTolerance < Fixed64.Zero) |
| | 1 | 610 | | throw new ArgumentOutOfRangeException(nameof(axialTolerance)); |
| | 4 | 611 | | if (radialTolerance < Fixed64.Zero) |
| | 1 | 612 | | throw new ArgumentOutOfRangeException(nameof(radialTolerance)); |
| | | 613 | | |
| | 3 | 614 | | return WideFiniteAxisIntersection.ContainsPointInCenteredFiniteCylinder( |
| | 3 | 615 | | point, |
| | 3 | 616 | | center, |
| | 3 | 617 | | axisDirection, |
| | 3 | 618 | | axisLength, |
| | 3 | 619 | | radius, |
| | 3 | 620 | | axialTolerance, |
| | 3 | 621 | | radialTolerance, |
| | 3 | 622 | | strict); |
| | | 623 | | } |
| | | 624 | | |
| | | 625 | | /// <summary> |
| | | 626 | | /// Returns the rounded nonnegative distance from a point to a conceptual |
| | | 627 | | /// centered capsule surface, saturating to <see cref="Fixed64.MaxValue"/> |
| | | 628 | | /// when the distance is not representable. |
| | | 629 | | /// </summary> |
| | | 630 | | /// <remarks> |
| | | 631 | | /// The final value uses round-half-to-even. Points inside or on the capsule |
| | | 632 | | /// return zero. |
| | | 633 | | /// </remarks> |
| | | 634 | | /// <exception cref="ArgumentException"> |
| | | 635 | | /// Thrown when <paramref name="axisDirection"/> is zero or not normalized. |
| | | 636 | | /// </exception> |
| | | 637 | | /// <exception cref="ArgumentOutOfRangeException"> |
| | | 638 | | /// Thrown when <paramref name="axisLength"/> or <paramref name="radius"/> |
| | | 639 | | /// is negative. |
| | | 640 | | /// </exception> |
| | | 641 | | public static Fixed64 GetDistanceToCenteredCapsule( |
| | | 642 | | Vector3d point, |
| | | 643 | | Vector3d center, |
| | | 644 | | Vector3d axisDirection, |
| | | 645 | | Fixed64 axisLength, |
| | | 646 | | Fixed64 radius) |
| | | 647 | | { |
| | 2 | 648 | | TryGetDistanceToCenteredCapsule( |
| | 2 | 649 | | point, |
| | 2 | 650 | | center, |
| | 2 | 651 | | axisDirection, |
| | 2 | 652 | | axisLength, |
| | 2 | 653 | | radius, |
| | 2 | 654 | | out Fixed64 distance); |
| | 2 | 655 | | return distance; |
| | | 656 | | } |
| | | 657 | | |
| | | 658 | | /// <summary> |
| | | 659 | | /// Attempts to return the rounded nonnegative distance from a point to a |
| | | 660 | | /// conceptual centered capsule surface. |
| | | 661 | | /// </summary> |
| | | 662 | | /// <remarks>The final value uses round-half-to-even.</remarks> |
| | | 663 | | /// <returns> |
| | | 664 | | /// True when the final distance is representable; otherwise false and |
| | | 665 | | /// <paramref name="distance"/> is <see cref="Fixed64.MaxValue"/>. |
| | | 666 | | /// Points inside or on the capsule return zero. |
| | | 667 | | /// </returns> |
| | | 668 | | /// <exception cref="ArgumentException"> |
| | | 669 | | /// Thrown when <paramref name="axisDirection"/> is zero or not normalized. |
| | | 670 | | /// </exception> |
| | | 671 | | /// <exception cref="ArgumentOutOfRangeException"> |
| | | 672 | | /// Thrown when <paramref name="axisLength"/> or <paramref name="radius"/> |
| | | 673 | | /// is negative. |
| | | 674 | | /// </exception> |
| | | 675 | | public static bool TryGetDistanceToCenteredCapsule( |
| | | 676 | | Vector3d point, |
| | | 677 | | Vector3d center, |
| | | 678 | | Vector3d axisDirection, |
| | | 679 | | Fixed64 axisLength, |
| | | 680 | | Fixed64 radius, |
| | | 681 | | out Fixed64 distance) |
| | | 682 | | { |
| | 5 | 683 | | ValidateCenteredAxis(axisDirection, axisLength); |
| | 5 | 684 | | if (radius < Fixed64.Zero) |
| | 1 | 685 | | throw new ArgumentOutOfRangeException(nameof(radius)); |
| | | 686 | | |
| | 4 | 687 | | return WideFiniteAxisIntersection.TryGetDistanceToCenteredCapsule( |
| | 4 | 688 | | point, |
| | 4 | 689 | | center, |
| | 4 | 690 | | axisDirection, |
| | 4 | 691 | | axisLength, |
| | 4 | 692 | | radius, |
| | 4 | 693 | | out distance); |
| | | 694 | | } |
| | | 695 | | |
| | | 696 | | /// <summary> |
| | | 697 | | /// Returns whether a point lies inside or on a conceptual centered capsule. |
| | | 698 | | /// </summary> |
| | | 699 | | /// <exception cref="ArgumentException"> |
| | | 700 | | /// Thrown when <paramref name="axisDirection"/> is zero or not normalized. |
| | | 701 | | /// </exception> |
| | | 702 | | /// <exception cref="ArgumentOutOfRangeException"> |
| | | 703 | | /// Thrown when <paramref name="axisLength"/> or <paramref name="radius"/> |
| | | 704 | | /// is negative. |
| | | 705 | | /// </exception> |
| | | 706 | | public static bool ContainsPointInCenteredCapsule( |
| | | 707 | | Vector3d point, |
| | | 708 | | Vector3d center, |
| | | 709 | | Vector3d axisDirection, |
| | | 710 | | Fixed64 axisLength, |
| | | 711 | | Fixed64 radius) => |
| | 5 | 712 | | ContainsPointInCenteredCapsule( |
| | 5 | 713 | | point, |
| | 5 | 714 | | center, |
| | 5 | 715 | | axisDirection, |
| | 5 | 716 | | axisLength, |
| | 5 | 717 | | radius, |
| | 5 | 718 | | Fixed64.Zero, |
| | 5 | 719 | | strict: false); |
| | | 720 | | |
| | | 721 | | /// <summary> |
| | | 722 | | /// Returns whether a point lies strictly inside or inclusively within a |
| | | 723 | | /// conceptual centered capsule. |
| | | 724 | | /// </summary> |
| | | 725 | | public static bool ContainsPointInCenteredCapsule( |
| | | 726 | | Vector3d point, |
| | | 727 | | Vector3d center, |
| | | 728 | | Vector3d axisDirection, |
| | | 729 | | Fixed64 axisLength, |
| | | 730 | | Fixed64 radius, |
| | | 731 | | bool strict) => |
| | 3 | 732 | | ContainsPointInCenteredCapsule( |
| | 3 | 733 | | point, |
| | 3 | 734 | | center, |
| | 3 | 735 | | axisDirection, |
| | 3 | 736 | | axisLength, |
| | 3 | 737 | | radius, |
| | 3 | 738 | | Fixed64.Zero, |
| | 3 | 739 | | strict); |
| | | 740 | | |
| | | 741 | | /// <summary> |
| | | 742 | | /// Returns whether a point lies inside or on a conceptual centered capsule, |
| | | 743 | | /// including a nonnegative radial expansion. |
| | | 744 | | /// </summary> |
| | | 745 | | /// <exception cref="ArgumentException"> |
| | | 746 | | /// Thrown when <paramref name="axisDirection"/> is zero or not normalized. |
| | | 747 | | /// </exception> |
| | | 748 | | /// <exception cref="ArgumentOutOfRangeException"> |
| | | 749 | | /// Thrown when <paramref name="axisLength"/>, <paramref name="radius"/>, |
| | | 750 | | /// or <paramref name="radiusExpansion"/> is negative. |
| | | 751 | | /// </exception> |
| | | 752 | | public static bool ContainsPointInCenteredCapsule( |
| | | 753 | | Vector3d point, |
| | | 754 | | Vector3d center, |
| | | 755 | | Vector3d axisDirection, |
| | | 756 | | Fixed64 axisLength, |
| | | 757 | | Fixed64 radius, |
| | | 758 | | Fixed64 radiusExpansion) => |
| | 2 | 759 | | ContainsPointInCenteredCapsule( |
| | 2 | 760 | | point, |
| | 2 | 761 | | center, |
| | 2 | 762 | | axisDirection, |
| | 2 | 763 | | axisLength, |
| | 2 | 764 | | radius, |
| | 2 | 765 | | radiusExpansion, |
| | 2 | 766 | | strict: false); |
| | | 767 | | |
| | | 768 | | /// <summary> |
| | | 769 | | /// Returns whether a point lies strictly inside or inclusively within a |
| | | 770 | | /// conceptual centered capsule with nonnegative radial expansion. |
| | | 771 | | /// </summary> |
| | | 772 | | public static bool ContainsPointInCenteredCapsule( |
| | | 773 | | Vector3d point, |
| | | 774 | | Vector3d center, |
| | | 775 | | Vector3d axisDirection, |
| | | 776 | | Fixed64 axisLength, |
| | | 777 | | Fixed64 radius, |
| | | 778 | | Fixed64 radiusExpansion, |
| | | 779 | | bool strict) |
| | | 780 | | { |
| | 12 | 781 | | ValidateCenteredAxis(axisDirection, axisLength); |
| | 12 | 782 | | if (radius < Fixed64.Zero) |
| | 1 | 783 | | throw new ArgumentOutOfRangeException(nameof(radius)); |
| | 11 | 784 | | if (radiusExpansion < Fixed64.Zero) |
| | 1 | 785 | | throw new ArgumentOutOfRangeException(nameof(radiusExpansion)); |
| | | 786 | | |
| | 10 | 787 | | return WideFiniteAxisIntersection.ContainsPointInCenteredCapsule( |
| | 10 | 788 | | point, |
| | 10 | 789 | | center, |
| | 10 | 790 | | axisDirection, |
| | 10 | 791 | | axisLength, |
| | 10 | 792 | | radius, |
| | 10 | 793 | | radiusExpansion, |
| | 10 | 794 | | strict); |
| | | 795 | | } |
| | | 796 | | |
| | | 797 | | /// <summary> |
| | | 798 | | /// Returns the normalized direction from the closest point on a conceptual |
| | | 799 | | /// centered finite axis toward <paramref name="point"/>, or zero when the |
| | | 800 | | /// point lies on that axis. |
| | | 801 | | /// </summary> |
| | | 802 | | /// <remarks> |
| | | 803 | | /// The conceptual endpoints are |
| | | 804 | | /// <c>center +/- axisDirection * (axisLength / 2)</c>. They are never |
| | | 805 | | /// constructed or narrowed before the closest-feature decision. |
| | | 806 | | /// </remarks> |
| | | 807 | | /// <exception cref="ArgumentException"> |
| | | 808 | | /// Thrown when <paramref name="axisDirection"/> is zero or not normalized. |
| | | 809 | | /// </exception> |
| | | 810 | | /// <exception cref="ArgumentOutOfRangeException"> |
| | | 811 | | /// Thrown when <paramref name="axisLength"/> is negative. |
| | | 812 | | /// </exception> |
| | | 813 | | public static Vector3d GetDirectionFromCenteredAxis( |
| | | 814 | | Vector3d point, |
| | | 815 | | Vector3d center, |
| | | 816 | | Vector3d axisDirection, |
| | | 817 | | Fixed64 axisLength) |
| | | 818 | | { |
| | 6 | 819 | | ValidateCenteredAxis(axisDirection, axisLength); |
| | | 820 | | |
| | 4 | 821 | | return WideFiniteAxisIntersection.GetDirectionFromCenteredAxis( |
| | 4 | 822 | | point, |
| | 4 | 823 | | center, |
| | 4 | 824 | | axisDirection, |
| | 4 | 825 | | axisLength); |
| | | 826 | | } |
| | | 827 | | |
| | | 828 | | /// <summary> |
| | | 829 | | /// Attempts to return the closest points on two conceptual centered finite |
| | | 830 | | /// axes described by normalized directions and full lengths. |
| | | 831 | | /// </summary> |
| | | 832 | | /// <returns> |
| | | 833 | | /// <see langword="true"/> when both final world points are representable; |
| | | 834 | | /// otherwise <see langword="false"/> and both outputs are zero. |
| | | 835 | | /// </returns> |
| | | 836 | | public static bool TryGetClosestPointsBetweenCenteredAxes( |
| | | 837 | | Vector3d firstCenter, |
| | | 838 | | Vector3d firstAxisDirection, |
| | | 839 | | Fixed64 firstAxisLength, |
| | | 840 | | Vector3d secondCenter, |
| | | 841 | | Vector3d secondAxisDirection, |
| | | 842 | | Fixed64 secondAxisLength, |
| | | 843 | | out Vector3d firstPoint, |
| | | 844 | | out Vector3d secondPoint) |
| | | 845 | | { |
| | 139 | 846 | | ValidateCenteredAxis( |
| | 139 | 847 | | firstAxisDirection, |
| | 139 | 848 | | firstAxisLength, |
| | 139 | 849 | | nameof(firstAxisDirection), |
| | 139 | 850 | | nameof(firstAxisLength)); |
| | 138 | 851 | | ValidateCenteredAxis( |
| | 138 | 852 | | secondAxisDirection, |
| | 138 | 853 | | secondAxisLength, |
| | 138 | 854 | | nameof(secondAxisDirection), |
| | 138 | 855 | | nameof(secondAxisLength)); |
| | 137 | 856 | | return WideFiniteAxisIntersection.TryGetClosestPointsBetweenCenteredAxes( |
| | 137 | 857 | | firstCenter, |
| | 137 | 858 | | firstAxisDirection, |
| | 137 | 859 | | firstAxisLength, |
| | 137 | 860 | | secondCenter, |
| | 137 | 861 | | secondAxisDirection, |
| | 137 | 862 | | secondAxisLength, |
| | 137 | 863 | | out firstPoint, |
| | 137 | 864 | | out secondPoint); |
| | | 865 | | } |
| | | 866 | | |
| | | 867 | | /// <summary> |
| | | 868 | | /// Attempts to return the closest offsets on two conceptual centered |
| | | 869 | | /// finite axes, each relative to its own center. |
| | | 870 | | /// </summary> |
| | | 871 | | /// <remarks> |
| | | 872 | | /// This relation remains usable when either absolute closest point would |
| | | 873 | | /// exceed the public scalar coordinate range. |
| | | 874 | | /// </remarks> |
| | | 875 | | public static bool TryGetClosestOffsetsBetweenCenteredAxes( |
| | | 876 | | Vector3d firstCenter, |
| | | 877 | | Vector3d firstAxisDirection, |
| | | 878 | | Fixed64 firstAxisLength, |
| | | 879 | | Vector3d secondCenter, |
| | | 880 | | Vector3d secondAxisDirection, |
| | | 881 | | Fixed64 secondAxisLength, |
| | | 882 | | out Vector3d firstCenterOffset, |
| | | 883 | | out Vector3d secondCenterOffset) |
| | | 884 | | { |
| | 1 | 885 | | ValidateCenteredAxis( |
| | 1 | 886 | | firstAxisDirection, |
| | 1 | 887 | | firstAxisLength, |
| | 1 | 888 | | nameof(firstAxisDirection), |
| | 1 | 889 | | nameof(firstAxisLength)); |
| | 1 | 890 | | ValidateCenteredAxis( |
| | 1 | 891 | | secondAxisDirection, |
| | 1 | 892 | | secondAxisLength, |
| | 1 | 893 | | nameof(secondAxisDirection), |
| | 1 | 894 | | nameof(secondAxisLength)); |
| | 1 | 895 | | return WideFiniteAxisIntersection.TryGetClosestOffsetsBetweenCenteredAxes( |
| | 1 | 896 | | firstCenter, |
| | 1 | 897 | | firstAxisDirection, |
| | 1 | 898 | | firstAxisLength, |
| | 1 | 899 | | secondCenter, |
| | 1 | 900 | | secondAxisDirection, |
| | 1 | 901 | | secondAxisLength, |
| | 1 | 902 | | out firstCenterOffset, |
| | 1 | 903 | | out secondCenterOffset); |
| | | 904 | | } |
| | | 905 | | |
| | | 906 | | /// <summary> |
| | | 907 | | /// Returns the normalized direction from the closest point on the first |
| | | 908 | | /// conceptual centered axis to the closest point on the second. |
| | | 909 | | /// </summary> |
| | | 910 | | /// <remarks> |
| | | 911 | | /// Coincident closest points return zero. The direction is resolved from |
| | | 912 | | /// the exact wide relation without materializing either world point. |
| | | 913 | | /// </remarks> |
| | | 914 | | public static Vector3d GetClosestDirectionBetweenCenteredAxes( |
| | | 915 | | Vector3d firstCenter, |
| | | 916 | | Vector3d firstAxisDirection, |
| | | 917 | | Fixed64 firstAxisLength, |
| | | 918 | | Vector3d secondCenter, |
| | | 919 | | Vector3d secondAxisDirection, |
| | | 920 | | Fixed64 secondAxisLength) |
| | | 921 | | { |
| | 1 | 922 | | ValidateCenteredAxis( |
| | 1 | 923 | | firstAxisDirection, |
| | 1 | 924 | | firstAxisLength, |
| | 1 | 925 | | nameof(firstAxisDirection), |
| | 1 | 926 | | nameof(firstAxisLength)); |
| | 1 | 927 | | ValidateCenteredAxis( |
| | 1 | 928 | | secondAxisDirection, |
| | 1 | 929 | | secondAxisLength, |
| | 1 | 930 | | nameof(secondAxisDirection), |
| | 1 | 931 | | nameof(secondAxisLength)); |
| | 1 | 932 | | return WideFiniteAxisIntersection.GetClosestDirectionBetweenCenteredAxes( |
| | 1 | 933 | | firstCenter, |
| | 1 | 934 | | firstAxisDirection, |
| | 1 | 935 | | firstAxisLength, |
| | 1 | 936 | | secondCenter, |
| | 1 | 937 | | secondAxisDirection, |
| | 1 | 938 | | secondAxisLength); |
| | | 939 | | } |
| | | 940 | | |
| | | 941 | | /// <summary> |
| | | 942 | | /// Attempts to build the exact contact relation between two conceptual |
| | | 943 | | /// centered capsules without narrowing either finite axis. |
| | | 944 | | /// </summary> |
| | | 945 | | /// <remarks> |
| | | 946 | | /// Each capsule axis is expressed in its normalized rigid frame. The |
| | | 947 | | /// returned normal points from the first capsule toward the second. |
| | | 948 | | /// <paramref name="fallbackNormal"/> is used only when the closest axis |
| | | 949 | | /// points coincide. Axial and radial terms remain separate in each anchor, |
| | | 950 | | /// so classification does not depend on materializing a combined world |
| | | 951 | | /// point or center-relative offset. |
| | | 952 | | /// </remarks> |
| | | 953 | | /// <returns> |
| | | 954 | | /// <see langword="true"/> when the capsules overlap; otherwise |
| | | 955 | | /// <see langword="false"/>. |
| | | 956 | | /// </returns> |
| | | 957 | | public static bool TryGetCenteredCapsulesContact( |
| | | 958 | | Vector3d firstCenter, |
| | | 959 | | FixedQuaternion firstRotation, |
| | | 960 | | Vector3d firstLocalAxisDirection, |
| | | 961 | | Fixed64 firstAxisLength, |
| | | 962 | | Fixed64 firstRadius, |
| | | 963 | | Vector3d secondCenter, |
| | | 964 | | FixedQuaternion secondRotation, |
| | | 965 | | Vector3d secondLocalAxisDirection, |
| | | 966 | | Fixed64 secondAxisLength, |
| | | 967 | | Fixed64 secondRadius, |
| | | 968 | | Vector3d fallbackNormal, |
| | | 969 | | out FixedContactAnchors contact) |
| | | 970 | | { |
| | 62 | 971 | | ValidateNormalizedRotation(firstRotation, nameof(firstRotation)); |
| | 61 | 972 | | ValidateNormalizedRotation(secondRotation, nameof(secondRotation)); |
| | 61 | 973 | | ValidateCenteredCapsulesContact( |
| | 61 | 974 | | firstLocalAxisDirection, |
| | 61 | 975 | | firstAxisLength, |
| | 61 | 976 | | firstRadius, |
| | 61 | 977 | | secondLocalAxisDirection, |
| | 61 | 978 | | secondAxisLength, |
| | 61 | 979 | | secondRadius, |
| | 61 | 980 | | fallbackNormal); |
| | 58 | 981 | | if (!WideOrientedBox.DoCenteredRigidCapsulesOverlap( |
| | 58 | 982 | | firstCenter, |
| | 58 | 983 | | firstRotation, |
| | 58 | 984 | | firstLocalAxisDirection, |
| | 58 | 985 | | firstAxisLength, |
| | 58 | 986 | | firstRadius, |
| | 58 | 987 | | secondCenter, |
| | 58 | 988 | | secondRotation, |
| | 58 | 989 | | secondLocalAxisDirection, |
| | 58 | 990 | | secondAxisLength, |
| | 58 | 991 | | secondRadius)) |
| | | 992 | | { |
| | 18 | 993 | | contact = default; |
| | 18 | 994 | | return false; |
| | | 995 | | } |
| | 40 | 996 | | Vector3d firstAxisDirection = firstLocalAxisDirection; |
| | 40 | 997 | | Vector3d secondAxisDirection = secondLocalAxisDirection; |
| | | 998 | | // Zero-core axes are irrelevant to the candidate; rotations still own |
| | | 999 | | // the radial anchors. Keep the exact rigid classifier above for all pairs. |
| | 40 | 1000 | | if (firstAxisLength != Fixed64.Zero || secondAxisLength != Fixed64.Zero) |
| | | 1001 | | { |
| | 14 | 1002 | | _ = firstRotation.TryRotate(firstLocalAxisDirection, out firstAxisDirection); |
| | 14 | 1003 | | _ = secondRotation.TryRotate(secondLocalAxisDirection, out secondAxisDirection); |
| | 14 | 1004 | | firstAxisDirection = firstAxisDirection.Normalized; |
| | 14 | 1005 | | secondAxisDirection = secondAxisDirection.Normalized; |
| | | 1006 | | } |
| | | 1007 | | |
| | 40 | 1008 | | return WideFiniteAxisIntersection.TryGetCenteredCapsulesContact( |
| | 40 | 1009 | | firstCenter, |
| | 40 | 1010 | | firstRotation, |
| | 40 | 1011 | | firstLocalAxisDirection, |
| | 40 | 1012 | | firstAxisDirection, |
| | 40 | 1013 | | firstAxisLength, |
| | 40 | 1014 | | firstRadius, |
| | 40 | 1015 | | secondCenter, |
| | 40 | 1016 | | secondRotation, |
| | 40 | 1017 | | secondLocalAxisDirection, |
| | 40 | 1018 | | secondAxisDirection, |
| | 40 | 1019 | | secondAxisLength, |
| | 40 | 1020 | | secondRadius, |
| | 40 | 1021 | | fallbackNormal, |
| | 40 | 1022 | | out contact); |
| | | 1023 | | } |
| | | 1024 | | |
| | | 1025 | | private static void ValidateNormalizedRotation( |
| | | 1026 | | FixedQuaternion rotation, |
| | | 1027 | | string parameterName) |
| | | 1028 | | { |
| | 189 | 1029 | | if (!rotation.IsNormalized()) |
| | | 1030 | | { |
| | 1 | 1031 | | throw new ArgumentException( |
| | 1 | 1032 | | "Capsule rotation must be normalized.", |
| | 1 | 1033 | | parameterName); |
| | | 1034 | | } |
| | 188 | 1035 | | } |
| | | 1036 | | |
| | | 1037 | | private static void ValidateCenteredCapsulesContact( |
| | | 1038 | | Vector3d firstAxisDirection, |
| | | 1039 | | Fixed64 firstAxisLength, |
| | | 1040 | | Fixed64 firstRadius, |
| | | 1041 | | Vector3d secondAxisDirection, |
| | | 1042 | | Fixed64 secondAxisLength, |
| | | 1043 | | Fixed64 secondRadius, |
| | | 1044 | | Vector3d fallbackNormal) |
| | | 1045 | | { |
| | 61 | 1046 | | ValidateCenteredAxis( |
| | 61 | 1047 | | firstAxisDirection, |
| | 61 | 1048 | | firstAxisLength, |
| | 61 | 1049 | | nameof(firstAxisDirection), |
| | 61 | 1050 | | nameof(firstAxisLength)); |
| | 61 | 1051 | | ValidateCenteredAxis( |
| | 61 | 1052 | | secondAxisDirection, |
| | 61 | 1053 | | secondAxisLength, |
| | 61 | 1054 | | nameof(secondAxisDirection), |
| | 61 | 1055 | | nameof(secondAxisLength)); |
| | 61 | 1056 | | if (firstRadius < Fixed64.Zero) |
| | 1 | 1057 | | throw new ArgumentOutOfRangeException(nameof(firstRadius)); |
| | 60 | 1058 | | if (secondRadius < Fixed64.Zero) |
| | 1 | 1059 | | throw new ArgumentOutOfRangeException(nameof(secondRadius)); |
| | 59 | 1060 | | if (!fallbackNormal.IsNormalized()) |
| | 1 | 1061 | | throw new ArgumentException("Fallback normal must be normalized.", nameof(fallbackNormal)); |
| | 58 | 1062 | | } |
| | | 1063 | | |
| | | 1064 | | private static void ValidateCenteredAxis( |
| | | 1065 | | Vector3d axisDirection, |
| | | 1066 | | Fixed64 axisLength) => |
| | 797 | 1067 | | ValidateCenteredAxis( |
| | 797 | 1068 | | axisDirection, |
| | 797 | 1069 | | axisLength, |
| | 797 | 1070 | | nameof(axisDirection), |
| | 797 | 1071 | | nameof(axisLength)); |
| | | 1072 | | |
| | | 1073 | | private static void ValidateCenteredAxis( |
| | | 1074 | | Vector3d axisDirection, |
| | | 1075 | | Fixed64 axisLength, |
| | | 1076 | | string directionParameterName, |
| | | 1077 | | string lengthParameterName) |
| | | 1078 | | { |
| | 2976 | 1079 | | if (!axisDirection.IsNormalized()) |
| | 5 | 1080 | | throw new ArgumentException("Axis direction must be normalized.", directionParameterName); |
| | 2971 | 1081 | | if (axisLength < Fixed64.Zero) |
| | 4 | 1082 | | throw new ArgumentOutOfRangeException(lengthParameterName); |
| | 2967 | 1083 | | } |
| | | 1084 | | } |