#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 System.Collections.Generic;
using Microsoft.Xna.Framework;
namespace Nuclex.Geometry.Lines.Collisions {
///
/// Detects intersections of infinite 2D lines with 2D axis-aligned boxes
///
public static class Line2Aabb2Collider {
/// Determines the contact times of a line with an axis aligned box
/// Offset of the line from the box
/// Direction into which the line goes
/// Extents of the box (half of the box' dimensions)
/// The contact points, if any, between the line and the box
///
/// Shamelessly lifted from the FreeMagic library at http://www.magic-software.com
/// and used as a supporting function for the other line/box contact finders.
///
public static LineContacts FindContacts(
Vector2 lineOffset, Vector2 lineDirection, Vector2 boxExtents
) {
float entrytime = float.MinValue;
float exitTime = float.MaxValue;
// Determine the instants of entry and exit into the box, if any
bool notEntirelyClipped =
clip(+lineDirection.X, -lineOffset.X - boxExtents.X, ref entrytime, ref exitTime) &&
clip(-lineDirection.X, +lineOffset.X - boxExtents.X, ref entrytime, ref exitTime) &&
clip(+lineDirection.Y, -lineOffset.Y - boxExtents.Y, ref entrytime, ref exitTime) &&
clip(-lineDirection.Y, +lineOffset.Y - boxExtents.Y, ref entrytime, ref exitTime);
// Find out if an intersection with the box has actually occured
bool intersects =
notEntirelyClipped &&
(entrytime != float.MinValue || exitTime != float.MaxValue);
if(intersects) {
return new LineContacts(entrytime, exitTime);
} else {
return LineContacts.None;
}
}
/// Determines the contact times of a line with an axis aligned box
/// Offset of the line from the box
/// Direction into which the line goes
/// Corner of the box with the lesser coordinates
/// Corner of the box with the greater coordinates
/// The contact points, if any, between the line and the box
public static LineContacts FindContacts(
Vector2 lineOffset, Vector2 lineDirection,
Vector2 minBoxCorner, Vector2 maxBoxCorner
) {
Vector2 boxExtents = (maxBoxCorner - minBoxCorner) / 2.0f;
Vector2 boxOffset = minBoxCorner + boxExtents;
return FindContacts(
lineOffset - boxOffset, lineDirection, boxExtents
);
}
/// Determines where a line will intersect with a normalized plane
/// Denominator of the line's direction towards the plane
/// Numerator of the line's direction towards the plane
/// Time of entry into the plane
/// Time of exit from the plane
/// True if the line segment actually intersects with the plane
///
/// Shamelessly lifted from the FreeMagic library at http://www.magic-software.com
/// and used as a supporting function for the other line/box contact finders.
///
private static bool clip(
float denominator, float numerator,
ref float entryTime, ref float exitTime
) {
if(denominator > 0.0f) {
if(numerator > denominator * exitTime)
return false;
if(numerator > denominator * entryTime)
entryTime = numerator / denominator;
return true;
} else if(denominator < 0.0f) {
if(numerator > denominator * entryTime)
return false;
if(numerator > denominator * exitTime)
exitTime = numerator / denominator;
return true;
} else {
return numerator <= 0.0f;
}
}
}
} // namespace Nuclex.Geometry.Lines.Collisions