Home | History | Annotate | Download | only in Collision
      1 /*
      2 * Copyright (c) 2007-2009 Erin Catto http://www.box2d.org
      3 *
      4 * This software is provided 'as-is', without any express or implied
      5 * warranty.  In no event will the authors be held liable for any damages
      6 * arising from the use of this software.
      7 * Permission is granted to anyone to use this software for any purpose,
      8 * including commercial applications, and to alter it and redistribute it
      9 * freely, subject to the following restrictions:
     10 * 1. The origin of this software must not be misrepresented; you must not
     11 * claim that you wrote the original software. If you use this software
     12 * in a product, an acknowledgment in the product documentation would be
     13 * appreciated but is not required.
     14 * 2. Altered source versions must be plainly marked as such, and must not be
     15 * misrepresented as being the original software.
     16 * 3. This notice may not be removed or altered from any source distribution.
     17 */
     18 
     19 #include <Box2D/Collision/b2Collision.h>
     20 #include <Box2D/Collision/b2Distance.h>
     21 
     22 void b2WorldManifold::Initialize(const b2Manifold* manifold,
     23 						  const b2Transform& xfA, float32 radiusA,
     24 						  const b2Transform& xfB, float32 radiusB)
     25 {
     26 	if (manifold->pointCount == 0)
     27 	{
     28 		return;
     29 	}
     30 
     31 	switch (manifold->type)
     32 	{
     33 	case b2Manifold::e_circles:
     34 		{
     35 			normal.Set(1.0f, 0.0f);
     36 			b2Vec2 pointA = b2Mul(xfA, manifold->localPoint);
     37 			b2Vec2 pointB = b2Mul(xfB, manifold->points[0].localPoint);
     38 			if (b2DistanceSquared(pointA, pointB) > b2_epsilon * b2_epsilon)
     39 			{
     40 				normal = pointB - pointA;
     41 				normal.Normalize();
     42 			}
     43 
     44 			b2Vec2 cA = pointA + radiusA * normal;
     45 			b2Vec2 cB = pointB - radiusB * normal;
     46 			points[0] = 0.5f * (cA + cB);
     47 			separations[0] = b2Dot(cB - cA, normal);
     48 		}
     49 		break;
     50 
     51 	case b2Manifold::e_faceA:
     52 		{
     53 			normal = b2Mul(xfA.q, manifold->localNormal);
     54 			b2Vec2 planePoint = b2Mul(xfA, manifold->localPoint);
     55 
     56 			for (int32 i = 0; i < manifold->pointCount; ++i)
     57 			{
     58 				b2Vec2 clipPoint = b2Mul(xfB, manifold->points[i].localPoint);
     59 				b2Vec2 cA = clipPoint + (radiusA - b2Dot(clipPoint - planePoint, normal)) * normal;
     60 				b2Vec2 cB = clipPoint - radiusB * normal;
     61 				points[i] = 0.5f * (cA + cB);
     62 				separations[i] = b2Dot(cB - cA, normal);
     63 			}
     64 		}
     65 		break;
     66 
     67 	case b2Manifold::e_faceB:
     68 		{
     69 			normal = b2Mul(xfB.q, manifold->localNormal);
     70 			b2Vec2 planePoint = b2Mul(xfB, manifold->localPoint);
     71 
     72 			for (int32 i = 0; i < manifold->pointCount; ++i)
     73 			{
     74 				b2Vec2 clipPoint = b2Mul(xfA, manifold->points[i].localPoint);
     75 				b2Vec2 cB = clipPoint + (radiusB - b2Dot(clipPoint - planePoint, normal)) * normal;
     76 				b2Vec2 cA = clipPoint - radiusA * normal;
     77 				points[i] = 0.5f * (cA + cB);
     78 				separations[i] = b2Dot(cA - cB, normal);
     79 			}
     80 
     81 			// Ensure normal points from A to B.
     82 			normal = -normal;
     83 		}
     84 		break;
     85 	}
     86 }
     87 
     88 void b2GetPointStates(b2PointState state1[b2_maxManifoldPoints], b2PointState state2[b2_maxManifoldPoints],
     89 					  const b2Manifold* manifold1, const b2Manifold* manifold2)
     90 {
     91 	for (int32 i = 0; i < b2_maxManifoldPoints; ++i)
     92 	{
     93 		state1[i] = b2_nullState;
     94 		state2[i] = b2_nullState;
     95 	}
     96 
     97 	// Detect persists and removes.
     98 	for (int32 i = 0; i < manifold1->pointCount; ++i)
     99 	{
    100 		b2ContactID id = manifold1->points[i].id;
    101 
    102 		state1[i] = b2_removeState;
    103 
    104 		for (int32 j = 0; j < manifold2->pointCount; ++j)
    105 		{
    106 			if (manifold2->points[j].id.key == id.key)
    107 			{
    108 				state1[i] = b2_persistState;
    109 				break;
    110 			}
    111 		}
    112 	}
    113 
    114 	// Detect persists and adds.
    115 	for (int32 i = 0; i < manifold2->pointCount; ++i)
    116 	{
    117 		b2ContactID id = manifold2->points[i].id;
    118 
    119 		state2[i] = b2_addState;
    120 
    121 		for (int32 j = 0; j < manifold1->pointCount; ++j)
    122 		{
    123 			if (manifold1->points[j].id.key == id.key)
    124 			{
    125 				state2[i] = b2_persistState;
    126 				break;
    127 			}
    128 		}
    129 	}
    130 }
    131 
    132 // From Real-time Collision Detection, p179.
    133 bool b2AABB::RayCast(b2RayCastOutput* output, const b2RayCastInput& input) const
    134 {
    135 	float32 tmin = -b2_maxFloat;
    136 	float32 tmax = b2_maxFloat;
    137 
    138 	b2Vec2 p = input.p1;
    139 	b2Vec2 d = input.p2 - input.p1;
    140 	b2Vec2 absD = b2Abs(d);
    141 
    142 	b2Vec2 normal;
    143 
    144 	for (int32 i = 0; i < 2; ++i)
    145 	{
    146 		if (absD(i) < b2_epsilon)
    147 		{
    148 			// Parallel.
    149 			if (p(i) < lowerBound(i) || upperBound(i) < p(i))
    150 			{
    151 				return false;
    152 			}
    153 		}
    154 		else
    155 		{
    156 			float32 inv_d = 1.0f / d(i);
    157 			float32 t1 = (lowerBound(i) - p(i)) * inv_d;
    158 			float32 t2 = (upperBound(i) - p(i)) * inv_d;
    159 
    160 			// Sign of the normal vector.
    161 			float32 s = -1.0f;
    162 
    163 			if (t1 > t2)
    164 			{
    165 				b2Swap(t1, t2);
    166 				s = 1.0f;
    167 			}
    168 
    169 			// Push the min up
    170 			if (t1 > tmin)
    171 			{
    172 				normal.SetZero();
    173 				normal(i) = s;
    174 				tmin = t1;
    175 			}
    176 
    177 			// Pull the max down
    178 			tmax = b2Min(tmax, t2);
    179 
    180 			if (tmin > tmax)
    181 			{
    182 				return false;
    183 			}
    184 		}
    185 	}
    186 
    187 	// Does the ray start inside the box?
    188 	// Does the ray intersect beyond the max fraction?
    189 	if (tmin < 0.0f || input.maxFraction < tmin)
    190 	{
    191 		return false;
    192 	}
    193 
    194 	// Intersection.
    195 	output->fraction = tmin;
    196 	output->normal = normal;
    197 	return true;
    198 }
    199 
    200 // Sutherland-Hodgman clipping.
    201 int32 b2ClipSegmentToLine(b2ClipVertex vOut[2], const b2ClipVertex vIn[2],
    202 						const b2Vec2& normal, float32 offset, int32 vertexIndexA)
    203 {
    204 	// Start with no output points
    205 	int32 numOut = 0;
    206 
    207 	// Calculate the distance of end points to the line
    208 	float32 distance0 = b2Dot(normal, vIn[0].v) - offset;
    209 	float32 distance1 = b2Dot(normal, vIn[1].v) - offset;
    210 
    211 	// If the points are behind the plane
    212 	if (distance0 <= 0.0f) vOut[numOut++] = vIn[0];
    213 	if (distance1 <= 0.0f) vOut[numOut++] = vIn[1];
    214 
    215 	// If the points are on different sides of the plane
    216 	if (distance0 * distance1 < 0.0f)
    217 	{
    218 		// Find intersection point of edge and plane
    219 		float32 interp = distance0 / (distance0 - distance1);
    220 		vOut[numOut].v = vIn[0].v + interp * (vIn[1].v - vIn[0].v);
    221 
    222 		// VertexA is hitting edgeB.
    223 		vOut[numOut].id.cf.indexA = static_cast<uint8>(vertexIndexA);
    224 		vOut[numOut].id.cf.indexB = vIn[0].id.cf.indexB;
    225 		vOut[numOut].id.cf.typeA = b2ContactFeature::e_vertex;
    226 		vOut[numOut].id.cf.typeB = b2ContactFeature::e_face;
    227 		++numOut;
    228 	}
    229 
    230 	return numOut;
    231 }
    232 
    233 bool b2TestOverlap(	const b2Shape* shapeA, int32 indexA,
    234 					const b2Shape* shapeB, int32 indexB,
    235 					const b2Transform& xfA, const b2Transform& xfB)
    236 {
    237 	b2DistanceInput input;
    238 	input.proxyA.Set(shapeA, indexA);
    239 	input.proxyB.Set(shapeB, indexB);
    240 	input.transformA = xfA;
    241 	input.transformB = xfB;
    242 	input.useRadii = true;
    243 
    244 	b2SimplexCache cache;
    245 	cache.count = 0;
    246 
    247 	b2DistanceOutput output;
    248 
    249 	b2Distance(&output, &cache, &input);
    250 
    251 	return output.distance < 10.0f * b2_epsilon;
    252 }
    253