TrinityCore
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
G3D::CollisionDetection Class Reference

#include <CollisionDetection.h>

Static Public Member Functions

static Vector3 separatingAxisForSolidBoxSolidBox (const int separatingAxisIndex, const Box &box1, const Box &box2)
 
static bool parallelAxisForSolidBoxSolidBox (const double *ca, const double epsilon, int &axis1, int &axis2)
 
static float projectedDistanceForSolidBoxSolidBox (const int separatingAxisIndex, const Vector3 &a, const Vector3 &b, const Vector3 &D, const double *c, const double *ca, const double *ad, const double *bd)
 
static void fillSolidBoxSolidBoxInfo (const Box &box1, const Box &box2, Vector3 &a, Vector3 &b, Vector3 &D, double *c, double *ca, double *ad, double *bd)
 
static bool conservativeBoxBoxTest (const Vector3 &a, const Vector3 &b, const Vector3 &D)
 
static bool fixedSolidBoxIntersectsFixedSolidBox (const Box &box1, const Box &box2, const int lastSeparatingAxis=-1)
 
static void closestPointsBetweenLineAndLine (const Line &line1, const Line &line2, Vector3 &closest1, Vector3 &closest2)
 
static float penetrationDepthForFixedBoxFixedBox (const Box &box1, const Box &box2, Array< Vector3 > &contactPoints, Array< Vector3 > &contactNormals, const int lastSeparatingAxis=-1)
 
static float penetrationDepthForFixedSphereFixedSphere (const class Sphere &sphereA, const Sphere &sphereB, Array< Vector3 > &contactPoints, Array< Vector3 > &contactNormals=ignoreArray)
 
static float penetrationDepthForFixedSphereFixedBox (const Sphere &sphere, const Box &box, Array< Vector3 > &contactPoints, Array< Vector3 > &contactNormals=ignoreArray)
 
static float penetrationDepthForFixedSphereFixedPlane (const Sphere &sphereA, const class Plane &planeB, Array< Vector3 > &contactPoints, Array< Vector3 > &contactNormals=ignoreArray)
 
static float penetrationDepthForFixedBoxFixedPlane (const Box &box, const Plane &plane, Array< Vector3 > &contactPoints, Array< Vector3 > &contactNormals=ignoreArray)
 
static float collisionTimeForMovingPointFixedPlane (const Vector3 &point, const Vector3 &velocity, const class Plane &plane, Vector3 &outLocation, Vector3 &outNormal=ignore)
 
static float collisionTimeForMovingPointFixedTriangle (const Vector3 &orig, const Vector3 &dir, const Vector3 &v0, const Vector3 &v1, const Vector3 &v2)
 
static float collisionTimeForMovingPointFixedTriangle (const Vector3 &orig, const Vector3 &dir, const Vector3 &v0, const Vector3 &v1, const Vector3 &v2, Vector3 &location)
 
static float collisionTimeForMovingPointFixedTriangle (const Vector3 &orig, const Vector3 &dir, const Triangle &tri, Vector3 &location=ignore, Vector3 &normal=ignore)
 
static float collisionTimeForMovingPointFixedTriangle (const Vector3 &orig, const Vector3 &dir, const Vector3 &v0, const Vector3 &v1, const Vector3 &v2, Vector3 &location, Vector3 &normal)
 
static float collisionTimeForMovingPointFixedAABox (const Vector3 &point, const Vector3 &velocity, const class AABox &box, Vector3 &outLocation, bool &inside=ignoreBool, Vector3 &outNormal=ignore)
 
static bool collisionLocationForMovingPointFixedAABox (const Vector3 &point, const Vector3 &velocity, const class AABox &box, Vector3 &outLocation, bool &inside=ignoreBool, Vector3 &normal=ignore)
 
static bool __fastcall rayAABox (const Ray &ray, const Vector3 &invDir, const AABox &box, const Vector3 &boxCenter, float boundingRadiusSquared, Vector3 &location, bool &inside)
 Calculates intersection of a ray and a static Axis-Aligned Box (AABox). More...
 
static float collisionTimeForMovingPointFixedSphere (const Vector3 &point, const Vector3 &velocity, const class Sphere &sphere, Vector3 &outLocation, Vector3 &outNormal=ignore, bool solid=false)
 
static float collisionTimeForMovingPointFixedBox (const Vector3 &point, const Vector3 &velocity, const class Box &box, Vector3 &outLocation, Vector3 &outNormal=ignore)
 
static float collisionTimeForMovingPointFixedRectangle (const Vector3 &point, const Vector3 &velocity, const Vector3 &v0, const Vector3 &v1, const Vector3 &v2, const Vector3 &v3, Vector3 &outLocation, Vector3 &outNormal=ignore)
 
static float collisionTimeForMovingPointFixedCapsule (const Vector3 &point, const Vector3 &velocity, const class Capsule &capsule, Vector3 &outLocation, Vector3 &outNormal=ignore)
 
static float collisionTimeForMovingSphereFixedPlane (const class Sphere &sphere, const Vector3 &velocity, const class Plane &plane, Vector3 &outLocation, Vector3 &outNormal=ignore)
 
static float collisionTimeForMovingSphereFixedTriangle (const class Sphere &sphere, const Vector3 &velocity, const Triangle &triangle, Vector3 &outLocation, float b[3]=(float *)&ignore)
 
static float collisionTimeForMovingSphereFixedRectangle (const class Sphere &sphere, const Vector3 &velocity, const Vector3 &v0, const Vector3 &v1, const Vector3 &v2, const Vector3 &v3, Vector3 &outLocation, Vector3 &outNormal=ignore)
 
static float collisionTimeForMovingSphereFixedBox (const class Sphere &sphere, const Vector3 &velocity, const class Box &box, Vector3 &outLocation, Vector3 &outNormal=ignore)
 
static float collisionTimeForMovingSphereFixedSphere (const Sphere &sphere, const Vector3 &velocity, const Sphere &fixedSphere, Vector3 &outLocation, Vector3 &outNormal=ignore)
 
static float collisionTimeForMovingSphereFixedCapsule (const class Sphere &sphere, const Vector3 &velocity, const class Capsule &capsule, Vector3 &outLocation, Vector3 &outNormal=ignore)
 
static Vector3 bounceDirection (const class Sphere &sphere, const Vector3 &velocity, const float collisionTime, const Vector3 &collisionLocation, const Vector3 &collisionNormal)
 
static Vector3 slideDirection (const class Sphere &sphere, const Vector3 &velocity, const float collisionTime, const Vector3 &collisionLocation)
 
static Vector3 closestPointOnLineSegment (const Vector3 &v0, const Vector3 &v1, const Vector3 &point)
 
static Vector3 closestPointOnLineSegment (const Vector3 &v0, const Vector3 &v1, const Vector3 &edgeDirection, float edgeLength, const Vector3 &point)
 
static Vector3 closestPointOnTrianglePerimeter (const Vector3 &v0, const Vector3 &v1, const Vector3 &v2, const Vector3 &point)
 
static Vector3 closestPointOnTrianglePerimeter (const Vector3 v[3], const Vector3 edgeDirection[3], const float edgeLength[3], const Vector3 &point, int &edgeIndex)
 
static bool isPointInsideTriangle (const Vector3 &v0, const Vector3 &v1, const Vector3 &v2, const Vector3 &normal, const Vector3 &point, float b[3], Vector3::Axis primaryAxis=Vector3::DETECT_AXIS)
 
static bool isPointInsideTriangle (const Vector3 &v0, const Vector3 &v1, const Vector3 &v2, const Vector3 &normal, const Vector3 &point, Vector3::Axis primaryAxis=Vector3::DETECT_AXIS)
 
static bool movingSpherePassesThroughFixedBox (const Sphere &sphere, const Vector3 &velocity, const Box &box, double timeLimit=inf())
 
static bool movingSpherePassesThroughFixedSphere (const Sphere &sphere, const Vector3 &velocity, const Sphere &fixedSphere, double timeLimit=inf())
 
static bool fixedSolidSphereIntersectsFixedSolidSphere (const Sphere &sphere1, const Sphere &sphere2)
 
static bool fixedSolidSphereIntersectsFixedSolidBox (const Sphere &sphere, const Box &box)
 
static bool fixedSolidSphereIntersectsFixedTriangle (const Sphere &sphere, const Triangle &triangle)
 
static bool fixedSolidBoxIntersectsFixedTriangle (const AABox &box, const Triangle &triangle)
 
static bool isPointInsideRectangle (const Vector3 &v0, const Vector3 &v1, const Vector3 &v2, const Vector3 &v3, const Vector3 &normal, const Vector3 &point)
 
static Vector3 closestPointToRectanglePerimeter (const Vector3 &v0, const Vector3 &v1, const Vector3 &v2, const Vector3 &v3, const Vector3 &point)
 
static Vector3 closestPointToRectangle (const Vector3 &v0, const Vector3 &v1, const Vector3 &v2, const Vector3 &v3, const Vector3 &point)
 

Private Member Functions

 CollisionDetection ()
 
virtual ~CollisionDetection ()
 

Static Private Attributes

static Vector3 ignore
 
static bool ignoreBool
 
static Array< Vector3ignoreArray
 

Detailed Description

Collision detection primitives and tools for building higher order collision detection schemes.

These routines provide moving and static collision detection. Moving collision detection allows the calculation of collisions that occur during a period of time – as opposed to the intersection of two static bodies.

Moving collision detection routines detect collisions between only static primitives and moving spheres or points. Since the reference frame can be user defined, these functions can be used to detect the collision between two moving bodies by subtracting the velocity vector of one object from the velocity vector of the sphere or point the detection is to occur with. This unified velocity vector will act as if both objects are moving simultaneously.

Collisions are detected for single-sided objects only. That is, no collision is detected when leaving a primitive or passing through a plane or triangle opposite the normal... except for the point-sphere calculation or when otherwise noted.

For a sphere, the collision location returned is the point in world space where the surface of the sphere and the fixed object meet. It is not the position of the center of the sphere at the time of the collision.

The collision normal returned is the surface normal to the fixed object at the collision location.

Static Collision Detection: (Neither object is moving)

Point3LineSegmentRay *LinePlaneTriangleSphereCylinderCapsuleAABoxBox
Point3P3::== V3::fuzzy distance
LineSegmentLS::closestPoint LS::distance CD
Ray *Ray::closestPoint Ray::distance
LineLine::closestPoint Line::distanceCD
Plane
Triangle
SphereSphere::containsCD , R::timeCDCD
CylinderCylinder::contains
CapsuleCapsule::contains CD
AABoxAABox::containsCD
BoxBox::contains(treat as Ray)CD(treat as Ray)CD CDCDNone (use OPCODE)CD CDCD

Moving Collision Detection:

* Note: Moving collision detection against certain primitives is equivalent to static collision detection against a bigger primitive. Ray, Line Segment == moving Point''; Capsule ==moving Sphere''; Plane == ``moving Line''

Deprecated:
Routines moving to the G3D::Intersect class in G3D 9.0

Constructor & Destructor Documentation

G3D::CollisionDetection::CollisionDetection ( )
inlineprivate
116 {}
virtual G3D::CollisionDetection::~CollisionDetection ( )
inlineprivatevirtual
117 {}

Member Function Documentation

Vector3 G3D::CollisionDetection::bounceDirection ( const class Sphere sphere,
const Vector3 velocity,
const float  collisionTime,
const Vector3 collisionLocation,
const Vector3 collisionNormal 
)
static

Finds the direction of bounce that a sphere would have when it intersects an object with the given time of collision, the collision location and the collision normal.

Note
This function works like a pong style ball bounce.
Parameters
sphereMoving sphere.
velocitySphere's velocity.
collisionTimeTime of collision.
collisionLocationCollision location.
collisionNormalSurface collision normal.
Returns
Direction of bounce.
1855  {
1856 
1857  // Location when the collision occurs
1858  Vector3 sphereLocation = sphere.center + velocity * collisionTime;
1859 
1860  Vector3 normal = (sphereLocation - collisionLocation);
1861  if (fuzzyEq(normal.squaredMagnitude(), 0)) {
1862  normal = collisionNormal;
1863  } else {
1864  normal = normal.direction();
1865  }
1866 
1867  Vector3 direction = velocity.direction();
1868 
1869  // Reflect direction about the normal
1870  return direction - 2.0 * normal * normal.dot(direction);
1871 }
bool fuzzyEq(double a, double b)
Definition: g3dmath.h:857

+ Here is the call graph for this function:

Vector3 G3D::CollisionDetection::closestPointOnLineSegment ( const Vector3 v0,
const Vector3 v1,
const Vector3 point 
)
static

Finds the closest point on a line segment to a given point.

Parameters
v0line vertex 1.
v1line vertex 2.
pointExternal point.
Returns
Closests point to point on the line segment.
1892  {
1893 
1894  const Vector3& edge = (v1 - v0);
1895  float edgeLength = edge.magnitude();
1896 
1897  if (edgeLength == 0) {
1898  // The line segment is a point
1899  return v0;
1900  }
1901 
1902  return closestPointOnLineSegment(v0, v1, edge / edgeLength, edgeLength, point);
1903 }
static Vector3 closestPointOnLineSegment(const Vector3 &v0, const Vector3 &v1, const Vector3 &point)
Definition: CollisionDetection.cpp:1889

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

Vector3 G3D::CollisionDetection::closestPointOnLineSegment ( const Vector3 v0,
const Vector3 v1,
const Vector3 edgeDirection,
float  edgeLength,
const Vector3 point 
)
static

Finds the closest point on a line segment to a given point.

Note
This is an optimization to closestPointOnLineSegment. Edge length and direction can be used in this function if already pre-calculated. This prevents doing the same work twice.
Parameters
v0line vertex 0.
v1line vertex 1.
edgeDirectionThe direction of the segment (unit length).
edgeLengthThe length of the segment.
pointExternal point.
Returns
Closests point to point on the line segment.
1911  {
1912 
1913  debugAssert((v1 - v0).direction().fuzzyEq(edgeDirection));
1914  debugAssert(fuzzyEq((v1 - v0).magnitude(), edgeLength));
1915 
1916  // Vector towards the point
1917  const Vector3& c = point - v0;
1918 
1919  // Projected onto the edge itself
1920  float t = edgeDirection.dot(c);
1921 
1922  if (t <= 0) {
1923  // Before the start
1924  return v0;
1925  } else if (t >= edgeLength) {
1926  // After the end
1927  return v1;
1928  } else {
1929  // At distance t along the edge
1930  return v0 + edgeDirection * t;
1931  }
1932 }
#define debugAssert(exp)
Definition: debugAssert.h:160
bool fuzzyEq(double a, double b)
Definition: g3dmath.h:857

+ Here is the call graph for this function:

Vector3 G3D::CollisionDetection::closestPointOnTrianglePerimeter ( const Vector3 v0,
const Vector3 v1,
const Vector3 v2,
const Vector3 point 
)
static

Finds the closest point on the perimeter of the triangle to an external point; given a triangle defined by three points v0, v1, & v2, and the external point.

