| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181 |
- using System;
- using Microsoft.Xna.Framework;
- namespace MonoGame.Extended.Collisions;
- /// <summary>
- /// Provides methods for transforming bounding volumes by matrices, rotations, and translations.
- /// </summary>
- public static class BoundingVolumeTransform
- {
- #region Circle Transformations
- /// <summary>
- /// Transforms a bounding circle by a 2D transformation matrix.
- /// </summary>
- /// <param name="circle">The circle to transform.</param>
- /// <param name="transform">The transformation matrix.</param>
- /// <returns>The transformed circle.</returns>
- /// <remarks>
- /// Circles are rotationally invariant; other the translation component is applied. <br/>
- /// If uniform scaling is needed, scale the radius separately after transformation. <br/>
- /// Non-uniform scaling is not supported (would produce an ellipse).
- /// </remarks>
- public static BoundingCircle Transform(in BoundingCircle circle, in Matrix3x2 transform)
- {
- // Extract translation from matrix
- Vector2 translation = new Vector2(transform.M31, transform.M32);
- return new BoundingCircle(circle.Center + translation, circle.Radius);
- }
- /// <summary>
- /// Translates a bounding circle by a vector.
- /// </summary>
- /// <param name="circle">The circle to translate.</param>
- /// <param name="translation">The translation vector.</param>
- /// <returns>The translated circle.</returns>
- public static BoundingCircle Translate(in BoundingCircle circle, Vector2 translation)
- {
- return new BoundingCircle(circle.Center + translation, circle.Radius);
- }
- #endregion
- #region AABB Transformations
- /// <summary>
- /// Transforms an AABB by a 2D transformation matrix, producing a new axis-aligned rectangle that bounds
- /// the transformed original.
- /// </summary>
- /// <param name="aabb">The AABB to transform.</param>
- /// <param name="transform">The transformation matrix.</param>
- /// <returns>A new AABB that contains the transformed original.</returns>
- /// <remarks>
- /// Rotation causes AABBs to lose tightness. the result is conservative (larger). <br/>
- /// For frequently updated AABBs, cache the local-space AABB and recompute from it rather than from the previous
- /// world-space AABB to avoid accumulating growth.
- /// </remarks>
- public static BoundingRectangle Transform(in BoundingRectangle aabb, in Matrix3x2 transform)
- {
- Vector2 center = aabb.Center;
- Vector2 halfExtents = aabb.HalfExtents;
- Vector2 transformedCenter = Vector2.Transform(center, transform);
- // For each axis, sum the absolute values of the transformed half-extents
- // This gives us the new AABB that bounds the rotated original AABB
- float newHalfWidth = MathF.Abs(transform.M11) * halfExtents.X
- + MathF.Abs(transform.M12) * halfExtents.Y;
- float newHalfHeight = MathF.Abs(transform.M21) * halfExtents.X
- + MathF.Abs(transform.M22) * halfExtents.Y;
- Vector2 newHalfExtents = new Vector2(newHalfWidth, newHalfHeight);
- return BoundingRectangle.FromCenterAndExtents(transformedCenter, newHalfExtents);
- }
- /// <summary>
- /// Transforms an AABB by separate rotation and translation components.
- /// </summary>
- /// <param name="aabb">The local-space AABB.</param>
- /// <param name="rotation">The rotation angle in radians.</param>
- /// <param name="translation">The translation vector.</param>
- /// <returns>The transformed AABB in world space.</returns>
- public static BoundingRectangle TransformFromRotation(in BoundingRectangle aabb, float rotation, Vector2 translation)
- {
- float cos = MathF.Cos(rotation);
- float sin = MathF.Sin(rotation);
- Matrix3x2 transform = new Matrix3x2(
- cos, sin,
- -sin, cos,
- translation.X, translation.Y
- );
- return Transform(aabb, transform);
- }
- /// <summary>
- /// Translates an AABB by a vector.
- /// </summary>
- /// <param name="aabb">The AABB to translate.</param>
- /// <param name="translation">The translation vector.</param>
- /// <returns>The translated AABB.</returns>
- public static BoundingRectangle Translate(in BoundingRectangle aabb, Vector2 translation)
- {
- return new BoundingRectangle(aabb.Min + translation, aabb.Max + translation);
- }
- #endregion
- #region OBB Transformations
- /// <summary>
- /// Transforms an oriented bounding rectangle by a 2D transformation matrix.
- /// </summary>
- /// <param name="obb">The OBB to transform.</param>
- /// <param name="transform">The transformation matrix.</param>
- /// <returns>The transformed OBB</returns>
- /// <remarks>
- /// Transforms center point and rotates the local axes. <br/>
- /// OBBs maintain tightness under transformation (unlike AABBs).
- /// </remarks>
- public static OrientedBoundingRectangle Transform(in OrientedBoundingRectangle obb, in Matrix3x2 transform)
- {
- Vector2 transformedCenter = Vector2.Transform(obb.Center, transform);
- // Transform axes (rotation only, no translation)
- Vector2 transformedAxisX = Vector2.TransformNormal(obb.AxisX, transform);
- Vector2 transformedAxisY = Vector2.TransformNormal(obb.AxisY, transform);
- transformedAxisX = GeometricPrimitives.SafeNormalize(transformedAxisX);
- transformedAxisY = GeometricPrimitives.SafeNormalize(transformedAxisY);
- return new OrientedBoundingRectangle(transformedCenter, transformedAxisX, transformedAxisY, obb.HalfExtents);
- }
- /// <summary>
- /// Rotates an obb by an angle in radians.
- /// </summary>
- /// <param name="obb">The OBB to rotate.</param>
- /// <param name="radians">The rotation angle in radians, measured counter-clockwise.</param>
- /// <returns>The rotated OBB.</returns>
- public static OrientedBoundingRectangle Rotate(in OrientedBoundingRectangle obb, float radians)
- {
- float cos = MathF.Cos(radians);
- float sin = MathF.Sin(radians);
- // Rotate axes
- Vector2 newAxisX = new Vector2(
- cos * obb.AxisX.X - sin * obb.AxisX.Y,
- sin * obb.AxisX.X + cos * obb.AxisX.Y
- );
- Vector2 newAxisY = new Vector2(
- cos * obb.AxisY.X - sin * obb.AxisY.Y,
- sin * obb.AxisY.X + cos * obb.AxisY.Y
- );
- newAxisX = GeometricPrimitives.SafeNormalize(newAxisX);
- newAxisY = GeometricPrimitives.SafeNormalize(newAxisY);
- return new OrientedBoundingRectangle(obb.Center, newAxisX, newAxisY, obb.HalfExtents);
- }
- /// <summary>
- /// Translates an OBB by a vector.
- /// </summary>
- /// <param name="obb">The OBB to translate.</param>
- /// <param name="translation">The translation vector.</param>
- /// <returns>The translated OBB.</returns>
- public static OrientedBoundingRectangle Translate(in OrientedBoundingRectangle obb, Vector2 translation)
- {
- return new OrientedBoundingRectangle(obb.Center + translation, obb.AxisX, obb.AxisY, obb.HalfExtents);
- }
- #endregion
- }
|