00001
00002
00003
00004
00005 #include <flatland/shapes.hpp>
00006 #include <flatland/intersection.hpp>
00007
00008 bool Flatland::Intersection::TestCircleQuad(const Geometry &c, const Geometry &q)
00009 {
00010 return TestQuadCircle(q, c);
00011 }
00012
00013 bool Flatland::Intersection::TestQuadCircle(const Geometry &g1, const Geometry &g2)
00014 {
00015 assert(g1.GetShape() == Shape::Quad);
00016 assert(g2.GetShape() == Shape::Circle);
00017 const Quad &q = static_cast<const Quad&>(g1);
00018 const Circle &c = static_cast<const Circle&>(g2);
00019
00020 bool onborder = false;
00021 vec2 l, t;
00022
00023 vec2 p = c.Center() - q.Center();
00024 l.x = q.Extent(0);
00025 t.x = dot(p, q.Axis(0));
00026 if (t.x < -l.x) { t.x = -l.x; onborder = true; }
00027 if (t.x > l.x) { t.x = l.x; onborder = true; }
00028
00029 l.y = q.Extent(1);
00030 t.y = dot(p, q.Axis(1));
00031 if (t.y < -l.y) { t.y = -l.y; onborder = true; }
00032 if (t.y > l.y) { t.y = l.y; onborder = true; }
00033
00034 if (!onborder)
00035 return true;
00036
00037 vec2 qq, r;
00038 vec2 a(q.Axis(0).x, q.Axis(1).x);
00039 vec2 b(q.Axis(0).y, q.Axis(1).y);
00040 qq.x = dot(t, a);
00041 qq.y = dot(t, b);
00042 r = p - qq;
00043 float depth = c.Radius() - r.length();
00044 return depth >= 0;
00045 }
00046
00047 void Flatland::Intersection::FindCircleQuad(const Geometry &c, const Geometry &q, ContactList &contacts)
00048 {
00049 contacts.ToggleNormalInversion();
00050 FindQuadCircle(q, c, contacts);
00051 contacts.ToggleNormalInversion();
00052 }
00053
00054 void Flatland::Intersection::FindQuadCircle(const Geometry &g1, const Geometry &g2, ContactList &contacts)
00055 {
00056 assert(g1.GetShape() == Shape::Quad);
00057 assert(g2.GetShape() == Shape::Circle);
00058 const Quad &q = static_cast<const Quad&>(g1);
00059 const Circle &c = static_cast<const Circle&>(g2);
00060
00061 bool onborder = false;
00062 vec2 l, t;
00063
00064 vec2 p = c.Center() - q.Center();
00065 l.x = q.Extent(0);
00066 t.x = dot(p, q.Axis(0));
00067 if (t.x < -l.x) { t.x = -l.x; onborder = true; }
00068 if (t.x > l.x) { t.x = l.x; onborder = true; }
00069
00070 l.y = q.Extent(1);
00071 t.y = dot(p, q.Axis(1));
00072 if (t.y < -l.y) { t.y = -l.y; onborder = true; }
00073 if (t.y > l.y) { t.y = l.y; onborder = true; }
00074
00075 if (!onborder)
00076 {
00077
00078 float min_distance = l.x - fabsf(t.x);
00079 vec2 normal = t.x < 0 ? -q.Axis(0) : q.Axis(0);
00080
00081 float face_distance = l.y - fabsf(t.y);
00082 if (face_distance < min_distance)
00083 {
00084 min_distance = face_distance;
00085 normal = t.y < 0 ? q.Axis(1) : -q.Axis(1);
00086 }
00087
00088 float depth = min_distance + c.Radius();
00089 contacts.AddContact(c.Center(), normal, depth);
00090 }
00091
00092 vec2 qq, r;
00093 vec2 a(q.Axis(0).x, q.Axis(1).x);
00094 vec2 b(q.Axis(0).y, q.Axis(1).y);
00095 qq.x = dot(t, a);
00096 qq.y = dot(t, b);
00097 r = p - qq;
00098
00099 float distance = r.length();
00100 float depth = c.Radius() - distance;
00101 if (depth < 0)
00102 return;
00103
00104 if (distance)
00105 r.normalize();
00106 else
00107 r = vec2(1, 0);
00108
00109 contacts.AddContact(qq + q.Center(), -r, depth);
00110 }