Parameters
v0Triangle vertex 0.
v1Triangle vertex 1.
v2Triangle vertex 2.
pointExternal point.
Returns
Closests point to point on the perimeter of the triangle.
1939  {
1940 
1941  Vector3 v[3] = {v0, v1, v2};
1942  Vector3 edgeDirection[3] = {(v1 - v0), (v2 - v1), (v0 - v2)};
1943  float edgeLength[3];
1944 
1945  for (int i = 0; i < 3; ++i) {
1946  edgeLength[i] = edgeDirection[i].magnitude();
1947  edgeDirection[i] /= edgeLength[i];
1948  }
1949 
1950  int edgeIndex;
1951  return closestPointOnTrianglePerimeter(v, edgeDirection, edgeLength, point, edgeIndex);
1952 }
static Vector3 closestPointOnTrianglePerimeter(const Vector3 &v0, const Vector3 &v1, const Vector3 &v2, const Vector3 &point)
Definition: CollisionDetection.cpp:1935

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

Vector3 G3D::CollisionDetection::closestPointOnTrianglePerimeter ( const Vector3  v[3],
const Vector3  edgeDirection[3],
const float  edgeLength[3],
const Vector3 point,
int &  edgeIndex 
)
static

Finds the closest point on the perimeter of the triangle to an external point; given a triangle defined by the array of points v, its edge directions and their lengths, as well as the external point.

Note
This is an optimization to closestPointToTrianglePerimeter. Edge length and direction can be used in this function if already pre-calculated. This prevents doing the same work twice.
Parameters
vTriangle vertices.
pointExternal point.
edgeIndexThe point lies on the edge between v[edgeIndex] and v[(edgeIndex + 1) % 3]
Returns
Closest point to point on the perimeter of the triangle.
1960  {
1961 
1962  // Closest point on segment from v[i] to v[i + 1]
1963  Vector3 r[3];
1964 
1965  // Distance squared from r[i] to point
1966  float d[3];
1967 
1968  // Index of the next point
1969  static const int next[] = {1, 2, 0};
1970 
1971  for (int i = 0; i < 3; ++i) {
1972  r[i] = closestPointOnLineSegment(v[i], v[next[i]], edgeDirection[i], edgeLength[i], point);
1973  d[i] = (r[i] - point).squaredMagnitude();
1974  }
1975 
1976  if (d[0] < d[1]) {
1977  if (d[0] < d[2]) {
1978  // Between v0 and v1
1979  edgeIndex = 0;
1980  } else {
1981  // Between v2 and v0
1982  edgeIndex = 2;
1983  }
1984  } else {
1985  if (d[1] < d[2]) {
1986  // Between v1 and v2
1987  edgeIndex = 1;
1988  } else {
1989  // Between v2 and v0
1990  edgeIndex = 2;
1991  }
1992  }
1993 
1994 # ifdef G3D_DEBUG
1995  {
1996  Vector3 diff = r[edgeIndex] - v[edgeIndex];
1997  debugAssertM(fuzzyEq(diff.direction().dot(edgeDirection[edgeIndex]), 1.0f) ||
1998  diff.fuzzyEq(Vector3::zero()), "Point not on correct triangle edge");
1999  float frac = diff.dot(edgeDirection[edgeIndex])/edgeLength[edgeIndex];
2000  debugAssertM(frac >= -0.000001, "Point off low side of edge.");
2001  debugAssertM(frac <= 1.000001, "Point off high side of edge.");
2002  }
2003 # endif
2004 
2005  return r[edgeIndex];
2006 }
int next(int i, int n)
Definition: RecastContour.cpp:469
#define debugAssertM(exp, message)
Definition: debugAssert.h:161
static const Vector3 & zero()
Definition: Vector3.cpp:119
static Vector3 closestPointOnLineSegment(const Vector3 &v0, const Vector3 &v1, const Vector3 &point)
Definition: CollisionDetection.cpp:1889
bool fuzzyEq(double a, double b)
Definition: g3dmath.h:857

+ Here is the call graph for this function:

void G3D::CollisionDetection::closestPointsBetweenLineAndLine ( const Line line1,
const Line line2,
Vector3 closest1,
Vector3 closest2 
)
static

Calculates the closest points on two lines with each other. If the lines are parallel then using the starting point, else calculate the closest point on each line to the other.

Note
This is very similiar to calculating the intersection of two lines. Logically then, the two points calculated would be identical if calculated with inifinite precision, but with the finite precision of floating point calculations, these values could (will) differ as the line slope approaches zero or inifinity.

[variables] and algorithm based on derivation at the following website: http://softsurfer.com/Archive/algorithm_0106/algorithm_0106.htm

Parameters
line1Line 1.
line2Line 2.
closest1Closest point on line 1.
closest2Closest point on line 2.
313  {
314  // TODO make accessors for Line that don't make a copy of data
315  Vector3 P0 = line1.point();
316  Vector3 u = line1.direction();
317  Vector3 Q0 = line2.point();
318  Vector3 v = line2.direction();
319  Vector3 w0 = P0 - Q0;
320 
321  // a = 1.0, c = 1.0
322  double b = dot(u, v);
323  double d = dot(u, w0);
324  double e = dot(v, w0);
325  double D = 1.0 - b * b;
326  double sc, tc;
327 
328  static const double epsilon = 0.00001;
329 
330  if (D < epsilon) {
331  // lines are parallel, choose P0 as one point, find the point
332  // on line2 that is closest to P0
333  sc = 0.0;
334  tc = (b > 1.0) ? (d / b) : (e / 1.0);
335  } else {
336  // lines are not parallel
337  sc = (b * e - 1.0 * d) / D;
338  tc = (1.0 * e - b * d) / D;
339  }
340 
341  closest1 = P0 + (sc * u);
342  closest2 = Q0 + (tc * v);
343 }
float dot(float a, float b)
Definition: g3dmath.h:445

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

Vector3 G3D::CollisionDetection::closestPointToRectangle ( const Vector3 v0,
const Vector3 v1,
const Vector3 v2,
const Vector3 v3,
const Vector3 point 
)
static

Finds the closest point in the rectangle to an external point; Given a rectangle defined by four points v0, v1, v2, & v3, and the external point.

Parameters
v0Rectangle vertex 1.
v1Rectangle vertex 2.
v2Rectangle vertex 3
v3Rectangle vertex 4.
pointExternal point.
Returns
Closet point in the rectangle to the external point.
2153  {
2154 
2155  Plane plane(v0, v1, v2);
2156 
2157  // Project the point into the plane
2158  double a, b, c, d;
2159  plane.getEquation(a, b, c, d);
2160 
2161  double distance = a*point.x + b*point.y + c*point.z + d;
2162  Vector3 planePoint = point - distance * plane.normal();
2163 
2164  if (isPointInsideRectangle(v0, v1, v2, v3, plane.normal(), planePoint)) {
2165  return planePoint;
2166  } else {
2167  return closestPointToRectanglePerimeter(v0, v1, v2, v3, planePoint);
2168  }
2169 }
double distance(double x, double y)
Definition: g3dmath.h:731
static bool isPointInsideRectangle(const Vector3 &v0, const Vector3 &v1, const Vector3 &v2, const Vector3 &v3, const Vector3 &normal, const Vector3 &point)
Definition: CollisionDetection.cpp:2086
static Vector3 closestPointToRectanglePerimeter(const Vector3 &v0, const Vector3 &v1, const Vector3 &v2, const Vector3 &v3, const Vector3 &point)
Definition: CollisionDetection.cpp:2099

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

Vector3 G3D::CollisionDetection::closestPointToRectanglePerimeter ( const Vector3 v0,
const Vector3 v1,
const Vector3 v2,
const Vector3 v3,
const Vector3 point 
)
static

Finds the closest point on the perimeter of the rectangle to an external point; given a rectangle defined by four points v0, v1, v2, & v3, and the external point.

Parameters
v0Rectangle vertex 1.
v1Rectangle vertex 2.
v2Rectangle vertex 3.
v3Rectangle vertex 4.
pointExternal point.
Returns
Closests point to point on the perimeter of the rectangle.
2104  {
2105 
2106  Vector3 r0 = closestPointOnLineSegment(v0, v1, point);
2107  Vector3 r1 = closestPointOnLineSegment(v1, v2, point);
2108  Vector3 r2 = closestPointOnLineSegment(v2, v3, point);
2109  Vector3 r3 = closestPointOnLineSegment(v3, v0, point);
2110 
2111  double d0 = (r0 - point).squaredMagnitude();
2112  double d1 = (r1 - point).squaredMagnitude();
2113  double d2 = (r2 - point).squaredMagnitude();
2114  double d3 = (r3 - point).squaredMagnitude();
2115 
2116  if (d0 < d1) {
2117  if (d0 < d2) {
2118  if (d0 < d3) {
2119  return r0;
2120  } else {
2121  return r3;
2122  }
2123  } else {
2124  if (d2 < d3) {
2125  return r2;
2126  } else {
2127  return r3;
2128  }
2129  }
2130  } else {
2131  if (d1 < d2) {
2132  if (d1 < d3) {
2133  return r1;
2134  } else {
2135  return r3;
2136  }
2137  } else {
2138  if (d2 < d3) {
2139  return r2;
2140  } else {
2141  return r3;
2142  }
2143  }
2144  }
2145 }
static Vector3 closestPointOnLineSegment(const Vector3 &v0, const Vector3 &v1, const Vector3 &point)
Definition: CollisionDetection.cpp:1889

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

bool G3D::CollisionDetection::collisionLocationForMovingPointFixedAABox ( const Vector3 point,
const Vector3 velocity,
const class AABox box,
Vector3 outLocation,
bool inside = ignoreBool,
Vector3 normal = ignore 
)
static

Calculates time between the intersection of a moving point and a fixed Axis-Aligned Box (AABox).

Note
Avoids the sqrt from collisionTimeForMovingPointFixedAABox.
Parameters
pointMoving point.
velocitySphere's velocity.
boxFixed AAbox.
outLocationLocation of collision. [Post Condition]
insideDoes the ray originate inside the box? [Post Condition]
normalBox's surface normal to collision [Post Condition]
Returns
Time til collision. If there is no collision then the return value will be inf().
1232  {
1233 
1234  // Integer representation of a floating-point value.
1235  #define IR(x) ((uint32&)x)
1236 
1237  Inside = true;
1238  const Vector3& MinB = box.low();
1239  const Vector3& MaxB = box.high();
1240  Vector3 MaxT(-1.0f, -1.0f, -1.0f);
1241 
1242  // Find candidate planes.
1243  for (int i = 0; i < 3; ++i) {
1244  if (origin[i] < MinB[i]) {
1245  location[i] = MinB[i];
1246  Inside = false;
1247 
1248  // Calculate T distances to candidate planes
1249  if (IR(dir[i])) {
1250  MaxT[i] = (MinB[i] - origin[i]) / dir[i];
1251  }
1252  } else if (origin[i] > MaxB[i]) {
1253  location[i] = MaxB[i];
1254  Inside = false;
1255 
1256  // Calculate T distances to candidate planes
1257  if (IR(dir[i])) {
1258  MaxT[i] = (MaxB[i] - origin[i]) / dir[i];
1259  }
1260  }
1261  }
1262 
1263  if (Inside) {
1264  // Ray origin inside bounding box
1265  location = origin;
1266  return false;
1267  }
1268 
1269  // Get largest of the maxT's for final choice of intersection
1270  int WhichPlane = 0;
1271  if (MaxT[1] > MaxT[WhichPlane]) {
1272  WhichPlane = 1;
1273  }
1274 
1275  if (MaxT[2] > MaxT[WhichPlane]) {
1276  WhichPlane = 2;
1277  }
1278 
1279  // Check final candidate actually inside box
1280  if (IR(MaxT[WhichPlane]) & 0x80000000) {
1281  // Miss the box
1282  return false;
1283  }
1284 
1285  for (int i = 0; i < 3; ++i) {
1286  if (i != WhichPlane) {
1287  location[i] = origin[i] + MaxT[WhichPlane] * dir[i];
1288  if ((location[i] < MinB[i]) ||
1289  (location[i] > MaxB[i])) {
1290  // On this plane we're outside the box extents, so
1291  // we miss the box
1292  return false;
1293  }
1294  }
1295  }
1296 
1297  // Choose the normal to be the plane normal facing into the ray
1298  normal = Vector3::zero();
1299  normal[WhichPlane] = (dir[WhichPlane] > 0) ? -1.0 : 1.0;
1300 
1301  return true;
1302 
1303  #undef IR
1304 }
static const Vector3 & zero()
Definition: Vector3.cpp:119
#define IR(x)

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

float G3D::CollisionDetection::collisionTimeForMovingPointFixedAABox ( const Vector3 point,
const Vector3 velocity,
const class AABox box,
Vector3 outLocation,
bool inside = ignoreBool,
Vector3 outNormal = ignore 
)
static

If the ray origin is inside the box, returns inf() but inside is set to true. Beta API

