File indexing completed on 2025-08-03 03:49:55
0001 /* 0002 * Copyright (c) 2007-2009 Erin Catto http://www.gphysics.com 0003 * 0004 * This software is provided 'as-is', without any express or implied 0005 * warranty. In no event will the authors be held liable for any damages 0006 * arising from the use of this software. 0007 * Permission is granted to anyone to use this software for any purpose, 0008 * including commercial applications, and to alter it and redistribute it 0009 * freely, subject to the following restrictions: 0010 * 1. The origin of this software must not be misrepresented; you must not 0011 * claim that you wrote the original software. If you use this software 0012 * in a product, an acknowledgment in the product documentation would be 0013 * appreciated but is not required. 0014 * 2. Altered source versions must be plainly marked as such, and must not be 0015 * misrepresented as being the original software. 0016 * 3. This notice may not be removed or altered from any source distribution. 0017 */ 0018 0019 #include <Box2D/Collision/b2Collision.h> 0020 #include <Box2D/Collision/b2Distance.h> 0021 0022 void b2WorldManifold::Initialize(const b2Manifold* manifold, 0023 const b2Transform& xfA, qreal radiusA, 0024 const b2Transform& xfB, qreal radiusB) 0025 { 0026 if (manifold->pointCount == 0) 0027 { 0028 return; 0029 } 0030 0031 switch (manifold->type) 0032 { 0033 case b2Manifold::e_circles: 0034 { 0035 normal.Set(1.0f, 0.0f); 0036 b2Vec2 pointA = b2Mul(xfA, manifold->localPoint); 0037 b2Vec2 pointB = b2Mul(xfB, manifold->points[0].localPoint); 0038 if (b2DistanceSquared(pointA, pointB) > b2_epsilon * b2_epsilon) 0039 { 0040 normal = pointB - pointA; 0041 normal.Normalize(); 0042 } 0043 0044 b2Vec2 cA = pointA + radiusA * normal; 0045 b2Vec2 cB = pointB - radiusB * normal; 0046 points[0] = 0.5f * (cA + cB); 0047 } 0048 break; 0049 0050 case b2Manifold::e_faceA: 0051 { 0052 normal = b2Mul(xfA.R, manifold->localNormal); 0053 b2Vec2 planePoint = b2Mul(xfA, manifold->localPoint); 0054 0055 for (int32 i = 0; i < manifold->pointCount; ++i) 0056 { 0057 b2Vec2 clipPoint = b2Mul(xfB, manifold->points[i].localPoint); 0058 b2Vec2 cA = clipPoint + (radiusA - b2Dot(clipPoint - planePoint, normal)) * normal; 0059 b2Vec2 cB = clipPoint - radiusB * normal; 0060 points[i] = 0.5f * (cA + cB); 0061 } 0062 } 0063 break; 0064 0065 case b2Manifold::e_faceB: 0066 { 0067 normal = b2Mul(xfB.R, manifold->localNormal); 0068 b2Vec2 planePoint = b2Mul(xfB, manifold->localPoint); 0069 0070 for (int32 i = 0; i < manifold->pointCount; ++i) 0071 { 0072 b2Vec2 clipPoint = b2Mul(xfA, manifold->points[i].localPoint); 0073 b2Vec2 cB = clipPoint + (radiusB - b2Dot(clipPoint - planePoint, normal)) * normal; 0074 b2Vec2 cA = clipPoint - radiusA * normal; 0075 points[i] = 0.5f * (cA + cB); 0076 } 0077 0078 // Ensure normal points from A to B. 0079 normal = -normal; 0080 } 0081 break; 0082 } 0083 } 0084 0085 void b2GetPointStates(b2PointState state1[b2_maxManifoldPoints], b2PointState state2[b2_maxManifoldPoints], 0086 const b2Manifold* manifold1, const b2Manifold* manifold2) 0087 { 0088 for (int32 i = 0; i < b2_maxManifoldPoints; ++i) 0089 { 0090 state1[i] = b2_nullState; 0091 state2[i] = b2_nullState; 0092 } 0093 0094 // Detect persists and removes. 0095 for (int32 i = 0; i < manifold1->pointCount; ++i) 0096 { 0097 b2ContactID id = manifold1->points[i].id; 0098 0099 state1[i] = b2_removeState; 0100 0101 for (int32 j = 0; j < manifold2->pointCount; ++j) 0102 { 0103 if (manifold2->points[j].id.key == id.key) 0104 { 0105 state1[i] = b2_persistState; 0106 break; 0107 } 0108 } 0109 } 0110 0111 // Detect persists and adds. 0112 for (int32 i = 0; i < manifold2->pointCount; ++i) 0113 { 0114 b2ContactID id = manifold2->points[i].id; 0115 0116 state2[i] = b2_addState; 0117 0118 for (int32 j = 0; j < manifold1->pointCount; ++j) 0119 { 0120 if (manifold1->points[j].id.key == id.key) 0121 { 0122 state2[i] = b2_persistState; 0123 break; 0124 } 0125 } 0126 } 0127 } 0128 0129 // From Real-time Collision Detection, p179. 0130 bool b2AABB::RayCast(b2RayCastOutput* output, const b2RayCastInput& input) const 0131 { 0132 qreal tmin = -b2_maxFloat; 0133 qreal tmax = b2_maxFloat; 0134 0135 b2Vec2 p = input.p1; 0136 b2Vec2 d = input.p2 - input.p1; 0137 b2Vec2 absD = b2Abs(d); 0138 0139 b2Vec2 normal; 0140 0141 for (int32 i = 0; i < 2; ++i) 0142 { 0143 if (absD(i) < b2_epsilon) 0144 { 0145 // Parallel. 0146 if (p(i) < lowerBound(i) || upperBound(i) < p(i)) 0147 { 0148 return false; 0149 } 0150 } 0151 else 0152 { 0153 qreal inv_d = 1.0f / d(i); 0154 qreal t1 = (lowerBound(i) - p(i)) * inv_d; 0155 qreal t2 = (upperBound(i) - p(i)) * inv_d; 0156 0157 // Sign of the normal vector. 0158 qreal s = -1.0f; 0159 0160 if (t1 > t2) 0161 { 0162 b2Swap(t1, t2); 0163 s = 1.0f; 0164 } 0165 0166 // Push the min up 0167 if (t1 > tmin) 0168 { 0169 normal.SetZero(); 0170 normal(i) = s; 0171 tmin = t1; 0172 } 0173 0174 // Pull the max down 0175 tmax = b2Min(tmax, t2); 0176 0177 if (tmin > tmax) 0178 { 0179 return false; 0180 } 0181 } 0182 } 0183 0184 // Does the ray start inside the box? 0185 // Does the ray intersect beyond the max fraction? 0186 if (tmin < 0.0f || input.maxFraction < tmin) 0187 { 0188 return false; 0189 } 0190 0191 // Intersection. 0192 output->fraction = tmin; 0193 output->normal = normal; 0194 return true; 0195 } 0196 0197 // Sutherland-Hodgman clipping. 0198 int32 b2ClipSegmentToLine(b2ClipVertex vOut[2], const b2ClipVertex vIn[2], 0199 const b2Vec2& normal, qreal offset, int32 vertexIndexA) 0200 { 0201 // Start with no output points 0202 int32 numOut = 0; 0203 0204 // Calculate the distance of end points to the line 0205 qreal distance0 = b2Dot(normal, vIn[0].v) - offset; 0206 qreal distance1 = b2Dot(normal, vIn[1].v) - offset; 0207 0208 // If the points are behind the plane 0209 if (distance0 <= 0.0f) vOut[numOut++] = vIn[0]; 0210 if (distance1 <= 0.0f) vOut[numOut++] = vIn[1]; 0211 0212 // If the points are on different sides of the plane 0213 if (distance0 * distance1 < 0.0f) 0214 { 0215 // Find intersection point of edge and plane 0216 qreal interp = distance0 / (distance0 - distance1); 0217 vOut[numOut].v = vIn[0].v + interp * (vIn[1].v - vIn[0].v); 0218 0219 // VertexA is hitting edgeB. 0220 vOut[numOut].id.cf.indexA = vertexIndexA; 0221 vOut[numOut].id.cf.indexB = vIn[0].id.cf.indexB; 0222 vOut[numOut].id.cf.typeA = b2ContactFeature::e_vertex; 0223 vOut[numOut].id.cf.typeB = b2ContactFeature::e_face; 0224 ++numOut; 0225 } 0226 0227 return numOut; 0228 } 0229 0230 bool b2TestOverlap( const b2Shape* shapeA, int32 indexA, 0231 const b2Shape* shapeB, int32 indexB, 0232 const b2Transform& xfA, const b2Transform& xfB) 0233 { 0234 b2DistanceInput input; 0235 input.proxyA.Set(shapeA, indexA); 0236 input.proxyB.Set(shapeB, indexB); 0237 input.transformA = xfA; 0238 input.transformB = xfB; 0239 input.useRadii = true; 0240 0241 b2SimplexCache cache; 0242 cache.count = 0; 0243 0244 b2DistanceOutput output; 0245 0246 b2Distance(&output, &cache, &input); 0247 0248 return output.distance < 10.0f * b2_epsilon; 0249 }