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