[Andrew] Woo, from "Graphics Gems", Academic Press, 1990 [Optimized] code by Pierre Terdiman, 2000 (~20-30% faster on Celeron 500) [Epsilon] value added by Klaus Hartmann [http://www.codercorner.com/RayAABB.cpp]

1216  {
1217 
1218  if (collisionLocationForMovingPointFixedAABox(origin, dir, box, location, Inside, normal)) {
1219  return (location - origin).magnitude();
1220  } else {
1221  return (float)finf();
1222  }
1223 }
float finf()
Definition: g3dmath.cpp:71
static bool collisionLocationForMovingPointFixedAABox(const Vector3 &point, const Vector3 &velocity, const class AABox &box, Vector3 &outLocation, bool &inside=ignoreBool, Vector3 &normal=ignore)
Definition: CollisionDetection.cpp:1226

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

float G3D::CollisionDetection::collisionTimeForMovingPointFixedBox ( const Vector3 point,
const Vector3 velocity,
const class Box box,
Vector3 outLocation,
Vector3 outNormal = ignore 
)
static

Calculates time between the intersection of a moving point and a fixed box.

Note
If the point is already inside the box, no collision: inf is returned.
Parameters
pointMoving point.
velocitySphere's velocity.
boxFixed box.
outLocationPosition of collision. [Post Condition]
outNormalBox's surface normal to collision [Post Condition]
Returns
Time til collision. If there is no collision then the return value will be inf().
1181  {
1182 
1183  double bestTime;
1184 
1185  Vector3 normal;
1186  Vector3 v[4];
1187 
1188  // Prime the loop
1189  int f = 0;
1190  box.getFaceCorners(f, v[0], v[1], v[2], v[3]);
1191  bestTime = collisionTimeForMovingPointFixedRectangle(point, velocity, v[0], v[1], v[2], v[3], location, normal);
1192  outNormal = normal;
1193 
1194  // Check other faces
1195  for (f = 1; f < 6; ++f) {
1196  Vector3 pos;
1197  box.getFaceCorners(f, v[0], v[1], v[2], v[3]);
1198  float time = collisionTimeForMovingPointFixedRectangle(point, velocity, v[0], v[1], v[2], v[3], pos, normal);
1199  if (time < bestTime) {
1200  bestTime = time;
1201  outNormal = normal;
1202  location = pos;
1203  }
1204  }
1205 
1206  return bestTime;
1207 }
static float collisionTimeForMovingPointFixedRectangle(const Vector3 &point, const Vector3 &velocity, const Vector3 &v0, const Vector3 &v1, const Vector3 &v2, const Vector3 &v3, Vector3 &outLocation, Vector3 &outNormal=ignore)
Definition: CollisionDetection.cpp:1308

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

float G3D::CollisionDetection::collisionTimeForMovingPointFixedCapsule ( const Vector3 point,
const Vector3 velocity,
const class Capsule capsule,
Vector3 outLocation,
Vector3 outNormal = ignore 
)
static

Calculates time between the intersection of a moving point and a fixed capsule.

Parameters
pointMoving point.
velocityPoint's velocity.
capsuleFixed capsule.
outLocationLocation of collision. [Post Condition]
outNormalCapsule's surface normal to collision [Post Condition]
Returns
Time til collision. If there is no collision then the return value will be inf().
1547  {
1548 
1549  float timeScale = velocity.magnitude();
1550 
1551  if (timeScale == 0.0f) {
1552  timeScale = 1;
1553  }
1554 
1555  Vector3 direction = velocity / timeScale;
1556  int numIntersections;
1557  Vector3 intersection[2];
1558  findRayCapsuleIntersection(Ray::fromOriginAndDirection(_point, direction), capsule, numIntersections, intersection);
1559 
1560  if (numIntersections == 2) {
1561  // A collision can only occur if there are two intersections. If there is one
1562  // intersection, that one is exiting the capsule.
1563 
1564  // Find the entering intersection (the first one that occurs).
1565  float d0 = (intersection[0] - _point).squaredMagnitude();
1566  float d1 = (intersection[1] - _point).squaredMagnitude();
1567 
1568  // Compute the surface normal (if we aren't ignoring the result)
1569  if (&outNormal != &ignore) {
1570  Vector3 p2 = LineSegment::fromTwoPoints(capsule.point(0), capsule.point(1)).closestPoint(_point);
1571  outNormal = (_point - p2).direction();
1572  }
1573 
1574  if (d0 > d1) {
1575  location = intersection[1];
1576  return sqrt(d1) / timeScale;
1577  } else {
1578  location = intersection[0];
1579  return sqrt(d0) / timeScale;
1580  }
1581  } else {
1582  // No entering intersection discovered; return no intersection.
1583  location = Vector3::inf();
1584  return finf();
1585  }
1586 }
float finf()
Definition: g3dmath.cpp:71
static bool findRayCapsuleIntersection(const Ray &rkRay, const Capsule &rkCapsule, int &riQuantity, Vector3 akPoint[2])
Definition: CollisionDetection.cpp:1519
static LineSegment fromTwoPoints(const Point3 &point1, const Point3 &point2)
Definition: LineSegment.h:47
static Vector3 ignore
Definition: CollisionDetection.h:101
static Ray fromOriginAndDirection(const Point3 &point, const Vector3 &direction)
Definition: Ray.h:87
static const Vector3 & inf()
Definition: Vector3.cpp:124

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

float G3D::CollisionDetection::collisionTimeForMovingPointFixedPlane ( const Vector3 point,
const Vector3 velocity,
const class Plane plane,
Vector3 outLocation,
Vector3 outNormal = ignore 
)
static

Calculates time between the intersection of a moving point and a fixed plane.

Note
This is only a one sided collision test. The side defined by the plane's surface normal is the only one tested. For a two sided collision, call the function once for each side's surface normal.
Parameters
pointMoving point.
velocityPoint's velocity.
planeFixed plane.
outLocationLocation of collision. [Post Condition] (Infinite vector on no collision)
outNormalPlane's surface normal. [Post Condition]
Returns
Time til collision. If there is no collision then the return value will be inf().
852  {
853 
854  // Solve for the time at which normal.dot(point + velocity) + d == 0.
855  float d;
856  Vector3 normal;
857  plane.getEquation(normal, d);
858 
859  const float vdotN = velocity.dot(normal);
860  const float pdotN = point.dot(normal);
861 
862  if (fuzzyEq(pdotN + d, 0.0f)) {
863  // The point is *in* the plane.
864  location = point;
865  outNormal = normal;
866  return 0;
867  }
868 
869  if (vdotN >= 0.0f) {
870  // no collision will occur
871  location = Vector3::inf();
872  return finf();
873  }
874 
875  const float t = -(pdotN + d) / vdotN;
876  if (t < 0) {
877  location = Vector3::inf();
878  return finf();
879  } else {
880  location = point + velocity * t;
881  outNormal = normal;
882  return t;
883  }
884 }
float finf()
Definition: g3dmath.cpp:71
static const Vector3 & inf()
Definition: Vector3.cpp:124
bool fuzzyEq(double a, double b)
Definition: g3dmath.h:857

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

float G3D::CollisionDetection::collisionTimeForMovingPointFixedRectangle ( const Vector3 point,
const Vector3 velocity,
const Vector3 v0,
const Vector3 v1,
const Vector3 v2,
const Vector3 v3,
Vector3 outLocation,
Vector3 outNormal = ignore 
)
static

Calculates time between the intersection of a moving point and a fixed rectangle defined by the points v0, v1, v2, & v3.

Note
This is only a one sided collision test. The side defined by the rectangle's surface normal is the only one tested. For a two sided collision, call the function once for each side's surface normal.
Parameters
pointMoving point.
velocitySphere's velocity.
v0Rectangle vertex 1.
v1Rectangle vertex 2.
v2Rectangle vertex 3
v3Rectangle vertex 4.
outLocationLocation of collision [Post Condition]
outNormalRectangle's surface normal. [Post Condition]
Returns
Time til collision. If there is no collision then the return value will be inf().
1316  {
1317 
1318  Plane plane = Plane(v0, v1, v2);
1319 
1320  float time = collisionTimeForMovingPointFixedPlane(point, velocity, plane, location, outNormal);
1321 
1322  if (time == finf()) {
1323  // No collision is ever going to happen
1324  return time;
1325  }
1326 
1327  if (isPointInsideRectangle(v0, v1, v2, v3, plane.normal(), location)) {
1328  // The intersection point is inside the rectangle; that is the location where
1329  // the point hits the rectangle.
1330  return time;
1331  } else {
1332  return finf();
1333  }
1334 }
float finf()
Definition: g3dmath.cpp:71
static bool isPointInsideRectangle(const Vector3 &v0, const Vector3 &v1, const Vector3 &v2, const Vector3 &v3, const Vector3 &normal, const Vector3 &point)
Definition: CollisionDetection.cpp:2086
static float collisionTimeForMovingPointFixedPlane(const Vector3 &point, const Vector3 &velocity, const class Plane &plane, Vector3 &outLocation, Vector3 &outNormal=ignore)
Definition: CollisionDetection.cpp:847

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

float G3D::CollisionDetection::collisionTimeForMovingPointFixedSphere ( const Vector3 point,
const Vector3 velocity,
const class Sphere sphere,
Vector3 outLocation,
Vector3 outNormal = ignore,
bool  solid = false 
)
static

Calculates time between the intersection of a moving point and a fixed sphere.

Note
When ray is starts inside the rectangle, the exiting intersection is detected.
Parameters
pointMoving point.
velocityPoint's velocity.
sphereFixed Sphere.
outLocationLocation of collision. [Post Condition]
outNormalSphere's surface normal to collision [Post Condition]
solidIf true, rays inside the sphere immediately intersect (good for collision detection). If false, they hit the opposite side of the sphere (good for ray tracing).
Returns
Time until collision. If there is no collision then the return value will be inf().
983  {
984 
985  if (solid && sphere.contains(point)) {
986  location = point;
987  outNormal = (point - sphere.center).direction();
988  return 0.0f;
989  }
990 
991  float speed = velocity.magnitude();
992  const Vector3& direction = velocity / speed;
993 
994  // length of the axis between the start and the sphere
995  const Vector3& L = sphere.center - point;
996  float d = L.dot(direction);
997 
998  float L2 = L.dot(L);
999  float R2 = square(sphere.radius);
1000  float D2 = square(d);
1001 
1002  if ((d < 0.0f) && (L2 > R2)) {
1003  location = Vector3::inf();
1004  return finf();
1005  }
1006 
1007  const float M2 = L2 - D2;
1008 
1009  if (M2 > R2) {
1010  location = Vector3::inf();
1011  return finf();
1012  }
1013 
1014  float q = sqrt(R2 - M2);
1015  float time;
1016 
1017  if (L2 > R2) {
1018  time = d - q;
1019  } else {
1020  time = d + q;
1021  }
1022 
1023  time /= speed;
1024 
1025  location = point + velocity * time;
1026  outNormal = (location - sphere.center).direction();
1027 
1028  return time;
1029 }
float finf()
Definition: g3dmath.cpp:71
double square(double fValue)
Definition: g3dmath.h:698
static const Vector3 & inf()
Definition: Vector3.cpp:124

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

static float G3D::CollisionDetection::collisionTimeForMovingPointFixedTriangle ( const Vector3 orig,
const Vector3 dir,
const Vector3 v0,
const Vector3 v1,
const Vector3 v2 
)
inlinestatic

Calculates time between the intersection of a moving point and a fixed triangle.

Note
This is only a one sided collision test. The side defined by the triangle's surface normal is the only one tested. For a two sided collision, call the function once for each side's surface normal.
Parameters
origMoving point.
dirPoint's velocity.
v0Triangle vertex 1.
v1Triangle vertex 2.
v2Triangle vertex 3
Returns
Time til collision. If there is no collision then the return value will be inf().
492  {
493  return Ray::fromOriginAndDirection(orig, dir).intersectionTime(v0, v1, v2);
494  }
static Ray fromOriginAndDirection(const Point3 &point, const Vector3 &direction)
Definition: Ray.h:87
float intersectionTime(const class Sphere &sphere, bool solid=false) const
Definition: Ray.cpp:179

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

static float G3D::CollisionDetection::collisionTimeForMovingPointFixedTriangle ( const Vector3 orig,
const Vector3 dir,
const Vector3 v0,
const Vector3 v1,
const Vector3 v2,
Vector3 location 
)
inlinestatic

Calculates time between the intersection of a moving point and a fixed triangle.

Note
This is only a one sided collision test. The side defined by the triangle's surface normal is the only one tested. For a two sided collision, call the function once for each side's surface normal.
Parameters
origMoving point.
dirPoint's velocity.
v0Triangle vertex 1.
v1Triangle vertex 2.
v2Triangle vertex 3
locationLocation of collision. [Post Condition] (Infinite vector on no collision)
Returns
Time til collision. If there is no collision then the return value will be inf().
521  {
522  float t = collisionTimeForMovingPointFixedTriangle(orig, dir, v0, v1, v2);
523  if (t < finf()) {
524  location = orig + dir * t;
525  }
526  return t;
527  }
float finf()
Definition: g3dmath.cpp:71
static float collisionTimeForMovingPointFixedTriangle(const Vector3 &orig, const Vector3 &dir, const Vector3 &v0, const Vector3 &v1, const Vector3 &v2)
Definition: CollisionDetection.h:487

+ Here is the call graph for this function:

static float G3D::CollisionDetection::collisionTimeForMovingPointFixedTriangle ( const Vector3 orig,
const Vector3 dir,
const Triangle tri,
Vector3 location = ignore,
Vector3 normal = ignore 
)
inlinestatic

Calculates time between the intersection of a moving point and a fixed triangle.

Note
This is only a one sided collision test. The side defined by the triangle's surface normal is the only one tested. For a two sided collision, call the function once for each side's surface normal.
Parameters
origMoving point.
dirPoint's velocity.
triFixed triangle.
locationLocation of collision. [Post Condition] (Infinite vector on no collision)
normalTriangle's surface normal. [Post Condition]
Returns
Time til collision. If there is no collision then the return value will be inf().
552  {
553 
555  orig, dir, tri.vertex(0), tri.vertex(1), tri.vertex(2));
556 
557  if ((t < finf()) && (&location != &ignore)) {
558  location = orig + dir * t;
559  normal = tri.normal();
560  }
561  return t;
562  }
float finf()
Definition: g3dmath.cpp:71
static Vector3 ignore
Definition: CollisionDetection.h:101
static float collisionTimeForMovingPointFixedTriangle(const Vector3 &orig, const Vector3 &dir, const Vector3 &v0, const Vector3 &v1, const Vector3 &v2)
Definition: CollisionDetection.h:487

+ Here is the call graph for this function:

static float G3D::CollisionDetection::collisionTimeForMovingPointFixedTriangle ( const Vector3 orig,
const Vector3 dir,
const Vector3 v0,
const Vector3 v1,
const Vector3 v2,
Vector3 location,
Vector3 normal 
)
inlinestatic

Calculates time between the intersection of a moving point and a fixed triangle.

Note
This is only a one sided collision test. The side defined by the triangle's surface normal is the only one tested. For a two sided collision, call the function once for each side's surface normal.
Parameters
origMoving point.
dirPoint's velocity.
v0Triangle vertex 1.
v1Triangle vertex 2.
v2Triangle vertex 3
locationLocation of collision. [Post Condition] (Infinite vector on no collision)
normalTriangle's surface normal. [Post Condition]
Returns
Time til collision. If there is no collision then the return value will be inf().
591  {
592  float t = collisionTimeForMovingPointFixedTriangle(orig, dir, v0, v1, v2);
593  if (t < finf()) {
594  location = orig + dir * t;
595  normal = (v1 - v0).cross(v2 - v0).direction();
596  }
597  return t;
598  }
float finf()
Definition: g3dmath.cpp:71
Vector3 direction() const
Definition: Vector3.h:756
static float collisionTimeForMovingPointFixedTriangle(const Vector3 &orig, const Vector3 &dir, const Vector3 &v0, const Vector3 &v1, const Vector3 &v2)
Definition: CollisionDetection.h:487
Vector3 cross(const Vector3 &v1, const Vector3 &v2)
Definition: vectorMath.h:144

+ Here is the call graph for this function:

float G3D::CollisionDetection::collisionTimeForMovingSphereFixedBox ( const class Sphere sphere,
const Vector3 velocity,
const class Box box,
Vector3 outLocation,
Vector3 outNormal = ignore 
)
static

Calculates time between the intersection of a moving sphere and a fixed box.

Note
This function will not detect an intersection between a moving object that is already interpenetrating the fixed object.
Parameters
sphereMoving sphere.
velocitySphere's velocity.
boxFixed box.
outLocationLocation of collision – not center position of sphere at the collision time. [Post Condition]
outNormalBox's surface normal to collision [Post Condition]
Returns
Time til collision. If there is no collision then the return value will be inf().
1795  {
1796 
1797  if (fixedSolidSphereIntersectsFixedSolidBox(sphere, box)) {
1798  // TODO: Compute more useful location and normal?
1799  location = sphere.center;
1800  outNormal = Vector3::zero();
1801  return 0;
1802  }
1803 
1804  float bestTime;
1805 
1806  Vector3 v[4];
1807  int f = 0;
1808  box.getFaceCorners(f, v[0], v[1], v[2], v[3]);
1809  bestTime = collisionTimeForMovingSphereFixedRectangle(sphere, velocity, v[0], v[1], v[2], v[3], location, outNormal);
1810 
1811  for (f = 1; f < 6; ++f) {
1812  Vector3 pos, normal;
1813  box.getFaceCorners(f, v[0], v[1], v[2], v[3]);
1814  float time = collisionTimeForMovingSphereFixedRectangle(sphere, velocity, v[0], v[1], v[2], v[3], pos, normal);
1815  if (time < bestTime) {
1816  bestTime = time;
1817  location = pos;
1818  outNormal = normal;
1819  }
1820  }
1821 
1822  return bestTime;
1823 }
static float collisionTimeForMovingSphereFixedRectangle(const class Sphere &sphere, const Vector3 &velocity, const Vector3 &v0, const Vector3 &v1, const Vector3 &v2, const Vector3 &v3, Vector3 &outLocation, Vector3 &outNormal=ignore)
Definition: CollisionDetection.cpp:1750
static const Vector3 & zero()
Definition: Vector3.cpp:119
static bool fixedSolidSphereIntersectsFixedSolidBox(const Sphere &sphere, const Box &box)
Definition: CollisionDetection.cpp:2180

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

