#region CPL License
/*
Nuclex Framework
Copyright (C) 2002-2009 Nuclex Development Labs
This library is free software; you can redistribute it and/or
modify it under the terms of the IBM Common Public License as
published by the IBM Corporation; either version 1.0 of the
License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
IBM Common Public License for more details.
You should have received a copy of the IBM Common Public
License along with this library
*/
#endregion
using System;
using Microsoft.Xna.Framework;
namespace Nuclex.Geometry.Areas.Collisions {
/// Contains all Aabb-to-Aabb interference detection code
public static class AabbAabbCollider {
/// Test whether two axis aligned boxes are overlapping
/// Minimum coordinate of first box
/// Maximum coordinate of first box
/// Minimum coordinate of second box
/// Maximum coordinate of second box
/// True if the boxes are intersecting each other
public static bool CheckContact(
Vector2 firstMin, Vector2 firstMax,
Vector2 secondMin, Vector2 secondMax
) {
return
(firstMin.X < secondMax.X) && (firstMax.X > secondMin.X) &&
(firstMin.Y < secondMax.Y) && (firstMax.Y > secondMin.Y);
}
/// Find the contact location between two axis aligned boxes
/// Minimum coordinate of first box
/// Maximum coordinate of first box
/// Minimum coordinate of second box
/// Maximum coordinate of second box
/// A contact location if the boxes touch each other
public static Vector2? FindContact(
Vector2 firstMin, Vector2 firstMax,
Vector2 secondMin, Vector2 secondMax
) {
// Extract the intersecting area of the two boxes
Vector2 min = Vector2.Max(firstMin, secondMin);
Vector2 max = Vector2.Min(firstMax, secondMax);
// If the boxes don't touch we don't have an intersection
if((max.X < min.X) || (max.Y < min.Y))
return null;
// The contact point is in the center of the intersecting area
return (min + max) / 2.0f;
}
/// Determines whether a box will hit another box
/// Minimum coordinate of first box
/// Maximum coordinate of first box
/// Minimum coordinate of second box
/// Maximum coordinate of second box
///
/// Velocity with which the second box is moving relative to the first box
///
/// True if the second box will hit the first box
public static bool CheckContact(
Vector2 firstMin, Vector2 firstMax,
Vector2 secondMin, Vector2 secondMax, Vector2 secondVelocity
) {
return FindContact(firstMin, firstMax, secondMin, secondMax, secondVelocity).HasValue;
}
/// Determines the time when the box will hit another box
/// Minimum coordinate of first box
/// Maximum coordinate of first box
/// Minimum coordinate of second box
/// Maximum coordinate of second box
///
/// Velocity with which the second box is moving relative to the first box
///
/// The point of first contact, if any
///
///
/// Conventional tests that resort to stepping often fail to detect collisions
/// between fast-moving objects. This impact determination test will always
/// detect a collision if it occurs, giving the exact time of the impact.
///
///
/// This is a simplified test that assumes a linear trajectory and does
/// not take object rotation into account. It is well suited to use on
/// two bounding boxes in order to determine if a collision between the
/// shapes contained is possible at all.
///
///
/// Idea taken from the "Simple Intersection Tests for Games" article
/// on gamasutra by Gomez.
///
///
public static float? FindContact(
Vector2 firstMin, Vector2 firstMax,
Vector2 secondMin, Vector2 secondMax, Vector2 secondVelocity
) {
Vector2 secondContact = new Vector2(0.0f, 0.0f);
Vector2 lastContact = new Vector2(1.0f, 1.0f);
// X axis
if(firstMax.X < secondMin.X && secondVelocity.X < 0.0f)
secondContact.X = (firstMax.X - secondMin.X) / secondVelocity.X;
else if(secondMax.X < firstMin.X && secondVelocity.X > 0.0f)
secondContact.X = (firstMin.X - secondMax.X) / secondVelocity.X;
if(secondMax.X > firstMin.X && secondVelocity.X < 0.0f)
lastContact.X = (firstMin.X - secondMax.X) / secondVelocity.X;
else if(firstMax.X > secondMin.X && secondVelocity.X > 0.0f)
lastContact.X = (firstMax.X - secondMin.X) / secondVelocity.X;
// Y axis
if(firstMax.Y < secondMin.Y && secondVelocity.Y < 0.0f)
secondContact.Y = (firstMax.Y - secondMin.Y) / secondVelocity.Y;
else if(secondMax.Y < firstMin.Y && secondVelocity.Y > 0.0f)
secondContact.Y = (firstMin.Y - secondMax.Y) / secondVelocity.Y;
if(secondMax.Y > firstMin.Y && secondVelocity.Y < 0.0f)
lastContact.Y = (firstMin.Y - secondMax.Y) / secondVelocity.Y;
else if(firstMax.Y > secondMin.Y && secondVelocity.Y > 0.0f)
lastContact.Y = (firstMax.Y - secondMin.Y) / secondVelocity.Y;
// We now extract the exact time of the box' entry into the other box
// as well as the time of exit (if any)
float entry = Math.Max(secondContact.X, secondContact.Y);
float exit = Math.Min(lastContact.X, lastContact.Y);
if(entry > exit)
return null;
return entry;
}
}
} // namespace Nuclex.Geometry.Areas.Collisions