00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include <Box2D/Collision/b2Collision.h>
00020 #include <Box2D/Collision/Shapes/b2PolygonShape.h>
00021
00022
00023 static float32 b2FindMaxSeparation(int32* edgeIndex,
00024 const b2PolygonShape* poly1, const b2Transform& xf1,
00025 const b2PolygonShape* poly2, const b2Transform& xf2)
00026 {
00027 int32 count1 = poly1->m_count;
00028 int32 count2 = poly2->m_count;
00029 const b2Vec2* n1s = poly1->m_normals;
00030 const b2Vec2* v1s = poly1->m_vertices;
00031 const b2Vec2* v2s = poly2->m_vertices;
00032 b2Transform xf = b2MulT(xf2, xf1);
00033
00034 int32 bestIndex = 0;
00035 float32 maxSeparation = -b2_maxFloat;
00036 for (int32 i = 0; i < count1; ++i)
00037 {
00038
00039 b2Vec2 n = b2Mul(xf.q, n1s[i]);
00040 b2Vec2 v1 = b2Mul(xf, v1s[i]);
00041
00042
00043 float32 si = b2_maxFloat;
00044 for (int32 j = 0; j < count2; ++j)
00045 {
00046 float32 sij = b2Dot(n, v2s[j] - v1);
00047 if (sij < si)
00048 {
00049 si = sij;
00050 }
00051 }
00052
00053 if (si > maxSeparation)
00054 {
00055 maxSeparation = si;
00056 bestIndex = i;
00057 }
00058 }
00059
00060 *edgeIndex = bestIndex;
00061 return maxSeparation;
00062 }
00063
00064 static void b2FindIncidentEdge(b2ClipVertex c[2],
00065 const b2PolygonShape* poly1, const b2Transform& xf1, int32 edge1,
00066 const b2PolygonShape* poly2, const b2Transform& xf2)
00067 {
00068 const b2Vec2* normals1 = poly1->m_normals;
00069
00070 int32 count2 = poly2->m_count;
00071 const b2Vec2* vertices2 = poly2->m_vertices;
00072 const b2Vec2* normals2 = poly2->m_normals;
00073
00074 b2Assert(0 <= edge1 && edge1 < poly1->m_count);
00075
00076
00077 b2Vec2 normal1 = b2MulT(xf2.q, b2Mul(xf1.q, normals1[edge1]));
00078
00079
00080 int32 index = 0;
00081 float32 minDot = b2_maxFloat;
00082 for (int32 i = 0; i < count2; ++i)
00083 {
00084 float32 dot = b2Dot(normal1, normals2[i]);
00085 if (dot < minDot)
00086 {
00087 minDot = dot;
00088 index = i;
00089 }
00090 }
00091
00092
00093 int32 i1 = index;
00094 int32 i2 = i1 + 1 < count2 ? i1 + 1 : 0;
00095
00096 c[0].v = b2Mul(xf2, vertices2[i1]);
00097 c[0].id.cf.indexA = (uint8)edge1;
00098 c[0].id.cf.indexB = (uint8)i1;
00099 c[0].id.cf.typeA = b2ContactFeature::e_face;
00100 c[0].id.cf.typeB = b2ContactFeature::e_vertex;
00101
00102 c[1].v = b2Mul(xf2, vertices2[i2]);
00103 c[1].id.cf.indexA = (uint8)edge1;
00104 c[1].id.cf.indexB = (uint8)i2;
00105 c[1].id.cf.typeA = b2ContactFeature::e_face;
00106 c[1].id.cf.typeB = b2ContactFeature::e_vertex;
00107 }
00108
00109
00110
00111
00112
00113
00114
00115
00116 void b2CollidePolygons(b2Manifold* manifold,
00117 const b2PolygonShape* polyA, const b2Transform& xfA,
00118 const b2PolygonShape* polyB, const b2Transform& xfB)
00119 {
00120 manifold->pointCount = 0;
00121 float32 totalRadius = polyA->m_radius + polyB->m_radius;
00122
00123 int32 edgeA = 0;
00124 float32 separationA = b2FindMaxSeparation(&edgeA, polyA, xfA, polyB, xfB);
00125 if (separationA > totalRadius)
00126 return;
00127
00128 int32 edgeB = 0;
00129 float32 separationB = b2FindMaxSeparation(&edgeB, polyB, xfB, polyA, xfA);
00130 if (separationB > totalRadius)
00131 return;
00132
00133 const b2PolygonShape* poly1;
00134 const b2PolygonShape* poly2;
00135 b2Transform xf1, xf2;
00136 int32 edge1;
00137 uint8 flip;
00138 const float32 k_tol = 0.1f * b2_linearSlop;
00139
00140 if (separationB > separationA + k_tol)
00141 {
00142 poly1 = polyB;
00143 poly2 = polyA;
00144 xf1 = xfB;
00145 xf2 = xfA;
00146 edge1 = edgeB;
00147 manifold->type = b2Manifold::e_faceB;
00148 flip = 1;
00149 }
00150 else
00151 {
00152 poly1 = polyA;
00153 poly2 = polyB;
00154 xf1 = xfA;
00155 xf2 = xfB;
00156 edge1 = edgeA;
00157 manifold->type = b2Manifold::e_faceA;
00158 flip = 0;
00159 }
00160
00161 b2ClipVertex incidentEdge[2];
00162 b2FindIncidentEdge(incidentEdge, poly1, xf1, edge1, poly2, xf2);
00163
00164 int32 count1 = poly1->m_count;
00165 const b2Vec2* vertices1 = poly1->m_vertices;
00166
00167 int32 iv1 = edge1;
00168 int32 iv2 = edge1 + 1 < count1 ? edge1 + 1 : 0;
00169
00170 b2Vec2 v11 = vertices1[iv1];
00171 b2Vec2 v12 = vertices1[iv2];
00172
00173 b2Vec2 localTangent = v12 - v11;
00174 localTangent.Normalize();
00175
00176 b2Vec2 localNormal = b2Cross(localTangent, 1.0f);
00177 b2Vec2 planePoint = 0.5f * (v11 + v12);
00178
00179 b2Vec2 tangent = b2Mul(xf1.q, localTangent);
00180 b2Vec2 normal = b2Cross(tangent, 1.0f);
00181
00182 v11 = b2Mul(xf1, v11);
00183 v12 = b2Mul(xf1, v12);
00184
00185
00186 float32 frontOffset = b2Dot(normal, v11);
00187
00188
00189 float32 sideOffset1 = -b2Dot(tangent, v11) + totalRadius;
00190 float32 sideOffset2 = b2Dot(tangent, v12) + totalRadius;
00191
00192
00193 b2ClipVertex clipPoints1[2];
00194 b2ClipVertex clipPoints2[2];
00195 int np;
00196
00197
00198 np = b2ClipSegmentToLine(clipPoints1, incidentEdge, -tangent, sideOffset1, iv1);
00199
00200 if (np < 2)
00201 return;
00202
00203
00204 np = b2ClipSegmentToLine(clipPoints2, clipPoints1, tangent, sideOffset2, iv2);
00205
00206 if (np < 2)
00207 {
00208 return;
00209 }
00210
00211
00212 manifold->localNormal = localNormal;
00213 manifold->localPoint = planePoint;
00214
00215 int32 pointCount = 0;
00216 for (int32 i = 0; i < b2_maxManifoldPoints; ++i)
00217 {
00218 float32 separation = b2Dot(normal, clipPoints2[i].v) - frontOffset;
00219
00220 if (separation <= totalRadius)
00221 {
00222 b2ManifoldPoint* cp = manifold->points + pointCount;
00223 cp->localPoint = b2MulT(xf2, clipPoints2[i].v);
00224 cp->id = clipPoints2[i].id;
00225 if (flip)
00226 {
00227
00228 b2ContactFeature cf = cp->id.cf;
00229 cp->id.cf.indexA = cf.indexB;
00230 cp->id.cf.indexB = cf.indexA;
00231 cp->id.cf.typeA = cf.typeB;
00232 cp->id.cf.typeB = cf.typeA;
00233 }
00234 ++pointCount;
00235 }
00236 }
00237
00238 manifold->pointCount = pointCount;
00239 }