float G3D::CollisionDetection::collisionTimeForMovingSphereFixedCapsule ( const class Sphere sphere,
const Vector3 velocity,
const class Capsule capsule,
Vector3 outLocation,
Vector3 outNormal = ignore 
)
static

Calculates time between the intersection of a moving sphere and a fixed capsule.

Note
This won't detect a collision if the sphere is already interpenetrating the capsule.
Parameters
sphereMoving sphere.
velocitySphere's velocity.
capsuleFixed capsule.
outLocationLocation of collision – not center position of sphere at the collision time. [Post Condition]
outNormalCapsule's surface normal to the collision [Post Condition]
Returns
Time til collision. If there is no collision then the return value will be inf().
1831  {
1832 
1833  (void)outNormal;
1834 
1835  Capsule _capsule(capsule.point(0), capsule.point(1), capsule.radius() + sphere.radius);
1836 
1837  Vector3 normal;
1838  double time = collisionTimeForMovingPointFixedCapsule(sphere.center, velocity, _capsule, location, normal);
1839 
1840  if (time < finf()) {
1841  // Location is now the position of the center of the sphere at the time of collision.
1842  // We have to adjust the collision location for the size of the sphere.
1843  location -= sphere.radius * normal;
1844  }
1845 
1846  return time;
1847 }
float finf()
Definition: g3dmath.cpp:71
static float collisionTimeForMovingPointFixedCapsule(const Vector3 &point, const Vector3 &velocity, const class Capsule &capsule, Vector3 &outLocation, Vector3 &outNormal=ignore)
Definition: CollisionDetection.cpp:1542

+ Here is the call graph for this function:

float G3D::CollisionDetection::collisionTimeForMovingSphereFixedPlane ( const class Sphere sphere,
const Vector3 velocity,
const class Plane plane,
Vector3 outLocation,
Vector3 outNormal = ignore 
)
static

Calculates time between the intersection of a moving sphere and a fixed triangle.

Parameters
sphereMoving sphere.
velocitySphere's velocity.
planeFixed Plane.
outLocationLocation of collision – not center position of sphere at the collision time. [Post Condition]
outNormalBox's surface normal to collision [Post Condition]
Returns
Time til collision. If there is no collision then the return value will be inf().
1594  {
1595 
1596  if (sphere.radius == 0) {
1597  // Optimization for zero radius sphere
1598  return collisionTimeForMovingPointFixedPlane(sphere.center, velocity, plane, location, outNormal);
1599  }
1600 
1601  // The world-space collision point, which lies on the surface of the sphere, will be the point at
1602  // center + velocity * time - (radius * planeNormal). Collisions only occur when
1603  // the sphere is travelling into the plane.
1604 
1605  float d;
1606  plane.getEquation(outNormal, d);
1607 
1608  // Rate at which the sphere is approaching the plane
1609  const float vdotN = velocity.dot(outNormal);
1610 
1611  if (fuzzyGt(vdotN, 0)) {
1612  // No collision when the sphere is moving towards a backface.
1613  location = Vector3::inf();
1614  return (float)finf();
1615  }
1616 
1617  // Initial distance from the sphere center to the plane
1618  const float distance = sphere.center.dot(outNormal) + d;
1619 
1620  if (fuzzyLe(G3D::abs(distance), sphere.radius)) {
1621  // Already interpenetrating
1622  location = sphere.center - distance * outNormal;
1623  return 0;
1624  } else {
1625  // The point on the sphere (in world space) that will eventually first contact the plane
1626  const Point3& point = sphere.center - (sphere.radius * outNormal);
1627 
1628  // The problem is now reduced to finding when the point hits the plane
1629  return collisionTimeForMovingPointFixedPlane(point, velocity, plane, location, outNormal);
1630  }
1631 
1632 }
float finf()
Definition: g3dmath.cpp:71
double abs(double fValue)
Definition: g3dmath.h:617
double distance(double x, double y)
Definition: g3dmath.h:731
bool fuzzyGt(double a, double b)
Definition: g3dmath.h:865
static float collisionTimeForMovingPointFixedPlane(const Vector3 &point, const Vector3 &velocity, const class Plane &plane, Vector3 &outLocation, Vector3 &outNormal=ignore)
Definition: CollisionDetection.cpp:847
static const Vector3 & inf()
Definition: Vector3.cpp:124
Vector3 Point3
Definition: Vector3.h:820
bool fuzzyLe(double a, double b)
Definition: g3dmath.h:877

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

float G3D::CollisionDetection::collisionTimeForMovingSphereFixedRectangle ( const class Sphere sphere,
const Vector3 velocity,
const Vector3 v0,
const Vector3 v1,
const Vector3 v2,
const Vector3 v3,
Vector3 outLocation,
Vector3 outNormal = ignore 
)
static

Calculates time between the intersection of a moving sphere and a fixed rectangle defined by the points v0, v1, v2, & v3.

Parameters
sphereMoving sphere.
velocitySphere's velocity.
v0Rectangle vertex 1.
v1Rectangle vertex 2.
v2Rectangle vertex 3
v3Rectangle vertex 4.
outLocationLocation of collision – not center position of sphere at the collision time. [Post Condition]
outNormalBox's surface normal to collision [Post Condition]
Returns
Time til collision. If there is no collision then the return value will be inf().
1758  {
1759 
1760  Plane plane(v0, v1, v2);
1761 
1762  float time = collisionTimeForMovingSphereFixedPlane(sphere, velocity, plane, location, outNormal);
1763 
1764  if (time == finf()) {
1765  // No collision is ever going to happen
1766  return time;
1767  }
1768 
1769  if (isPointInsideRectangle(v0, v1, v2, v3, plane.normal(), location)) {
1770  // The intersection point is inside the rectangle; that is the location where
1771  // the sphere hits the rectangle.
1772  return time;
1773  }
1774 
1775  // Switch over to moving the rectangle towards a fixed sphere and see at what time
1776  // they will hit.
1777 
1778  Vector3 point = closestPointToRectanglePerimeter(v0, v1, v2, v3, sphere.center);
1779 
1780  Vector3 dummy;
1781  double t = collisionTimeForMovingPointFixedSphere(point, -velocity, sphere, location, dummy);
1782 
1783  // Normal is the plane normal, location is the original location of the point.
1784  location = point;
1785 
1786  return t;
1787 }
float finf()
Definition: g3dmath.cpp:71
static bool isPointInsideRectangle(const Vector3 &v0, const Vector3 &v1, const Vector3 &v2, const Vector3 &v3, const Vector3 &normal, const Vector3 &point)
Definition: CollisionDetection.cpp:2086
static Vector3 closestPointToRectanglePerimeter(const Vector3 &v0, const Vector3 &v1, const Vector3 &v2, const Vector3 &v3, const Vector3 &point)
Definition: CollisionDetection.cpp:2099
static float collisionTimeForMovingPointFixedSphere(const Vector3 &point, const Vector3 &velocity, const class Sphere &sphere, Vector3 &outLocation, Vector3 &outNormal=ignore, bool solid=false)
Definition: CollisionDetection.cpp:977
static float collisionTimeForMovingSphereFixedPlane(const class Sphere &sphere, const Vector3 &velocity, const class Plane &plane, Vector3 &outLocation, Vector3 &outNormal=ignore)
Definition: CollisionDetection.cpp:1589

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

float G3D::CollisionDetection::collisionTimeForMovingSphereFixedSphere ( const Sphere sphere,
const Vector3 velocity,
const Sphere fixedSphere,
Vector3 outLocation,
Vector3 outNormal = ignore 
)
static

Calculates time between the intersection of a moving sphere and a fixed sphere.

If they are already interpenetrating, returns 0 and location is the closest point on the surface of the fixed sphere to the center of the moving sphere.

Parameters
sphereMoving sphere.
velocitySphere's velocity.
fixedSphereFixed Sphere.
outLocationLocation of collision – not center position of sphere at the collision time. [Post Condition]
outNormalMoving sphere's surface normal to collision [Post Condition]
Returns
Time until collision. If there is no collision then the return value will be inf().
1037  {
1038 
1039  const Vector3& sep = (fixedSphere.center - movingSphere.center);
1040  float sepLen = sep.squaredLength();
1041  if (sepLen < square(movingSphere.radius + fixedSphere.radius)) {
1042  // Interpenetrating
1043  outNormal = sep.directionOrZero();
1044  location = fixedSphere.center - outNormal * fixedSphere.radius;
1045  return 0;
1046  }
1047 
1049  (movingSphere.center, velocity,
1050  Sphere(fixedSphere.center, fixedSphere.radius + movingSphere.radius),
1051  location, outNormal);
1052 
1053  if (time < finf()) {
1054  // Location is now the center of the moving sphere at the collision time.
1055  // Adjust for the size of the moving sphere. Two spheres always collide
1056  // along a line between their centers.
1057  location += (location - fixedSphere.center) * movingSphere.radius / fixedSphere.radius;
1058  }
1059 
1060  return time;
1061 }
float finf()
Definition: g3dmath.cpp:71
double square(double fValue)
Definition: g3dmath.h:698
static float collisionTimeForMovingPointFixedSphere(const Vector3 &point, const Vector3 &velocity, const class Sphere &sphere, Vector3 &outLocation, Vector3 &outNormal=ignore, bool solid=false)
Definition: CollisionDetection.cpp:977

+ Here is the call graph for this function:

float G3D::CollisionDetection::collisionTimeForMovingSphereFixedTriangle ( const class Sphere sphere,
const Vector3 velocity,
const Triangle triangle,
Vector3 outLocation,
float  b[3] = (float*)&ignore 
)
static

Calculates time between the intersection of a moving sphere and a fixed triangle.

Parameters
sphereThe moving sphere.
velocityThe sphere's velocity.
triangleSingle-sided fixed triangle.
outLocationLocation of collision, if collision occurs – not center position of sphere at the collision time. If there is interpenetration at the start, this point may be inside the sphere.
bBarycentric coordinates. These are not valid unless collision occurs.
Returns
Time until collision. If there is no collision then the return value will be finf().
1640  {
1641 
1642  if (velocity.dot(triangle.normal()) > 0.0f) {
1643  // No collision if moving towards a backface
1644  return finf();
1645  }
1646  Vector3 dummy;
1647  const float time = collisionTimeForMovingSphereFixedPlane(sphere, velocity, triangle.plane(),
1648  outLocation, dummy);
1649 
1650  if (time == finf()) {
1651  // No collision is ever going to happen
1652  return time;
1653  }
1654 
1655  // We will hit the plane of the triangle at *time*. See if
1656  // the intersection point actually is within the triangle.
1657 
1658  if (isPointInsideTriangle(triangle.vertex(0), triangle.vertex(1), triangle.vertex(2), triangle.normal(),
1659  outLocation, b, triangle.primaryAxis())) {
1660 
1661  // The intersection point is inside the triangle; that is the location where
1662  // the sphere hits the triangle.
1663 
1664 # ifdef G3D_DEBUG
1665  {
1666  // Internal consistency checks
1667  debugAssertM(b[0] >= 0.0 && b[0] <= 1.0f, "Intersection is outside triangle.");
1668  debugAssertM(b[1] >= 0.0 && b[1] <= 1.0f, "Intersection is outside triangle.");
1669  debugAssertM(b[2] >= 0.0 && b[2] <= 1.0f, "Intersection is outside triangle.");
1670  const Vector3& blend =
1671  b[0] * triangle.vertex(0) +
1672  b[1] * triangle.vertex(1) +
1673  b[2] * triangle.vertex(2);
1674  debugAssertM(blend.fuzzyEq(outLocation), "Barycentric coords don't match intersection.");
1675  // Call again so that we can debug the problem
1676  // isPointInsideTriangle(triangle.vertex(0), triangle.vertex(1), triangle.vertex(2), triangle.normal(),
1677  // outLocation, b, triangle.primaryAxis());
1678  }
1679 # endif
1680 
1681  return time;
1682  }
1683 
1684  // The collision (if it exists) is with a point on the triangle perimeter.
1685  // Switch over to moving the triangle towards a fixed sphere and see at what time
1686  // they will hit.
1687 
1688  // Closest point on the triangle to the sphere intersection with the plane.
1689  int edgeIndex;
1690  const Vector3& point = closestPointOnTrianglePerimeter(triangle._vertex, triangle.edgeDirection,
1691  triangle.edgeMagnitude, outLocation, edgeIndex);
1692 
1693  float t = 0;
1694  if (! sphere.contains(point)) {
1695  // The point is outside the sphere--see when it will hit
1696  t = collisionTimeForMovingPointFixedSphere(point, -velocity, sphere, dummy, dummy);
1697  }
1698 
1699  if (t < finf()) {
1700  outLocation = point;
1701  // Compute Barycentric coords
1702 
1703  // Index of the next vertex
1704  static const int next[] = {1, 2, 0};
1705 
1706  // Project along the edge in question.
1707  // Avoid sqrt by taking advantage of the existing edgeDirection unit vector.
1708  b[next[edgeIndex]] = (outLocation - triangle._vertex[edgeIndex]).dot
1709  (triangle.edgeDirection[edgeIndex]) / triangle.edgeMagnitude[edgeIndex];
1710 
1711  b[edgeIndex] = 1.0f - b[next[edgeIndex]];
1712 
1713  b[next[next[edgeIndex]]] = 0.0f;
1714 
1715 # ifdef G3D_DEBUG
1716  {
1717  // Internal consistency checks
1718  for (int i = 0; i < 3; ++i) {
1719  debugAssertM(fuzzyGe(b[i], 0.0f) && fuzzyLe(b[i], 1.0f), "Intersection is outside triangle.");
1720  }
1721  Vector3 blend =
1722  b[0] * triangle.vertex(0) +
1723  b[1] * triangle.vertex(1) +
1724  b[2] * triangle.vertex(2);
1725  debugAssertM(blend.fuzzyEq(outLocation),
1726  format("Barycentric coords don't match intersection. %s != %s",
1727  blend.toString().c_str(),
1728  outLocation.toString().c_str()));
1729 
1730  // Call again so that we can debug the problem
1731  collisionTimeForMovingPointFixedSphere(point, -velocity, sphere, dummy, dummy);
1732  }
1733 # endif
1734 
1735  // Due to tiny roundoffs, these values might be slightly out of bounds.
1736  // Ensure that they are legal. Note that the above debugging code
1737  // verifies that we are not clamping truly illegal values.
1738  for (int i = 0; i < 3; ++i) {
1739  b[i] = clamp(b[i], 0.0f, 1.0f);
1740  }
1741  }
1742 
1743  // The collision occured at the point, if it occured. The normal
1744  // was the plane normal, computed above.
1745 
1746  return t;
1747 }
float finf()
Definition: g3dmath.cpp:71
Definition: adtfile.h:46
int next(int i, int n)
Definition: RecastContour.cpp:469
double clamp(double val, double low, double hi)
Definition: g3dmath.h:571
#define debugAssertM(exp, message)
Definition: debugAssert.h:161
static bool isPointInsideTriangle(const Vector3 &v0, const Vector3 &v1, const Vector3 &v2, const Vector3 &normal, const Vector3 &point, float b[3], Vector3::Axis primaryAxis=Vector3::DETECT_AXIS)
Definition: CollisionDetection.cpp:2009
static Vector3 closestPointOnTrianglePerimeter(const Vector3 &v0, const Vector3 &v1, const Vector3 &v2, const Vector3 &point)
Definition: CollisionDetection.cpp:1935
std::string __cdecl format(const char *fmt...) G3D_CHECK_PRINTF_ARGS
static float collisionTimeForMovingPointFixedSphere(const Vector3 &point, const Vector3 &velocity, const class Sphere &sphere, Vector3 &outLocation, Vector3 &outNormal=ignore, bool solid=false)
Definition: CollisionDetection.cpp:977
static float collisionTimeForMovingSphereFixedPlane(const class Sphere &sphere, const Vector3 &velocity, const class Plane &plane, Vector3 &outLocation, Vector3 &outNormal=ignore)
Definition: CollisionDetection.cpp:1589
float dot(float a, float b)
Definition: g3dmath.h:445
bool fuzzyGe(double a, double b)
Definition: g3dmath.h:869
bool fuzzyLe(double a, double b)
Definition: g3dmath.h:877

