00001
00002
00003
00004
00005 #include <flatland/shapes.hpp>
00006 #include <flatland/intersection.hpp>
00007
00008
00009
00010 namespace
00011 {
00012 Flatland::vec2 delta;
00013 float dotA0B0, dotA0B1, dotA1B0, dotA1B1;
00014 float absDotA0B0, absDotA0B1, absDotA1B0, absDotA1B1;
00015 float extAA0B0, extAA0B1, extAA1B0, extAA1B1, extBA0B0, extBA0B1, extBA1B0, extBA1B1;
00016 float depth;
00017 enum ECode {NA0, NA1, NB0, NB1, PA0, PA1, PB0, PB1} code;
00018 }
00019
00020 bool Flatland::Intersection::TestQuadQuad(const Geometry &g1, const Geometry &g2)
00021 {
00022 assert(g1.GetShape() == Shape::Quad);
00023 assert(g2.GetShape() == Shape::Quad);
00024 const Quad &a = static_cast<const Quad&>(g1);
00025 const Quad &b = static_cast<const Quad&>(g2);
00026
00027 delta = a.Center() - b.Center();
00028 float minDepth = HUGE_VAL;
00029
00030
00031 dotA0B0 = dot(a.Axis(0), b.Axis(0));
00032 absDotA0B0 = fabsf(dotA0B0);
00033 dotA0B1 = dot(a.Axis(0), b.Axis(1));
00034 absDotA0B1 = fabsf(dotA0B1);
00035 extBA0B0 = b.Extent(0)*absDotA0B0;
00036 extBA0B1 = b.Extent(1)*absDotA0B1;
00037 float dist1 = dot(a.Axis(0), delta);
00038 float dist2 = a.Extent(0) + extBA0B0 + extBA0B1;
00039 depth = dist2 - fabsf(dist1);
00040 if (depth < 0)
00041 return false;
00042 if (depth < minDepth)
00043 {
00044 minDepth = depth;
00045 code = dist1 < 0 ? NA0 : PA0;
00046 }
00047
00048
00049 dotA1B0 = dot(a.Axis(1), b.Axis(0));
00050 absDotA1B0 = fabsf(dotA1B0);
00051 dotA1B1 = dot(a.Axis(1), b.Axis(1));
00052 absDotA1B1 = fabsf(dotA1B1);
00053 extBA1B0 = b.Extent(0)*absDotA1B0;
00054 extBA1B1 = b.Extent(1)*absDotA1B1;
00055 dist1 = dot(a.Axis(1), delta);
00056 dist2 = a.Extent(1) + extBA1B0 + extBA1B1;
00057 depth = dist2 - fabsf(dist1);
00058 if (depth < 0)
00059 return false;
00060 if (depth < minDepth)
00061 {
00062 minDepth = depth;
00063 code = dist1 < 0 ? NA1 : PA1;
00064 }
00065
00066
00067 extAA0B0 = a.Extent(0)*absDotA0B0;
00068 extAA1B0 = a.Extent(1)*absDotA1B0;
00069 dist1 = dot(b.Axis(0), delta);
00070 dist2 = b.Extent(0) + extAA0B0 + extAA1B0;
00071 depth = dist2 - fabsf(dist1);
00072 if (depth < 0)
00073 return false;
00074 if (depth < minDepth)
00075 {
00076 minDepth = depth;
00077 code = dist1 < 0 ? NB0 : PB0;
00078 }
00079
00080
00081 extAA0B1 = a.Extent(0)*absDotA0B1;
00082 extAA1B1 = a.Extent(1)*absDotA1B1;
00083 dist1 = dot(b.Axis(1), delta);
00084 dist2 = b.Extent(1) + extAA0B1 + extAA1B1;
00085 depth = dist2 - fabsf(dist1);
00086 if (depth < 0)
00087 return false;
00088 if (depth < minDepth)
00089 {
00090 minDepth = depth;
00091 code = dist1 < 0 ? NB1 : PB1;
00092 }
00093
00094 return true;
00095 }
00096
00097 void Flatland::Intersection::FindQuadQuad(const Geometry &g1, const Geometry &g2, ContactList &contacts)
00098 {
00099 assert(g1.GetShape() == Shape::Quad);
00100 assert(g2.GetShape() == Shape::Quad);
00101 const Quad &a = static_cast<const Quad&>(g1);
00102 const Quad &b = static_cast<const Quad&>(g2);
00103
00104 vec2 normal;
00105 vec2 normal2;
00106 vec2 center;
00107 int axis0, axis1;
00108 int a0, a1;
00109 const Quad *reference;
00110 const Quad *incident;
00111 float m11;
00112 float k1;
00113 bool negate;
00114
00115 switch (code)
00116 {
00117 case PA0:
00118 normal = a.Axis(0);
00119 axis0 = 0; axis1 = 1;
00120 normal2 = -normal;
00121 reference = &a; incident = &b;
00122 a0 = absDotA0B1 > absDotA0B0 ? 1 : 0; a1 = 1 - a0;
00123 if (a1)
00124 {
00125 m11 = dotA1B1;
00126 k1 = extBA1B1;
00127 negate = -dotA0B0 < 0;
00128 }
00129 else
00130 {
00131 m11 = dotA1B0;
00132 k1 = extBA1B0;
00133 negate = -dotA0B1 < 0;
00134 }
00135 center = -delta;
00136 break;
00137
00138 case PA1:
00139 normal = a.Axis(1);
00140 axis0 = 1; axis1 = 0;
00141 normal2 = -normal;
00142 reference = &a; incident = &b;
00143 a0 = absDotA1B1 > absDotA1B0 ? 1 : 0; a1 = 1 - a0;
00144 if (a1)
00145 {
00146 m11 = dotA0B1;
00147 k1 = extBA0B1;
00148 negate = -dotA1B0 < 0;
00149 }
00150 else
00151 {
00152 m11 = dotA0B0;
00153 k1 = extBA0B0;
00154 negate = -dotA1B1 < 0;
00155 }
00156 center = -delta;
00157 break;
00158
00159 case PB0:
00160 normal = b.Axis(0);
00161 axis0 = 0; axis1 = 1;
00162 normal2 = normal;
00163 reference = &b; incident = &a;
00164 a0 = absDotA1B0 > absDotA0B0 ? 1 : 0; a1 = 1 - a0;
00165 if (a1)
00166 {
00167 m11 = dotA1B1;
00168 k1 = extAA1B1;
00169 negate = dotA0B0 < 0;
00170 }
00171 else
00172 {
00173 m11 = dotA0B1;
00174 k1 = extAA0B1;
00175 negate = dotA1B0 < 0;
00176 }
00177 center = delta;
00178 break;
00179
00180 case PB1:
00181 normal = b.Axis(1);
00182 axis0 = 1; axis1 = 0;
00183 normal2 = normal;
00184 reference = &b; incident = &a;
00185 a0 = absDotA1B1 > absDotA0B1 ? 1 : 0; a1 = 1 - a0;
00186 if (a1)
00187 {
00188 m11 = dotA1B0;
00189 k1 = extAA1B0;
00190 negate = dotA0B1 < 0;
00191 }
00192 else
00193 {
00194 m11 = dotA0B0;
00195 k1 = extAA0B0;
00196 negate = dotA1B1 < 0;
00197 }
00198 center = delta;
00199 break;
00200
00201 case NA0:
00202 normal = -a.Axis(0);
00203 axis0 = 0; axis1 = 1;
00204 normal2 = -normal;
00205 reference = &a; incident = &b;
00206 a0 = absDotA0B1 > absDotA0B0 ? 1 : 0; a1 = 1 - a0;
00207 if (a1)
00208 {
00209 m11 = dotA1B1;
00210 k1 = extBA1B1;
00211 negate = dotA0B0 < 0;
00212 }
00213 else
00214 {
00215 m11 = dotA1B0;
00216 k1 = extBA1B0;
00217 negate = dotA0B1 < 0;
00218 }
00219 center = -delta;
00220 break;
00221
00222 case NA1:
00223 normal = -a.Axis(1);
00224 axis0 = 1; axis1 = 0;
00225 normal2 = -normal;
00226 reference = &a; incident = &b;
00227 a0 = absDotA1B1 > absDotA1B0 ? 1 : 0; a1 = 1 - a0;
00228 if (a1)
00229 {
00230 m11 = dotA0B1;
00231 k1 = extBA0B1;
00232 negate = dotA1B0 < 0;
00233 }
00234 else
00235 {
00236 m11 = dotA0B0;
00237 k1 = extBA0B0;
00238 negate = dotA1B1 < 0;
00239 }
00240 center = -delta;
00241 break;
00242
00243 case NB0:
00244 normal = -b.Axis(0);
00245 axis0 = 0; axis1 = 1;
00246 normal2 = normal;
00247 reference = &b; incident = &a;
00248 a0 = absDotA1B0 > absDotA0B0 ? 1 : 0; a1 = 1 - a0;
00249 if (a1)
00250 {
00251 m11 = dotA1B1;
00252 k1 = extAA1B1;
00253 negate = -dotA0B0 < 0;
00254 }
00255 else
00256 {
00257 m11 = dotA0B1;
00258 k1 = extAA0B1;
00259 negate = -dotA1B0 < 0;
00260 }
00261 center = delta;
00262 break;
00263
00264 case NB1:
00265 normal = -b.Axis(1);
00266 axis0 = 1; axis1 = 0;
00267 normal2 = normal;
00268 reference = &b; incident = &a;
00269 a0 = absDotA1B1 > absDotA0B1 ? 1 : 0; a1 = 1 - a0;
00270 if (a1)
00271 {
00272 m11 = dotA1B0;
00273 k1 = extAA1B0;
00274 negate = -dotA0B1 < 0;
00275 }
00276 else
00277 {
00278 m11 = dotA0B0;
00279 k1 = extAA0B0;
00280 negate = -dotA1B1 < 0;
00281 }
00282 center = delta;
00283 break;
00284 }
00285
00286
00287 if (negate)
00288 center += incident->EAxis(a0);
00289 else
00290 center -= incident->EAxis(a0);
00291
00292
00293 float collisions[2];
00294 int count = 0;
00295 {
00296 float c1 = dot(center, reference->Axis(axis1));
00297 float a = c1 - k1;
00298 float b = c1 + k1;
00299 float w = reference->Extent(axis1);
00300
00301 if (w > a && w < b)
00302 collisions[count++] = w - c1;
00303 if (a < w && a > -w)
00304 collisions[count++] = -k1;
00305 if (-w > a && -w < b)
00306 collisions[count++] = -w - c1;
00307 if (b < w && b > -w)
00308 collisions[count++] = k1;
00309 }
00310
00311
00312 assert(count < 3);
00313
00314 for (int j = 0; j < count; ++j)
00315 {
00316 float k1 = collisions[j] / m11;
00317 vec2 point = center + incident->Axis(a1) * k1;
00318 float depth = reference->Extent(axis0) - dot(normal2, point);
00319 if (depth >= 0)
00320 contacts.AddContact(point + reference->Center(), normal, depth);
00321 }
00322 }