| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143 |
- using System;
- using System.Collections.Generic;
- using System.Runtime.CompilerServices;
- using Microsoft.Xna.Framework;
- namespace MonoGame.Extended
- {
- internal class PrimitivesHelper
- {
- // Used by Ray2 and Segment2
- internal static bool IntersectsSlab(float positionCoordinate, float directionCoordinate, float slabMinimum,
- float slabMaximum, ref float rayMinimumDistance, ref float rayMaximumDistance)
- {
- // Real-Time Collision Detection, Christer Ericson, 2005. Chapter 5.3; Basic Primitive Tests - Intersecting Lines, Rays, and (Directed Segments). pg 179-181
- if (Math.Abs(directionCoordinate) < float.Epsilon)
- return (positionCoordinate >= slabMinimum) && (positionCoordinate <= slabMaximum);
- // Compute intersection values of ray with near and far plane of slab
- var rayNearDistance = (slabMinimum - positionCoordinate)/directionCoordinate;
- var rayFarDistance = (slabMaximum - positionCoordinate)/directionCoordinate;
- if (rayNearDistance > rayFarDistance)
- {
- // Swap near and far distance
- var temp = rayNearDistance;
- rayNearDistance = rayFarDistance;
- rayFarDistance = temp;
- }
- // Compute the intersection of slab intersection intervals
- rayMinimumDistance = rayNearDistance > rayMinimumDistance ? rayNearDistance : rayMinimumDistance;
- rayMaximumDistance = rayFarDistance < rayMaximumDistance ? rayFarDistance : rayMaximumDistance;
- // Exit with no collision as soon as slab intersection becomes empty
- return rayMinimumDistance <= rayMaximumDistance;
- }
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- internal static void CreateRectangleFromPoints(IReadOnlyList<Vector2> points, out Vector2 minimum, out Vector2 maximum)
- {
- // Real-Time Collision Detection, Christer Ericson, 2005. Chapter 4.2; Bounding Volumes - Axis-aligned Bounding Boxes (AABBs). pg 82-84
- if (points == null || points.Count == 0)
- {
- minimum = Vector2.Zero;
- maximum = Vector2.Zero;
- return;
- }
- minimum = maximum = points[0];
- // ReSharper disable once ForCanBeConvertedToForeach
- for (var index = points.Count - 1; index > 0; --index)
- {
- var point = points[index];
- minimum = MathExtended.CalculateMinimumVector2(minimum, point);
- maximum = MathExtended.CalculateMaximumVector2(maximum, point);
- }
- }
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- internal static void TransformRectangle(ref Vector2 center, ref Vector2 halfExtents, ref Matrix3x2 transformMatrix)
- {
- // Real-Time Collision Detection, Christer Ericson, 2005. Chapter 4.2; Bounding Volumes - Axis-aligned Bounding Boxes (AABBs). pg 86-87
- center = transformMatrix.Transform(center);
- var xRadius = halfExtents.X;
- var yRadius = halfExtents.Y;
- halfExtents.X = xRadius * Math.Abs(transformMatrix.M11) + yRadius * Math.Abs(transformMatrix.M12);
- halfExtents.Y = xRadius * Math.Abs(transformMatrix.M21) + yRadius * Math.Abs(transformMatrix.M22);
- }
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- internal static void TransformOrientedRectangle(
- ref Vector2 center,
- ref Matrix3x2 orientation,
- ref Matrix3x2 transformMatrix)
- {
- // Real-Time Collision Detection, Christer Ericson, 2005. Chapter 4.4; Oriented Bounding Boxes (OBBs), pg 101-105.
- center = transformMatrix.Transform(center);
- orientation *= transformMatrix;
- // Reset the translation since orientation is only about rotation
- orientation.M31 = 0;
- orientation.M32 = 0;
- }
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- internal static float SquaredDistanceToPointFromRectangle(Vector2 minimum, Vector2 maximum, Vector2 point)
- {
- // Real-Time Collision Detection, Christer Ericson, 2005. Chapter 5.1.3.1; Basic Primitive Tests - Closest-point Computations - Distance of Point to AABB. pg 130-131
- var squaredDistance = 0.0f;
- // for each axis add up the excess distance outside the box
- // x-axis
- if (point.X < minimum.X)
- {
- var distance = minimum.X - point.X;
- squaredDistance += distance * distance;
- }
- else if (point.X > maximum.X)
- {
- var distance = maximum.X - point.X;
- squaredDistance += distance * distance;
- }
- // y-axis
- if (point.Y < minimum.Y)
- {
- var distance = minimum.Y - point.Y;
- squaredDistance += distance * distance;
- }
- else if (point.Y > maximum.Y)
- {
- var distance = maximum.Y - point.Y;
- squaredDistance += distance * distance;
- }
- return squaredDistance;
- }
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- internal static void ClosestPointToPointFromRectangle(Vector2 minimum, Vector2 maximum, Vector2 point, out Vector2 result)
- {
- // Real-Time Collision Detection, Christer Ericson, 2005. Chapter 5.1.2; Basic Primitive Tests - Closest-point Computations. pg 130-131
- result = point;
- // For each coordinate axis, if the point coordinate value is outside box, clamp it to the box, else keep it as is
- if (result.X < minimum.X)
- result.X = minimum.X;
- else if (result.X > maximum.X)
- result.X = maximum.X;
- if (result.Y < minimum.Y)
- result.Y = minimum.Y;
- else if (result.Y > maximum.Y)
- result.Y = maximum.Y;
- }
- }
- }
|