+ Here is the call graph for this function:

bool G3D::CollisionDetection::conservativeBoxBoxTest ( const Vector3 a,
const Vector3 b,
const Vector3 D 
)
static

Performs a simple bounding sphere check between two boxes to determine whether these boxes could possibly intersect. This is a very cheap operation (three dot products, two sqrts and a few others). If it returns true, an intersection is possible, but not necessarily guaranteed.

Parameters
aVector from box A's center to an outer vertex
bVector from box B's center to an outer vertex
DDistance between the centers of the two boxes
Returns
true - if possible intersection
false - otherwise (This does not guarantee an intersection)
240  {
241  // do a quick bounding sphere test because it is relatively
242  // cheap, (three dot products, two sqrts, and a few others)
243  double boxRadius1 = a.magnitude();
244  double boxRadius2 = b.magnitude();
245  return (D.squaredMagnitude() < square(boxRadius1 + boxRadius2));
246 }
double square(double fValue)
Definition: g3dmath.h:698

+ Here is the call graph for this function:

void G3D::CollisionDetection::fillSolidBoxSolidBoxInfo ( const Box box1,
const Box box2,
Vector3 a,
Vector3 b,
Vector3 D,
double *  c,
double *  ca,
double *  ad,
double *  bd 
)
static

Creates a set of standard information about two boxes in order to solve for their collision. This information includes a vector to the radius of the bounding sphere for each box, the vector between each boxes' center and a series of dot products between differing important vectors. These dot products include those between the axes of both boxes (signed and unsigned values), and the dot products between all the axes of box1 and the boxes' center vector and box2 and the boxes' center vector.

Precondition
The following space requirements must be met:
  • c[] 9 elements
  • ca[] 9 elements
  • ad[] 3 elements
  • bd[] 3 elements

[dobted] from David Eberly's papers, variables used in this function correspond to variables used in pages 6 and 7 in the pdf http://www.magic-software.com/Intersection.html http://www.magic-software.com/Documentation/DynamicCollisionDetection.pdf

Note
Links are out-dated. (Kept to preserve origin and authorship)
Parameters
box1Box 1
box2Box 2
aBox 1's bounding sphere vector
bBox 2's bounding sphere vector
DVector between Box 1 and Box 2's center points
cPointer to array of dot products of the axes of Box 1 and Box 2.
caPointer to array of unsigned dot products of the axes of Box 1 and Box 2.
adPointer to array of dot products of Box 1 axes and D.
bdPointer to array of dot products of Box 2 axes and D.
211  {
212  // length between center and each side of box1 and box2
213  a = box1.extent() * 0.5;
214  b = box2.extent() * 0.5;
215 
216  // difference between centers of box1 and box2
217  D = box2.center() - box1.center();
218 
219  // store the value of all possible dot products between the
220  // axes of box1 and box2, c_{row, col} in the Eberly paper
221  // corresponds to c[row * 3 + col] for this 9 element array.
222  //
223  // c[] holds signed values, ca[] hold absolute values
224  for (int i = 0; i < 9; ++i) {
225  c[i] = dot(box1.axis(i / 3), box2.axis(i % 3));
226  ca[i] = fabs(c[i]);
227  }
228 
229  // store all possible dot products between the axes of box1 and D,
230  // as well as the axes of box2 and D
231  for (int i = 0; i < 3; ++i) {
232  ad[i] = dot(box1.axis(i), D);
233  bd[i] = dot(box2.axis(i), D);
234  }
235 }
float dot(float a, float b)
Definition: g3dmath.h:445

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

bool G3D::CollisionDetection::fixedSolidBoxIntersectsFixedSolidBox ( const Box box1,
const Box box2,
const int  lastSeparatingAxis = -1 
)
static

Determines whether two fixed solid boxes intersect.

Note
To speed up collision detection, the lastSeparatingAxis from the previous time step can be passed in and that plane can be checked first. If the separating axis was not saved, or if the two boxes intersected then lastSeparatingAxis should equal -1.

[Adobted] from David Eberly's papers, variables used in this function correspond to variables used in pages 6 and 7 in the pdf http://www.magic-software.com/Intersection.html http://www.magic-software.com/Documentation/DynamicCollisionDetection.pdf

Parameters
box1Box 1.
box2Box 2.
lastSeparatingAxisLast separating axis. (optimization - see note)
Returns
true - Intersection.
false - otherwise.
254  {
255  // for explanations of the variable please refer to the
256  // paper and fillSolidBoxSolidBoxInfo()
257  Vector3 a;
258  Vector3 b;
259  Vector3 D;
260  double c[9];
261  double ca[9];
262  double ad[3];
263  double bd[3];
264 
265  fillSolidBoxSolidBoxInfo(box1, box2, a, b, D, c, ca, ad, bd);
266 
267  int dummy1, dummy2;
268  bool parallelAxes = parallelAxisForSolidBoxSolidBox(ca, 0.00001,
269  dummy1, dummy2);
270 
271  // check the separating axis from the last time step
272  if (lastSeparatingAxis != -1 &&
273  (lastSeparatingAxis < 6 || !parallelAxes)) {
274  double projectedDistance = projectedDistanceForSolidBoxSolidBox(
275  lastSeparatingAxis, a, b, D, c, ca, ad, bd);
276 
277  // the separating axis from the last time step is still
278  // valid, the boxes do not intersect
279  if (projectedDistance > 0.0) {
280  return false;
281  }
282  }
283 
284  // test if the boxes can be separated by a plane normal to
285  // any of the three axes of box1, any of the three axes of box2,
286  // or any of the 9 possible cross products of axes from box1
287  // and box2
288  for (int i = 0; i < 15; ++i) {
289  // do not need to check edge-edge cases if any two of
290  // the axes are parallel
291  if (parallelAxes && i == 6) {
292  return true;
293  }
294 
295  double projectedDistance =
296  projectedDistanceForSolidBoxSolidBox(i, a, b, D, c, ca, ad, bd);
297 
298  // found a separating axis, the boxes do not intersect
299  if (projectedDistance > 0.0) {
300  return false;
301  }
302  }
303 
304  return true;
305 }
static void fillSolidBoxSolidBoxInfo(const Box &box1, const Box &box2, Vector3 &a, Vector3 &b, Vector3 &D, double *c, double *ca, double *ad, double *bd)
Definition: CollisionDetection.cpp:202
static bool parallelAxisForSolidBoxSolidBox(const double *ca, const double epsilon, int &axis1, int &axis2)
Definition: CollisionDetection.cpp:183
static float projectedDistanceForSolidBoxSolidBox(const int separatingAxisIndex, const Vector3 &a, const Vector3 &b, const Vector3 &D, const double *c, const double *ca, const double *ad, const double *bd)
Definition: CollisionDetection.cpp:69

+ Here is the call graph for this function:

bool G3D::CollisionDetection::fixedSolidBoxIntersectsFixedTriangle ( const AABox box,
const Triangle triangle 
)
static
2368  {
2369 
2370  // use separating axis theorem to test overlap between triangle and box
2371  // need to test for overlap in these directions:
2372  // 1) the {x,y,z}-directions (actually, since we use the AABB of the triangle
2373  // we do not even need to test these)
2374  // 2) normal of the triangle
2375  // 3) crossproduct(edge from tri, {x,y,z}-direction)
2376  // this gives 3x3=9 more tests
2377 
2378  // This is the fastest branch (on Sun).
2379  // Move the triangle to the object space of the box
2380  // Triangle vertices in box object space
2381 
2382  const Vector3& boxcenter = box.center();
2383  const Vector3& boxhalfsize = box.extent() * 0.5f;
2384 
2385  const Vector3& v0 = tri.vertex(0) - boxcenter;
2386  const Vector3& v1 = tri.vertex(1) - boxcenter;
2387  const Vector3& v2 = tri.vertex(2) - boxcenter;
2388 
2389  // Compute triangle edges in object space
2390  const Vector3& e0 = v1 - v0;
2391  const Vector3& e1 = v2 - v1;
2392  const Vector3& e2 = v0 - v2;
2393 
2394  // Bullet 3:
2395  // test the 9 tests first (this was faster)
2396  float min,max,p0,p1,p2,rad;
2397  Vector3 fe;
2398 
2399  fe = abs(e0);
2400  AXISTEST_X01(e0[Z], e0[Y], fe[Z], fe[Y]);
2401  AXISTEST_Y02(e0[Z], e0[X], fe[Z], fe[X]);
2402  AXISTEST_Z12(e0[Y], e0[X], fe[Y], fe[X]);
2403 
2404  fe = abs(e1);
2405  AXISTEST_X01(e1[Z], e1[Y], fe[Z], fe[Y]);
2406  AXISTEST_Y02(e1[Z], e1[X], fe[Z], fe[X]);
2407  AXISTEST_Z0 (e1[Y], e1[X], fe[Y], fe[X]);
2408 
2409  fe = abs(e2);
2410  AXISTEST_X2 (e2[Z], e2[Y], fe[Z], fe[Y]);
2411  AXISTEST_Y1 (e2[Z], e2[X], fe[Z], fe[X]);
2412  AXISTEST_Z12(e2[Y], e2[X], fe[Y], fe[X]);
2413 
2414  // Bullet 1:
2415  // first test overlap in the {x,y,z}-directions
2416  // find min, max of the triangle each direction, and test for overlap in
2417  // that direction -- this is equivalent to testing a minimal AABB around
2418  // the triangle against the AABB
2419 
2420  // test in X-direction
2421  FINDMINMAX(v0[X],v1[X],v2[X],min,max);
2422  if (min > boxhalfsize[X] || max < -boxhalfsize[X]) {
2423  return false;
2424  }
2425 
2426  // test in Y-direction
2427  FINDMINMAX(v0[Y],v1[Y],v2[Y],min,max);
2428  if (min > boxhalfsize[Y] || max < -boxhalfsize[Y]) {
2429  return false;
2430  }
2431 
2432  // test in Z-direction
2433  FINDMINMAX(v0[Z],v1[Z],v2[Z],min,max);
2434  if (min > boxhalfsize[Z] || max < -boxhalfsize[Z]) {
2435  return false;
2436  }
2437 
2438  // Bullet 2:
2439  // test if the box intersects the plane of the triangle
2440  // compute plane equation of triangle: normal*x+d=0
2441 
2442  if (! planeBoxOverlap(tri.normal(), v0, boxhalfsize)) {
2443  return false;
2444  }
2445 
2446  // box and triangle overlap
2447  return true;
2448 }
#define Z
Definition: CollisionDetection.cpp:2283
#define X
Definition: CollisionDetection.cpp:2281
double abs(double fValue)
Definition: g3dmath.h:617
static bool planeBoxOverlap(const Vector3 &normal, const Vector3 &vert, const Vector3 &maxbox)
Definition: CollisionDetection.cpp:2292
#define AXISTEST_Z12(a, b, fa, fb)
Definition: CollisionDetection.cpp:2353
T max(const T &x, const T &y)
Definition: g3dmath.h:320
#define AXISTEST_X01(a, b, fa, fb)
Definition: CollisionDetection.cpp:2320
T min(const T &x, const T &y)
Definition: g3dmath.h:305
#define AXISTEST_Y1(a, b, fa, fb)
Definition: CollisionDetection.cpp:2344
#define AXISTEST_Y02(a, b, fa, fb)
Definition: CollisionDetection.cpp:2337
#define FINDMINMAX(x0, x1, x2, min, max)
Definition: CollisionDetection.cpp:2285
#define AXISTEST_Z0(a, b, fa, fb)
Definition: CollisionDetection.cpp:2360
#define Y
Definition: CollisionDetection.cpp:2282
#define AXISTEST_X2(a, b, fa, fb)
Definition: CollisionDetection.cpp:2328

+ Here is the call graph for this function:

bool G3D::CollisionDetection::fixedSolidSphereIntersectsFixedSolidBox ( const Sphere sphere,
const Box box 
)
static

Tests for the intersection of a fixed sphere and a fixed box.

Parameters
sphereFixed sphere.
boxFixed box.
Returns
true - if the two objects touch.
false - if there is no intersection.
2182  {
2183 
2184  // If the center of the sphere is within the box, the whole
2185  // sphere is within the box.
2186  if (box.contains(sphere.center)) {
2187  return true;
2188  }
2189 
2190  float r2 = square(sphere.radius);
2191 
2192  // Find the closest point on the surface of the box to the sphere. If
2193  // this point is within the sphere's radius, they intersect.
2194  int f;
2195  for (f = 0; f < 6; ++f) {
2196  Vector3 v0, v1, v2, v3;
2197  box.getFaceCorners(f, v0, v1, v2, v3);
2198  if ((closestPointToRectangle(v0, v1, v2, v3, sphere.center) - sphere.center).squaredMagnitude() <= r2) {
2199  return true;
2200  }
2201  }
2202 
2203  return false;
2204 }
double square(double fValue)
Definition: g3dmath.h:698
static Vector3 closestPointToRectangle(const Vector3 &v0, const Vector3 &v1, const Vector3 &v2, const Vector3 &v3, const Vector3 &point)
Definition: CollisionDetection.cpp:2148

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

bool G3D::CollisionDetection::fixedSolidSphereIntersectsFixedSolidSphere ( const Sphere sphere1,
const Sphere sphere2 
)
static

Tests for the intersection of two fixed spheres.

Parameters
sphere1Fixed sphere 1.
sphere2Fixed sphere 2.
Returns
true - if the two spheres touch.
false - if there is no intersection.
2174  {
2175 
2176  return (sphere1.center - sphere2.center).squaredMagnitude() < square(sphere1.radius + sphere2.radius);
2177 }
double square(double fValue)
Definition: g3dmath.h:698

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

