00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #include <physics/CollisionDetector>
00026
00027 #include <base/Dimension3>
00028 #include <base/Transform>
00029 #include <gfx/Segment3>
00030 #include <physics/Box>
00031 #include <physics/Sphere>
00032
00033 using physics::CollisionDetector;
00034
00035 using base::Dimension3;
00036 using base::Transform;
00037
00038 using gfx::Segment3;
00039
00040 using physics::Collidable;
00041 using physics::CollidableBody;
00042 using physics::CollidableGroup;
00043 using physics::CollisionState;
00044
00045 using physics::Shape;
00046 using physics::Box;
00047 using physics::Sphere;
00048
00049
00050
00051 namespace physics {
00052
00053
00054 bool operator<(ref<const CollidableBody> s1, const CollidableBody* s2)
00055 { return &(*s1) < s2; }
00056
00057 }
00058
00059
00060 const Real CollisionDetector::collisionEpsilon = 1e-6;
00061
00062
00063 CollisionDetector::CollisionDetector()
00064 : queryType(AllContactPoints)
00065 {
00066 }
00067
00068
00069 CollisionDetector::~CollisionDetector()
00070 {
00071 }
00072
00073
00074 Segment3 CollisionDetector::shortestSegmentBetween(ref<const Collidable> collidable1, ref<const Collidable> collidable2)
00075 {
00076
00077
00078
00079 if (instanceof(*collidable1, const CollidableGroup) || instanceof(*collidable2, const CollidableGroup))
00080 throw std::runtime_error(Exception("distance between CollidableGoups not yet implemented - sorry."));
00081
00082 if (instanceof(*collidable1, const CollidableBody) && instanceof(*collidable1, const CollidableBody)) {
00083
00084 ref<const CollidableBody> body1(narrow_ref<const CollidableBody>(collidable1));
00085 ref<const CollidableBody> body2(narrow_ref<const CollidableBody>(collidable2));
00086
00087 ref<const Shape> shape1(body1->getShape());
00088 ref<const Shape> shape2(body2->getShape());
00089
00090
00091
00092 if (instanceof(*shape1, const Box)) {
00093
00094 ref<const Box> box1(narrow_ref<const Box>(shape1));
00095
00096 if (instanceof(*shape2, const Box)) {
00097
00098 ref<const Box> box2(narrow_ref<const Box>(shape2));
00099
00100 return box1->shortestSegmentBetween( body1->getConfiguration(),
00101 box2, body2->getConfiguration());
00102 }
00103 else if (instanceof(*shape2, const Sphere)) {
00104
00105 ref<const Sphere> sphere2(narrow_ref<const Sphere>(shape2));
00106
00107
00108 Segment3 seg( box1->shortestSegmentBetween( body1->getConfiguration(),
00109 body2->getPosition() ) );
00110 Real r(sphere2->radius());
00111
00112 Vector3 dir(seg.e-seg.s);
00113 seg.e = seg.s + dir*(1-(r/dir.length()));
00114
00115 return seg;
00116
00117 }
00118 else
00119 throw std::runtime_error(Exception("unsupported Shape combination"));
00120
00121 }
00122 else if (instanceof(*shape1, const Sphere)) {
00123
00124 ref<const Sphere> sphere1(narrow_ref<const Sphere>(shape1));
00125
00126 if (instanceof(*shape2, const Box)) {
00127
00128 Segment3 minSeg = shortestSegmentBetween(collidable2, collidable1);
00129 base::swap(minSeg.s, minSeg.e);
00130 return minSeg;
00131
00132 }
00133 else if (instanceof(*shape2, const Sphere)) {
00134 ref<const Sphere> sphere2(narrow_ref<const Sphere>(shape2));
00135
00136 Vector3 vdir( body2->getPosition() - body1->getPosition() ); vdir.normalize();
00137 Point3 spherep1( body1->getPosition() + vdir*sphere1->radius() );
00138 Point3 spherep2( body2->getPosition() - vdir*sphere2->radius() );
00139 return Segment3( spherep1, spherep2 );
00140 }
00141 else
00142 throw std::runtime_error(Exception("unsupported Shape combination"));
00143
00144 }
00145 else
00146 throw std::runtime_error(Exception("unsupported Shape"));
00147
00148
00149 }
00150 else {
00151 throw std::runtime_error(Exception("unsupported Collidable subtype"));
00152 }
00153
00154 }
00155
00156 ref<CollisionState> CollisionDetector::getCollisionState(ref<const CollidableBody> collidableBody1, ref<const CollidableBody> collidableBody2) const
00157 {
00158 if (&(*collidableBody1) > &(*collidableBody2))
00159 base::swap(collidableBody1,collidableBody2);
00160
00161 CollidableBodyPair contactPair = std::make_pair(collidableBody1, collidableBody2);
00162
00163
00164 CollisionStateMap::iterator entry = collisionStates.find(contactPair);
00165 if (entry != collisionStates.end()) {
00166
00167 return entry->second;
00168 }
00169 else {
00170
00171 ref<CollisionState> collisionState = newCollisionState(collidableBody1,collidableBody2);
00172 collisionStates[contactPair] = collisionState;
00173 return collisionState;
00174 }
00175 }
00176
00177