bool G3D::CollisionDetection::fixedSolidSphereIntersectsFixedTriangle ( const Sphere sphere,
const Triangle triangle 
)
static
2247  {
2248 
2249  // How far is the sphere from the plane of the triangle
2250  const Plane& plane = triangle.plane();
2251 
2252  // Does the closest point to the sphere center lie within the triangle?
2253  Vector3 v = plane.closestPoint(sphere.center);
2254 
2255  // Is the closest point to the plane within the sphere?
2256  if ((v - sphere.center).squaredLength() <= square(sphere.radius)) {
2257  // Is it also within the triangle?
2258  float b[3];
2259  if (isPointInsideTriangle(triangle.vertex(0), triangle.vertex(1), triangle.vertex(2), triangle.normal(),
2260  v, b, triangle.primaryAxis())){
2261  // The closest point is inside the triangle
2262  return true;
2263  }
2264  }
2265 
2266  // ignored
2267  int edgeIndex;
2268 
2269  v = closestPointOnTrianglePerimeter(triangle._vertex, triangle.edgeDirection, triangle.edgeMagnitude, sphere.center, edgeIndex);
2270 
2271  // Is the closest point within the sphere?
2272  return ((v - sphere.center).squaredLength() <= square(sphere.radius));
2273 }
Definition: adtfile.h:46
static bool isPointInsideTriangle(const Vector3 &v0, const Vector3 &v1, const Vector3 &v2, const Vector3 &normal, const Vector3 &point, float b[3], Vector3::Axis primaryAxis=Vector3::DETECT_AXIS)
Definition: CollisionDetection.cpp:2009
static Vector3 closestPointOnTrianglePerimeter(const Vector3 &v0, const Vector3 &v1, const Vector3 &v2, const Vector3 &point)
Definition: CollisionDetection.cpp:1935
double square(double fValue)
Definition: g3dmath.h:698

+ Here is the call graph for this function:

bool G3D::CollisionDetection::isPointInsideRectangle ( const Vector3 v0,
const Vector3 v1,
const Vector3 v2,
const Vector3 v3,
const Vector3 normal,
const Vector3 point 
)
static

Tests whether a point is inside a rectangle defined by the vertexes v0, v1, v2, & v3, and the rectangle's plane normal.

Parameters
v0Rectangle vertex 1.
v1Rectangle vertex 2.
v2Rectangle vertex 3.
v3Rectangle vertex 4.
normalNormal to rectangle's plane.
pointThe point in question.
Returns
true - if point is inside the rectangle.
false - otherwise
2092  {
2093 
2094  return isPointInsideTriangle(v0, v1, v2, normal, point) ||
2095  isPointInsideTriangle(v2, v3, v0, normal, point);
2096 }
static bool isPointInsideTriangle(const Vector3 &v0, const Vector3 &v1, const Vector3 &v2, const Vector3 &normal, const Vector3 &point, float b[3], Vector3::Axis primaryAxis=Vector3::DETECT_AXIS)
Definition: CollisionDetection.cpp:2009

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

bool G3D::CollisionDetection::isPointInsideTriangle ( const Vector3 v0,
const Vector3 v1,
const Vector3 v2,
const Vector3 normal,
const Vector3 point,
float  b[3],
Vector3::Axis  primaryAxis = Vector3::DETECT_AXIS 
)
static

Tests whether a point is contained within the triangle defined by v0, v1, and v2 and its plane's normal.

Parameters
v0Triangle vertex 0.
v1Triangle vertex 1.
v2Triangle vertex 2.
normalNormal to triangle's plane.
pointThe point in question.
primaryAxisPrimary axis of triangle. This will be detected if not given. This parameter is provided as an optimization.
bBarycentric coordinates; b[i] is the weight on v[i]
Returns
true - if point is inside the triangle.
false - otherwise
2016  {
2017 
2018  if (primaryAxis == Vector3::DETECT_AXIS) {
2019  primaryAxis = normal.primaryAxis();
2020  }
2021 
2022  // Check that the point is within the triangle using a Barycentric
2023  // coordinate test on a two dimensional plane.
2024  int i, j;
2025 
2026  switch (primaryAxis) {
2027  case Vector3::X_AXIS:
2028  i = Vector3::Y_AXIS;
2029  j = Vector3::Z_AXIS;
2030  break;
2031 
2032  case Vector3::Y_AXIS:
2033  i = Vector3::Z_AXIS;
2034  j = Vector3::X_AXIS;
2035  break;
2036 
2037  case Vector3::Z_AXIS:
2038  i = Vector3::X_AXIS;
2039  j = Vector3::Y_AXIS;
2040  break;
2041 
2042  default:
2043  // This case is here to supress a warning on Linux
2044  i = j = 0;
2045  debugAssertM(false, "Should not get here.");
2046  break;
2047  }
2048 
2049  // See if all barycentric coordinates are non-negative
2050 
2051  // 2D area via cross product
2052 # define AREA2(d, e, f) (((e)[i] - (d)[i]) * ((f)[j] - (d)[j]) - ((f)[i] - (d)[i]) * ((e)[j] - (d)[j]))
2053 
2054  // Area of the polygon
2055  float area = AREA2(v0, v1, v2);
2056  if (area == 0) {
2057  // This triangle has zero area, so the point must not
2058  // be in it unless the triangle point is the test point.
2059  return (v0 == point);
2060  }
2061 
2062  debugAssert(area != 0);
2063 
2064  float invArea = 1.0f / area;
2065 
2066  // (avoid normalization until absolutely necessary)
2067  b[0] = AREA2(point, v1, v2) * invArea;
2068 
2069  if ((b[0] < 0.0f) || (b[0] > 1.0f)) {
2070  return false;
2071  }
2072 
2073  b[1] = AREA2(v0, point, v2) * invArea;
2074  if ((b[1] < 0.0f) || (b[1] > 1.0f)) {
2075  return false;
2076  }
2077 
2078  b[2] = 1.0f - b[0] - b[1];
2079 
2080 # undef AREA2
2081 
2082  return (b[2] >= 0.0f) && (b[2] <= 1.0f);
2083 }
Definition: Vector3.h:122
#define AREA2(d, e, f)
#define debugAssertM(exp, message)
Definition: debugAssert.h:161
Definition: Vector3.h:122
#define debugAssert(exp)
Definition: debugAssert.h:160
Definition: Vector3.h:122
Definition: Vector3.h:122

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

static bool G3D::CollisionDetection::isPointInsideTriangle ( const Vector3 v0,
const Vector3 v1,
const Vector3 v2,
const Vector3 normal,
const Vector3 point,
Vector3::Axis  primaryAxis = Vector3::DETECT_AXIS 
)
inlinestatic
1056  {
1057 
1058  float b[3];
1059  return isPointInsideTriangle(v0, v1, v2, normal, point, b, primaryAxis);
1060  }
static bool isPointInsideTriangle(const Vector3 &v0, const Vector3 &v1, const Vector3 &v2, const Vector3 &normal, const Vector3 &point, float b[3], Vector3::Axis primaryAxis=Vector3::DETECT_AXIS)
Definition: CollisionDetection.cpp:2009

+ Here is the call graph for this function:

bool G3D::CollisionDetection::movingSpherePassesThroughFixedBox ( const Sphere sphere,
const Vector3 velocity,
const Box box,
double  timeLimit = inf() 
)
static

Tests for the intersection of a moving sphere and a fixed box in a given time limit.

Note
Returns true if any part of the sphere is inside the box during the time period (inf means "ever"). Useful for performing bounding-box collision detection.
Parameters
sphereMoving sphere.
velocityVelocity of moving sphere.
boxFixed box.
timeLimitTime limit for intersection test.
Returns
true - if the two objects will touch.
false - if there is no intersection.
2211  {
2212 
2213  // If they intersect originally, they definitely pass through each other.
2214  if (fixedSolidSphereIntersectsFixedSolidBox(sphere, box)) {
2215  return true;
2216  }
2217 
2218  // See if the sphere hits the box during the time period.
2219  Vector3 dummy1, dummy2;
2220 
2221  return (collisionTimeForMovingSphereFixedBox(sphere, velocity, box, dummy1, dummy2) < timeLimit);
2222 }
static bool fixedSolidSphereIntersectsFixedSolidBox(const Sphere &sphere, const Box &box)
Definition: CollisionDetection.cpp:2180
static float collisionTimeForMovingSphereFixedBox(const class Sphere &sphere, const Vector3 &velocity, const class Box &box, Vector3 &outLocation, Vector3 &outNormal=ignore)
Definition: CollisionDetection.cpp:1790

+ Here is the call graph for this function:

bool G3D::CollisionDetection::movingSpherePassesThroughFixedSphere ( const Sphere sphere,
const Vector3 velocity,
const Sphere fixedSphere,
double  timeLimit = inf() 
)
static

Tests for the intersection of a moving sphere and a fixed sphere in a given time limit.

Note
This function will not detect an intersection between a moving object that is already interpenetrating the fixed object.
Parameters
sphereMoving sphere.
velocityVelocity of moving sphere.
fixedSphereFixed sphere.
timeLimitTime limit for intersection test.
Returns
true - if the two spheres will touch.
false - if there is no intersection.
2229  {
2230 
2231  if (fixedSolidSphereIntersectsFixedSolidSphere(sphere, fixedSphere)) {
2232  return true;
2233  }
2234 
2235  // Extend the fixed sphere by the radius of the moving sphere
2236  Sphere bigFixed(fixedSphere.center, fixedSphere.radius + sphere.radius);
2237  Vector3 dummy1, dummy2;
2238 
2239  // If the sphere collides with the other sphere during the time limit, it passes through
2240  return (collisionTimeForMovingPointFixedSphere(sphere.center, velocity, bigFixed, dummy1, dummy2) < timeLimit);
2241 }
static bool fixedSolidSphereIntersectsFixedSolidSphere(const Sphere &sphere1, const Sphere &sphere2)
Definition: CollisionDetection.cpp:2172
static float collisionTimeForMovingPointFixedSphere(const Vector3 &point, const Vector3 &velocity, const class Sphere &sphere, Vector3 &outLocation, Vector3 &outNormal=ignore, bool solid=false)
Definition: CollisionDetection.cpp:977

+ Here is the call graph for this function:

bool G3D::CollisionDetection::parallelAxisForSolidBoxSolidBox ( const double *  ca,
const double  epsilon,
int &  axis1,
int &  axis2 
)
static

Tests whether two boxes have axes that are parallel to each other. If they are, axis1 and axis2 are set to be the parallel axes for both box1 and box2 respectively.

Parameters
caDot products of each of the boxes axes
epsilonFudge factor (small unit by which the dot products may vary and still be considered zero).
axis1Parallel Axis 1. [Post Condition]
axis2Parallel Axis 2. [Post Condition]
Returns
true - If boxes have a parallel axis
false - otherwise.
187  {
188  const double parallelDot = 1.0 - epsilon;
189  for (int i = 0; i < 9; ++i) {
190  if (ca[i] >= parallelDot) {
191  axis1 = i / 3;
192  axis2 = i % 3;
193  return true;
194  }
195  }
196  return false;
197 }

+ Here is the caller graph for this function:

float G3D::CollisionDetection::penetrationDepthForFixedBoxFixedBox ( const Box box1,
const Box box2,
Array< Vector3 > &  contactPoints,
Array< Vector3 > &  contactNormals,
const int  lastSeparatingAxis = -1 
)
static

Calculates the depth of penetration between two fixed boxes. Contact normal faces away from box1 and into box2. If there is contact, only one contact point is returned. The minimally violated separating plane is computed

  • if the separating axis corresponds to a face the contact point is half way between the deepest vertex and the face
  • if the separating axis corresponds to two edges the contact point is the midpoint of the smallest line segment between the two edge lines
Note
This is very similiar to calculating the intersection of two lines. Logically then, the two points calculated would be identical if calculated with inifinite precision, but with the finite precision of floating point calculations, these values could (will) differ as the line slope approaches zero or inifinity.

[adobted] from David Eberly's papers, variables used in this function correspond to variables used in pages 6 and 7 in the pdf http://www.magic-software.com/Intersection.html http://www.magic-software.com/Documentation/DynamicCollisionDetection.pdf

Parameters
box1Box 1
box2Box 2
contactPointsContact point between boxes. [Post Condition]
contactNormalsSurface normal at contact point. [Post Condition]
lastSeparatingAxisLast separating axis. (Used for optimization)
Returns
Depth of penetration between the two boxes. If there is no intersection between the boxes, then a negative value is returned.
352  {
353 
354  contactPoints.resize(0, DONT_SHRINK_UNDERLYING_ARRAY);
355  contactNormals.resize(0, DONT_SHRINK_UNDERLYING_ARRAY);
356 
357  Vector3 a;
358  Vector3 b;
359  Vector3 D;
360  double c[9];
361  double ca[9];
362  double ad[3];
363  double bd[3];
364 
365  debugAssert(lastSeparatingAxis >= -1);
366  debugAssert(lastSeparatingAxis < 15);
367 
368  fillSolidBoxSolidBoxInfo(box1, box2, a, b, D, c, ca, ad, bd);
369 
370  int axis1, axis2;
371  bool parallelAxes = parallelAxisForSolidBoxSolidBox(ca, 0.00001,
372  axis1, axis2);
373 
374 
375  // check the separating axis from the last time step
376  if (lastSeparatingAxis != -1 &&
377  (lastSeparatingAxis < 6 || !parallelAxes)) {
378  float projectedDistance = projectedDistanceForSolidBoxSolidBox(
379  lastSeparatingAxis, a, b, D, c, ca, ad, bd);
380 
381  // the separating axis from the last time step is still
382  // valid, the boxes do not intersect
383  if (projectedDistance > 0.0) {
384  return -projectedDistance;
385  }
386  }
387 
388  // test if the boxes can be separated by a plane normal to
389  // any of the three axes of box1, any of the three axes of box2,
390  // (test 9 possible cross products later)
391  float penetration = -finf();
392  int penetrationAxisIndex = -1;
393 
394  for (int i = 0; i < 6; ++i) {
395  float projectedDistance =
396  projectedDistanceForSolidBoxSolidBox(i, a, b, D, c, ca, ad, bd);
397 
398  // found a separating axis, the boxes do not intersect
399  if (projectedDistance > 0.0) {
400  return -projectedDistance;
401  }
402 
403  // keep track of the axis that is least violated
404  if (projectedDistance > penetration) {
405  penetration = projectedDistance;
406  penetrationAxisIndex = i;
407  }
408  }
409 
410 
411  // for each edge-edge case we have to adjust the magnitude of
412  // penetration since we did not include the dot(L, L) denominator
413  // that can be smaller than 1.0 for the edge-edge cases.
414 
415  if (!parallelAxes) {
416  double edgeDistances[9];
417 
418  // run through edge-edge cases to see if we can find a separating axis
419  for (int i = 6; i < 15; ++i) {
420  float projectedDistance =
421  projectedDistanceForSolidBoxSolidBox(i, a, b, D, c, ca, ad, bd);
422 
423  // found a separating axis, the boxes do not intersect,
424  // correct magnitude and return projected distance
425  if (projectedDistance > 0.0) {
426  Vector3 L = separatingAxisForSolidBoxSolidBox(i, box1, box2);
427  projectedDistance /= dot(L, L);
428  return -projectedDistance;
429  }
430 
431  edgeDistances[i - 6] = projectedDistance;
432  }
433 
434  // no separating axis found, the boxes do intersect,
435  // correct the magnitudes of the projectedDistance values
436  for (int i = 6; i < 15; ++i) {
437  // find the negative penetration value with the smallest magnitude,
438  // the adjustment done for the edge-edge cases only increases
439  // magnitude by dividing by a number smaller than 1 and greater than 0
440  float projectedDistance = (float)edgeDistances[i - 6];
441  if (projectedDistance > penetration) {
442  Vector3 L = separatingAxisForSolidBoxSolidBox(i, box1, box2);
443  projectedDistance /= dot(L, L);
444  if (projectedDistance > penetration) {
445  penetration = projectedDistance;
446  penetrationAxisIndex = i;
447  }
448  }
449  }
450  }
451 
452  // get final separating axis vector
453  Vector3 L = separatingAxisForSolidBoxSolidBox(penetrationAxisIndex,
454  box1, box2);
455 
456  // set L to be the normal that faces away from box1
457  if (dot(L, D) < 0) {
458  L = -L;
459  }
460 
461  Vector3 contactPoint;
462 
463  if (penetrationAxisIndex < 6) {
464  // vertex to face collision, find deepest colliding vertex
465  const Box* vertexBox;
466  Vector3 faceNormal = L;
467 
468  // L will be the outward facing normal for the faceBox
469  if (penetrationAxisIndex < 3) {
470  vertexBox = & box2;
471  if (dot(L, D) < 0) {
472  faceNormal = -L;
473  }
474  } else {
475  vertexBox = & box1;
476  if (dot(L, D) > 0) {
477  faceNormal = -L;
478  }
479  }
480 
481  // find the vertex that is farthest away in the direction
482  // face normal direction
483  int deepestPointIndex = 0;
484  float deepestPointDot = dot(faceNormal, vertexBox->corner(0));
485  for (int i = 1; i < 8; ++i) {
486  float dotProduct = dot(faceNormal, vertexBox->corner(i));
487  if (dotProduct < deepestPointDot) {
488  deepestPointDot = dotProduct;
489  deepestPointIndex = i;
490  }
491  }
492 
493  // return the point half way between the deepest point and the
494  // contacting face
495  contactPoint = vertexBox->corner(deepestPointIndex) +
496  (-penetration * 0.5 * faceNormal);
497  } else {
498  // edge-edge case, find the two ege lines
499  int edge1 = (penetrationAxisIndex - 6) / 3;
500  int edge2 = (penetrationAxisIndex - 6) % 3;
501  Vector3 linePoint1 = box1.center();
502  Vector3 linePoint2 = box2.center();
503  Vector3 lineDir1;
504  Vector3 lineDir2;
505 
506  // find edge line by finding the edge axis, and the
507  // other two axes that are closest to the other box
508  for (int i = 0; i < 3; ++i) {
509  if (i == edge1) {
510  lineDir1 = box1.axis(i);
511  } else {
512  Vector3 axis = box1.axis(i);
513  if (dot(axis, L) < 0) {
514  axis = -axis;
515  }
516  linePoint1 += axis * a[i];
517  }
518 
519  if (i == edge2) {
520  lineDir2 = box2.axis(i);
521  } else {
522  Vector3 axis = box2.axis(i);
523  if (dot(axis, L) > 0) {
524  axis = -axis;
525  }
526  linePoint2 += axis * b[i];
527  }
528  }
529 
530  // make lines from the two closest edges, and find
531  // the points that on each line that are closest to the other
532  Line line1 = Line::fromPointAndDirection(linePoint1, lineDir1);
533  Line line2 = Line::fromPointAndDirection(linePoint2, lineDir2);
534  Vector3 closest1;
535  Vector3 closest2;
536 
537  closestPointsBetweenLineAndLine(line1, line2, closest1, closest2);
538 
539  // take the average of the two closest edge points for the final
540  // contact point
541  contactPoint = (closest1 + closest2) * 0.5;
542  }
543 
544  contactPoints.push(contactPoint);
545  contactNormals.push(L);
546 
547  return -penetration;
548 
549 }
float finf()
Definition: g3dmath.cpp:71
static Line fromPointAndDirection(const Vector3 &point, const Vector3 &direction)
Definition: Line.h:59
static void closestPointsBetweenLineAndLine(const Line &line1, const Line &line2, Vector3 &closest1, Vector3 &closest2)
Definition: CollisionDetection.cpp:309
const bool DONT_SHRINK_UNDERLYING_ARRAY
Definition: Array.h:43
#define debugAssert(exp)
Definition: debugAssert.h:160
static void fillSolidBoxSolidBoxInfo(const Box &box1, const Box &box2, Vector3 &a, Vector3 &b, Vector3 &D, double *c, double *ca, double *ad, double *bd)
Definition: CollisionDetection.cpp:202
static bool parallelAxisForSolidBoxSolidBox(const double *ca, const double epsilon, int &axis1, int &axis2)
Definition: CollisionDetection.cpp:183
float dot(float a, float b)
Definition: g3dmath.h:445
static Vector3 separatingAxisForSolidBoxSolidBox(const int separatingAxisIndex, const Box &box1, const Box &box2)
Definition: CollisionDetection.cpp:45
static float projectedDistanceForSolidBoxSolidBox(const int separatingAxisIndex, const Vector3 &a, const Vector3 &b, const Vector3 &D, const double *c, const double *ca, const double *ad, const double *bd)
Definition: CollisionDetection.cpp:69

+ Here is the call graph for this function:

float G3D::CollisionDetection::penetrationDepthForFixedBoxFixedPlane ( const Box box,
const Plane plane,
Array< Vector3 > &  contactPoints,
Array< Vector3 > &  contactNormals = ignoreArray 
)
static

Calculates the depth of penetration between a fixed box and a fixed plane as well as the vertexes of the box that penetrate the plane and the plane normals at those intersections.

Parameters
boxFixed Box.
planeFixed Plane.
contactPointsBox points that penetrate the plane. [Post Condition]
contactNormalsNormals at penetration points [Post Condition]
Returns
Depth of penetration. If there is no intersection between the objects then the depth will be a negative value.
817  {
818 
819  Vector3 N;
820  double d;
821 
822  plane.getEquation(N, d);
823 
824  contactPoints.resize(0, DONT_SHRINK_UNDERLYING_ARRAY);
825  contactNormals.resize(0, DONT_SHRINK_UNDERLYING_ARRAY);
826 
827  float lowest = finf();
828  for (int i = 0; i < 8; ++i) {
829  const Vector3 vertex = box.corner(i);
830 
831  float x = vertex.dot(N) + (float)d;
832 
833  if (x <= 0) {
834  // All vertices below the plane should be contact points.
835  contactPoints.append(vertex);
836  contactNormals.append(-N);
837  }
838 
839  lowest = min(lowest, x);
840  }
841 
842  // Depth should be a positive number
843  return -lowest;
844 }
float finf()
Definition: g3dmath.cpp:71
T min(const T &x, const T &y)
Definition: g3dmath.h:305
const bool DONT_SHRINK_UNDERLYING_ARRAY
Definition: Array.h:43
G3D::int16 x
Definition: Vector2int16.h:37

+ Here is the call graph for this function:

float G3D::CollisionDetection::penetrationDepthForFixedSphereFixedBox ( const Sphere sphere,
const Box box,
Array< Vector3 > &  contactPoints,
Array< Vector3 > &  contactNormals = ignoreArray 
)
static

Calculates the depth of penetration between a fixed sphere and a fixed box as well as the deepest point of the sphere that penetrates the box and the normal at that intersection.

Note
There are three possible intersections between a sphere and box.
  • Sphere completely contained in the box
  • Sphere intersects one edge
  • Sphere intersects one vertex

The contact point and contact normal vary for each of these situations.

  • Sphere contained in Box:
    • Normal is based on side of least penetration (as is the depth calculation).
    • Point is based on center of sphere
  • Sphere intersects one edge
    • Normal is based on vector from the box center to the point of depth.
    • Point is closest point to the sphere on the line
  • Sphere intersects one vertex
    • Normal is based on vector from the box center to the vertex of penetration.
    • Point is vertex of penetration.

[Adapted] from Jim Arvo's method in Graphics Gems See also http://www.win.tue.nl/~gino/solid/gdc2001depth.pdf

Parameters
sphereFixed Sphere.
boxFixed Box.
contactPointsSphere point that penetrates the box. [Post Condition]
contactNormalsNormal at the penetration point. [Post Condition]
Returns
Depth of penetration. If there is no intersection between the objects then the depth will be a negative value.
558  {
559 
560  contactPoints.resize(0, DONT_SHRINK_UNDERLYING_ARRAY);
561  contactNormals.resize(0, DONT_SHRINK_UNDERLYING_ARRAY);
562 
563  // In its local coordinate frame, the box measures
564  // 2 * halfExtent[a] along dimesion a.
565  Vector3 halfExtent(box.extent(0), box.extent(1), box.extent(2));
566  halfExtent *= 0.5f;
567 
568  CoordinateFrame boxFrame;
569  box.getLocalFrame(boxFrame);
570 
571  // Transform the sphere to the box's coordinate frame.
572  Vector3 center = boxFrame.pointToObjectSpace(sphere.center);
573 
574  // Find the square of the distance from the sphere to the box
575 
576 
577  // Distance along each axis from the closest side of the box
578  // to the sphere center. Negative values are *inside* the box.
579  Vector3 distOutsideBox;
580 
581  // Divide space up into the 27 regions corresponding
582  // to {+|-|0}X, {+|-|0}Y, {+|-|0}Z and classify the
583  // sphere center into one of them.
584  Vector3 centerRegion;
585 
586  // In the edge collision case, the edge is between vertices
587  // (constant + variable) and (constant - variable).
588  Vector3 constant, variable;
589 
590  int numNonZero = 0;
591 
592  // Iterate over axes
593  for (int a = 0; a < 3; ++a) {
594  // For each (box side), see which direction the sphere
595  // is outside the box (positive or negative). Add the
596  // square of that distance to the total distance from
597  // the box.
598 
599  float distanceFromLow = -halfExtent[a] - center[a];
600  float distanceFromHigh = center[a] - halfExtent[a];
601 
602  if (fabsf(distanceFromLow) < fabsf(distanceFromHigh)) {
603  distOutsideBox[a] = distanceFromLow;
604  } else {
605  distOutsideBox[a] = distanceFromHigh;
606  }
607 
608  if (distanceFromLow < 0.0) {
609  if (distanceFromHigh < 0.0) {
610  // Inside the box
611  centerRegion[a] = 0.0;
612  variable[a] = 1.0;
613  } else {
614  // Off the high side
615  centerRegion[a] = 1.0;
616  constant[a] = halfExtent[a];
617  ++numNonZero;
618  }
619  } else if (distanceFromHigh < 0.0) {
620  // Off the low side
621  centerRegion[a] = -1.0;
622  constant[a] = -halfExtent[a];
623  ++numNonZero;
624  } else {
625  debugAssertM(false,
626  "distanceFromLow and distanceFromHigh cannot both be positive");
627  }
628  }
629 
630  // Squared distance between the outside of the box and the
631  // sphere center.
632  float d2 = Vector3::zero().max(distOutsideBox).squaredMagnitude();
633 
634  if (d2 > square(sphere.radius)) {
635  // There is no penetration because the distance is greater
636  // than the radius of the sphere. This is the common case
637  // and we quickly exit.
638  return -1;
639  }
640 
641  // We know there is some penetration but need to classify it.
642  //
643  // Examine the region that contains the center of the sphere. If
644  // there is exactly one non-zero axis, the collision is with a
645  // plane. If there are exactly two non-zero axes, the collision
646  // is with an edge. If all three axes are non-zero, the collision is
647  // with a vertex. If there are no non-zero axes, the center is inside
648  // the box.
649 
650  double depth = -1;
651  switch (numNonZero) {
652  case 3: // Vertex collision
653  // The collision point is the vertex at constant, the normal
654  // is the vector from there to the sphere center.
655  contactNormals.append(boxFrame.normalToWorldSpace(constant - center));
656  contactPoints.append(boxFrame.pointToWorldSpace(constant));
657  depth = sphere.radius - sqrt(d2);
658  break;
659 
660  case 2: // Edge collision
661  {
662  // TODO: unwrapping the edge constructor and closest point
663  // code will probably make it faster.
664 
665  // Determine the edge
666  Line line = Line::fromPointAndDirection(constant, variable);
667 
668  // Penetration depth:
669  depth = sphere.radius - sqrt(d2);
670 
671  // The contact point is the closes point to the sphere on the line
672  Vector3 X = line.closestPoint(center);
673  contactNormals.append(boxFrame.normalToWorldSpace(X - center).direction());
674  contactPoints.append(boxFrame.pointToWorldSpace(X));
675  }
676  break;
677 
678  case 1: // Plane collision
679  {
680  // The plane normal is the centerRegion vector,
681  // so the sphere normal is the negative. Take
682  // it to world space from box-space.
683 
684  // Center region doesn't need to be normalized because
685  // it is known to contain only one non-zero value
686  // and that value is +/- 1.
687  Vector3 N = boxFrame.normalToWorldSpace(-centerRegion);
688  contactNormals.append(N);
689 
690  // Penetration depth:
691  depth = sphere.radius - sqrtf(d2);
692 
693  // Compute the contact point from the penetration depth
694  contactPoints.append(sphere.center + N * (sphere.radius - depth));
695  }
696  break;
697 
698  case 0: // Volume collision
699 
700  // The sphere center is inside the box. This is an easy case
701  // to handle. Note that all axes of distOutsideBox must
702  // be negative.
703 
704  // Arbitratily choose the sphere center as a contact point
705  contactPoints.append(sphere.center);
706 
707  // Find the least-negative penetration axis.
708  //
709  // We could have computed this during the loop over the axes,
710  // but since volume collisions are rare (they only occur with
711  // large time steps), this case will seldom be executed and
712  // should not be optimized at the expense of the others.
713  if (distOutsideBox.x > distOutsideBox.y) {
714  if (distOutsideBox.x > distOutsideBox.z) {
715  // Smallest penetration on x-axis
716  // Chose normal based on which side we're closest to.
717  // Keep in mind that this is a normal to the sphere,
718  // so it is the inverse of the box normal.
719  if (center.x > 0) {
720  contactNormals.append(boxFrame.normalToWorldSpace(-Vector3::unitX()));
721  } else {
722  contactNormals.append(boxFrame.normalToWorldSpace(Vector3::unitX()));
723  }
724  depth = -distOutsideBox.x;
725  } else {
726  // Smallest penetration on z-axis
727  goto ZAXIS;
728  }
729  } else if (distOutsideBox.y > distOutsideBox.z) {
730  // Smallest penetration on y-axis
731  // Chose normal based on which side we're closest to.
732  // Keep in mind that this is a normal to the sphere,
733  // so it is the inverse of the box normal.
734  if (center.y > 0) {
735  contactNormals.append(boxFrame.normalToWorldSpace(-Vector3::unitY()));
736  } else {
737  contactNormals.append(boxFrame.normalToWorldSpace(Vector3::unitY()));
738  }
739  depth = -distOutsideBox.y;
740  } else {
741  // Smallest on z-axis
742 ZAXIS:
743  // Chose normal based on which side we're closest to.
744  // Keep in mind that this is a normal to the sphere,
745  // so it is the inverse of the box normal.
746  if (center.z > 0) {
747  contactNormals.append(boxFrame.normalToWorldSpace(-Vector3::unitZ()));
748  } else {
749  contactNormals.append(boxFrame.normalToWorldSpace(Vector3::unitZ()));
750  }
751  depth = -distOutsideBox.z;
752  }
753  break;
754 
755  default:
756  debugAssertM(false, "Fell through switch");
757  break;
758  }
759 
760  return depth;
761 }
static Line fromPointAndDirection(const Vector3 &point, const Vector3 &direction)
Definition: Line.h:59
float squaredMagnitude() const
Definition: Vector3.h:736
#define X
Definition: CollisionDetection.cpp:2281
Vector3 __fastcall max(const Vector3 &v) const
Definition: Vector3.h:794
#define debugAssertM(exp, message)
Definition: debugAssert.h:161
static const Vector3 & unitX()
Definition: Vector3.cpp:121
static const Vector3 & zero()
Definition: Vector3.cpp:119
const bool DONT_SHRINK_UNDERLYING_ARRAY
Definition: Array.h:43
static const Vector3 & unitY()
Definition: Vector3.cpp:122
double square(double fValue)
Definition: g3dmath.h:698
static const Vector3 & unitZ()
Definition: Vector3.cpp:123

+ Here is the call graph for this function:

float G3D::CollisionDetection::penetrationDepthForFixedSphereFixedPlane ( const Sphere sphereA,
const class Plane planeB,
Array< Vector3 > &  contactPoints,
Array< Vector3 > &  contactNormals = ignoreArray 
)
static

Calculates the depth of penetration between a Fixed Sphere and a Fixed Plane as well as the deepest point of the sphere that penetrates the plane and the plane normal at that intersection.

Parameters
sphereAFixed Sphere.
planeBFixed Plane.
contactPointsSphere point that penetrates the plane. [Post Condition]
contactNormalsNormal at penetration point. [Post Condition]
Returns
Depth of penetration. If there is no intersection between the objects then the depth will be a negative value.
792  {
793 
794  Vector3 N;
795  double d;
796 
797  planeB.getEquation(N, d);
798 
799  double depth = -(sphereA.center.dot(N) + d - sphereA.radius);
800 
801  contactPoints.resize(0, DONT_SHRINK_UNDERLYING_ARRAY);
802  contactNormals.resize(0, DONT_SHRINK_UNDERLYING_ARRAY);
803 
804  if (depth >= 0) {
805  contactPoints.append(N * (depth - sphereA.radius) + sphereA.center);
806  contactNormals.append(N);
807  }
808 
809  return depth;
810 }
const bool DONT_SHRINK_UNDERLYING_ARRAY
Definition: Array.h:43

+ Here is the call graph for this function:

float G3D::CollisionDetection::penetrationDepthForFixedSphereFixedSphere ( const class Sphere sphereA,
const Sphere sphereB,
Array< Vector3 > &  contactPoints,
Array< Vector3 > &  contactNormals = ignoreArray 
)
static

Calculates the depth of penetration between two fixed spheres as well as the deepest point of Sphere A that penetrates Sphere B. The normal returned points away from the object A, although it may represent a perpendicular to either the faces of object B or object A depending on their relative orientations.

Parameters
sphereAFixed Sphere A.
sphereBFixed Sphere B.
contactPointsSphere A's deepest point that penetrates Sphere B. [Post Condition]
contactNormalsNormal at penetration point. [Post Condition]
Returns
Depth of penetration. If there is no intersection between the objects then the depth will be a negative value.
768  {
769 
770  Vector3 axis = sphereB.center - sphereA.center;
771  double radius = sphereA.radius + sphereB.radius;
772  double mag = axis.magnitude();
773  axis /= mag;
774  double depth = -(mag - radius);
775 
776  contactPoints.resize(0, DONT_SHRINK_UNDERLYING_ARRAY);
777  contactNormals.resize(0, DONT_SHRINK_UNDERLYING_ARRAY);
778 
779  if (depth >= 0) {
780  contactPoints.append(sphereA.center + axis * (sphereA.radius - depth / 2));
781  contactNormals.append(axis);
782  }
783 
784  return depth;
785 }
const bool DONT_SHRINK_UNDERLYING_ARRAY
Definition: Array.h:43

+ Here is the call graph for this function:

float G3D::CollisionDetection::projectedDistanceForSolidBoxSolidBox ( const int  separatingAxisIndex,
const Vector3 a,
const Vector3 b,
const Vector3 D,
const double *  c,
const double *  ca,
const double *  ad,
const double *  bd 
)
static

Calculates the projected distance between the two boxes along the specified separating axis, negative distances correspond to an overlap along that separating axis. The distance is not divided by denominator dot(L, L), see penetrationDepthForFixedSphereFixedBox() for more details

Parameters
separatingAxisIndex
aBox 1's bounding sphere vector
bBox 2's bounding sphere vector
DVector between Box 1 and Box 2's center points
cPointer to array of dot products of the axes of Box 1 and Box 2.
caPointer to array of unsigned dot products of the axes of Box 1 and Box 2.
adPointer to array of dot products of Box 1 axes and D.
bdPointer to array of dot products of Box 2 axes and D.
Returns
Projected distance between the two boxes along the specified separating axis.
78 {
79  (void)D;
80 
81  float R0 = 0.0f;
82  float R1 = 0.0f;
83  float R = 0.0f;
84  switch (separatingAxisIndex) {
85  case 0:
86  // A0
87  R0 = a[0];
88  R1 = b[0] * ca[0] + b[1] * ca[1] + b[2] * ca[2];
89  R = fabs(ad[0]);
90  break;
91  case 1:
92  // A1
93  R0 = a[1];
94  R1 = b[0] * ca[3] + b[1] * ca[4] + b[2] * ca[5];
95  R = fabs(ad[1]);
96  break;
97  case 2:
98  // A2
99  R0 = a[2];
100  R1 = b[0] * ca[6] + b[1] * ca[7] + b[2] * ca[8];
101  R = fabs(ad[2]);
102  break;
103  case 3:
104  // B0
105  R0 = a[0] * ca[0] + a[1] * ca[3] + a[2] * ca[6];
106  R1 = b[0];
107  R = fabs(bd[0]);
108  break;
109  case 4:
110  // B1
111  R0 = a[0] * ca[1] + a[1] * ca[4] + a[2] * ca[7];
112  R1 = b[1];
113  R = fabs(bd[1]);
114  break;
115  case 5:
116  // B2
117  R0 = a[0] * ca[2] + a[1] * ca[5] + a[2] * ca[8];
118  R1 = b[2];
119  R = fabs(bd[2]);
120  break;
121  case 6:
122  // A0 x B0
123  R0 = a[1] * ca[6] + a[2] * ca[3];
124  R1 = b[1] * ca[2] + b[2] * ca[1];
125  R = fabs(c[3] * ad[2] - c[6] * ad[1]);
126  break;
127  case 7:
128  // A0 x B1
129  R0 = a[1] * ca[7] + a[2] * ca[4];
130  R1 = b[0] * ca[2] + b[2] * ca[0];
131  R = fabs(c[4] * ad[2] - c[7] * ad[1]);
132  break;
133  case 8:
134  // A0 x B2
135  R0 = a[1] * ca[8] + a[2] * ca[5];
136  R1 = b[0] * ca[1] + b[1] * ca[0];
137  R = fabs(c[5] * ad[2] - c[8] * ad[1]);
138  break;
139  case 9:
140  // A1 x B0
141  R0 = a[0] * ca[6] + a[2] * ca[0];
142  R1 = b[1] * ca[5] + b[2] * ca[4];
143  R = fabs(c[6] * ad[0] - c[0] * ad[2]);
144  break;
145  case 10:
146  // A1 x B1
147  R0 = a[0] * ca[7] + a[2] * ca[1];
148  R1 = b[0] * ca[5] + b[2] * ca[3];
149  R = fabs(c[7] * ad[0] - c[1] * ad[2]);
150  break;
151  case 11:
152  // A1 x B2
153  R0 = a[0] * ca[8] + a[2] * ca[2];
154  R1 = b[0] * ca[4] + b[1] * ca[3];
155  R = fabs(c[8] * ad[0] - c[2] * ad[2]);
156  break;
157  case 12:
158  // A2 x B0
159  R0 = a[0] * ca[3] + a[1] * ca[0];
160  R1 = b[1] * ca[8] + b[2] * ca[7];
161  R = fabs(c[0] * ad[1] - c[3] * ad[0]);
162  break;
163  case 13:
164  // A2 x B1
165  R0 = a[0] * ca[4] + a[1] * ca[1];
166  R1 = b[0] * ca[8] + b[2] * ca[6];
167  R = fabs(c[1] * ad[1] - c[4] * ad[0]);
168  break;
169  case 14:
170  // A2 x B2
171  R0 = a[0] * ca[5] + a[1] * ca[2];
172  R1 = b[0] * ca[7] + b[1] * ca[6];
173  R = fabs(c[2] * ad[1] - c[5] * ad[0]);
174  break;
175  default:
176  debugAssertM(false, "fell through switch statement");
177  }
178 
179  return (R - (R0 + R1));
180 }
#define debugAssertM(exp, message)
Definition: debugAssert.h:161

+ Here is the caller graph for this function:

bool __fastcall G3D::CollisionDetection::rayAABox ( const Ray ray,
const Vector3 invDir,
const AABox box,
const Vector3 boxCenter,
float  boundingRadiusSquared,
Vector3 location,
bool inside 
)
static

Calculates intersection of a ray and a static Axis-Aligned Box (AABox).

Note
Avoids the sqrt from collisionTimeForMovingPointFixedAABox; early-out branches and operations optimized for Intel Core2 architecture.
Parameters
invDir1/dir
locationLocation of collision. [Post Condition]
insideDoes the ray originate inside the box? [Post Condition]
Returns
True if the ray hits the box
893  {
894 
895  debugAssertM(fabs(ray.direction().squaredLength() - 1.0f) < 0.01f, format("Length = %f", ray.direction().length()));
896  {
897  // Pre-emptive partial bounding sphere test
898  const Vector3 L(boxCenter - ray.origin());
899  float d = L.dot(ray.direction());
900 
901  float L2 = L.dot(L);
902  float D2 = square(d);
903  float M2 = L2 - D2;
904 
905  if (((d < 0) && (L2 > boundingRadiusSquared)) || (M2 > boundingRadiusSquared)) {
906  inside = false;
907  return false;
908  }
909  // Passing here does not mean that the ray hits the bounding sphere;
910  // we would still have to perform more expensive tests to determine
911  // that.
912  }
913 
914  inside = true;
915  const Vector3& MinB = box.low();
916  const Vector3& MaxB = box.high();
917  Vector3 MaxT(-1.0f, -1.0f, -1.0f);
918 
919  // Find candidate planes.
920  for (int i = 0; i < 3; ++i) {
921  if (ray.origin()[i] < MinB[i]) {
922  location[i] = MinB[i];
923  inside = false;
924 
925  // Calculate T distances to candidate planes
926  if (ray.direction()[i] != 0) {
927  MaxT[i] = (MinB[i] - ray.origin()[i]) * invDir[i];
928  }
929  } else if (ray.origin()[i] > MaxB[i]) {
930  location[i] = MaxB[i];
931  inside = false;
932 
933  // Calculate T distances to candidate planes
934  if (ray.direction()[i] != 0) {
935  MaxT[i] = (MaxB[i] - ray.origin()[i]) * invDir[i];
936  }
937  }
938  }
939 
940  if (inside) {
941  // Ray origin inside bounding box
942  location = ray.origin();
943  return true;
944  }
945 
946  // Get largest of the maxT's for final choice of intersection
947  int WhichPlane = 0;
948  if (MaxT[1] > MaxT[WhichPlane]) {
949  WhichPlane = 1;
950  }
951 
952  if (MaxT[2] > MaxT[WhichPlane]) {
953  WhichPlane = 2;
954  }
955 
956  // Check final candidate actually inside box
957  if (MaxT[WhichPlane] < 0.0f) {
958  // Miss the box
959  return false;
960  }
961 
962  for (int i = 0; i < 3; ++i) {
963  if (i != WhichPlane) {
964  location[i] = ray.origin()[i] + MaxT[WhichPlane] * ray.direction()[i];
965  if ((location[i] < MinB[i]) ||
966  (location[i] > MaxB[i])) {
967  // On this plane we're outside the box extents, so
968  // we miss the box
969  return false;
970  }
971  }
972  }
973 
974  return true;
975 }
#define debugAssertM(exp, message)
Definition: debugAssert.h:161
double square(double fValue)
Definition: g3dmath.h:698
std::string __cdecl format(const char *fmt...) G3D_CHECK_PRINTF_ARGS

+ Here is the call graph for this function:

Vector3 G3D::CollisionDetection::separatingAxisForSolidBoxSolidBox ( const int  separatingAxisIndex,
const Box box1,
const Box box2 
)
static

Converts an index [0, 15] to the corresponding separating axis. Does not return normalized vector in the edge-edge case (indices 6 through 15).

Parameters
separatingAxisIndexSeparating axis.
box1Box 1.
box2Box 2.
Returns
Axis that separates the two boxes.
48  {
49  debugAssert(separatingAxisIndex >= 0);
50  debugAssert(separatingAxisIndex < 15);
51  Vector3 axis;
52  if (separatingAxisIndex < 3) {
53  axis = box1.axis(separatingAxisIndex);
54  } else if (separatingAxisIndex < 6) {
55  axis = box2.axis(separatingAxisIndex - 3);
56  } else {
57  int box1Index = (separatingAxisIndex - 6) / 3;
58  int box2Index = (separatingAxisIndex - 6) % 3;
59  axis = cross(box1.axis(box1Index), box2.axis(box2Index));
60  }
61  return axis;
62 }
#define debugAssert(exp)
Definition: debugAssert.h:160
Vector3 cross(const Vector3 &v1, const Vector3 &v2)
Definition: vectorMath.h:144

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

Vector3 G3D::CollisionDetection::slideDirection ( const class Sphere sphere,
const Vector3 velocity,
const float  collisionTime,
const Vector3 collisionLocation 
)
static

Finds the direction of slide given a moving sphere, its velocity, the time of collision and the collision location. This function works as if the sphere intersects the surface and continues to hug it.

Note
The result will work well for calculating the movement of a player who collides with an object and continues moving along the object instead of just bouncing off it.
Parameters
sphereMoving sphere.
velocitySphere's velocity.
collisionTimeTime of collision
collisionLocationCollision location.
Returns
Direction of slide.
1878  {
1879 
1880  Vector3 sphereLocation = sphere.center + velocity * collisionTime;
1881  Vector3 normal = (sphereLocation - collisionLocation).direction();
1882  Vector3 direction = velocity.direction();
1883 
1884  // subtract off the part in the direction away from the normal.
1885  return direction - normal * normal.dot(direction);
1886 }

+ Here is the call graph for this function:

Member Data Documentation

Vector3 G3D::CollisionDetection::ignore
staticprivate

Default parameter if value passed to a function as reference is not to be calculated. Must be explicitly supported by function.

Array< Vector3 > G3D::CollisionDetection::ignoreArray
staticprivate

Default parameter if value passed to a function as reference is not to be calculated. Must be explicitly supported by function.

bool G3D::CollisionDetection::ignoreBool
staticprivate

Default parameter if value passed to a function as reference is not to be calculated. Must be explicitly supported by function.


The documentation for this class was generated from the following files: