00001
00002
00003
00004 #include "colmodel.h"
00005 #include "globals.h"
00006 #include "log.h"
00007
00008 const double EPSILON = 0.00001;
00009
00010
00011
00012
00013 CollisionModel::CollisionModel()
00014 {
00015 mReseted = true;
00016 mBox.zeroize();
00017 mTransBox.zeroize();
00018 mTranslation.set( 0, 0, 0 );
00019 mRotation.set( ZERO_ROTATION_VECTOR, 0 );
00020 mAvoidVector.set( 0, 0, 0);
00021 }
00022
00023 #define SEP_TEST(box1, box2, a1, a2, b1, b2) \
00024 if ( absD((d=box1.trySepparatingAxis(box2, a1, a2, b1, b2, normal))) < absD(min)) \
00025 { \
00026 if (absD(min = d) < EPSILON) return false; \
00027 result = normal; \
00028 }
00029
00030 #define SEPSELF_TEST(box1, box2, a1, a2, b1, b2) \
00031 if ( absD((d=box1.trySepparatingAxisSelf(box2, a1, a2, b1, b2, normal))) < absD(min)) \
00032 { \
00033 if (absD(min = d) < EPSILON) return false; \
00034 result = normal; \
00035 }
00036
00037 #define SEPSELF_MINUSTEST(box1, box2, a1, a2, b1, b2) \
00038 if ( absD((d=box1.trySepparatingAxisSelf(box2, a1, a2, b1, b2, normal))) < absD(min)) \
00039 { \
00040 if (absD(min = -d) < EPSILON) return false; \
00041 result = normal; \
00042 }
00043
00044 bool CollisionModel::computeMinimalAvoidVector(const CollisionModel & model, GLVector3d & result)
00045 {
00046
00047
00048 if (!mTransBox.quickCheckCollision(model.mTransBox))
00049 {
00050 return false;
00051 }
00052
00053 const CDBox &box1 = mTransBox;
00054 const CDBox &box2 = model.mTransBox;
00055
00056 GLVector3d normal;
00057 double d, min = 10000;
00058
00059
00060 for (int i = 0; i < 2; i++)
00061 {
00062 for (int j = 0; j < 2; j++)
00063 SEP_TEST(box1, box2, i, i+1, j, j+1);
00064
00065 SEP_TEST(box1, box2, i, i+1, 0, 4);
00066 SEP_TEST(box1, box2, 0, 4, i, i+1);
00067 }
00068 SEP_TEST(box1, box2, 0, 4, 0, 4);
00069
00070
00071 SEPSELF_TEST(box1, box2, 0, 1, 1, 2);
00072 SEPSELF_TEST(box1, box2, 1, 2, 1, 5);
00073 SEPSELF_TEST(box1, box2, 0, 1, 0, 4);
00074
00075
00076 SEPSELF_MINUSTEST(box1, box2, 0, 1, 1, 2);
00077 SEPSELF_MINUSTEST(box2, box1, 0, 1, 1, 2);
00078 SEPSELF_MINUSTEST(box2, box1, 1, 2, 1, 5);
00079 SEPSELF_MINUSTEST(box2, box1, 0, 1, 0, 4);
00080
00081
00082 result *= min;
00083
00084 return true;
00085 }
00086
00087 double projectAndCompareMax(const CDBox & box1, const CDBox & box2, const GLVector3d &normal, double scale)
00088 {
00089
00090 double min1, max1;
00091 box1.project(normal, min1, max1);
00092
00093
00094 double min2, max2;
00095 box2.project(normal, min2, max2);
00096
00097
00098 if (min2 >= max1 || min1 >= max2)
00099 {
00100 return 0;
00101 }
00102
00103 if (scale == 0) return 100000;
00104 if ((max2 - min1)/scale > 0) return (max2 - min1)/scale;
00105 return (min2 - max1)/scale;
00106 }
00107
00108 double trySepparatingAxisMax(const CDBox &box1, const CDBox &box2, int a1, int a2,
00109 int b1, int b2, GLVector3d &normal, const GLVector3d &direction)
00110 {
00111
00112 normal = box1.mVertex[a1]-box1.mVertex[a2];
00113 normal.cross(box2.mVertex[b1]-box2.mVertex[b2]);
00114
00115 if (normal.length() == 0)
00116 {
00117 return 100000000;
00118 }
00119 normal.normalize();
00120
00121 double scale = normal.dot(direction);
00122
00123 return projectAndCompareMax(box1, box2, normal, scale);
00124 }
00125
00126 double trySepparatingAxisSelfMax(const CDBox &box1, const CDBox &box2, int a1, int a2,
00127 int b1, int b2, GLVector3d &normal, const GLVector3d &direction)
00128 {
00129
00130 normal = box1.mVertex[a1]-box1.mVertex[a2];
00131 normal.cross(box1.mVertex[b1]-box1.mVertex[b2]);
00132
00133 if (normal.length() == 0)
00134 {
00135 return 100000000;
00136 }
00137 normal.normalize();
00138
00139 double scale = normal.dot(direction);
00140
00141 return projectAndCompareMax(box1, box2, normal, scale);
00142 }
00143
00144
00145 #define SEP_TESTMAX(box1, box2, a1, a2, b1, b2) \
00146 if ( (d = trySepparatingAxisMax(box1, box2, a1, a2, b1, b2, normal, direction)) < min) \
00147 { \
00148 if ((min = d) < EPSILON) return 0; \
00149 if (min < 0) \
00150 LOGE " POZOR!!!" << endl; \
00151 }
00152
00153 #define SEPSELF_TESTMAX(box1, box2, a1, a2, b1, b2) \
00154 if ( (d = trySepparatingAxisSelfMax(box1, box2, a1, a2, b1, b2, normal, direction)) < min) \
00155 { \
00156 if ((min = d) < EPSILON) return 0; \
00157 if (min < 0) \
00158 LOGE " POZOR!!!" << endl; \
00159 }
00160
00161 #define SEPSELF_MINUSTESTMAX(box1, box2, a1, a2, b1, b2) \
00162 if ( (d = trySepparatingAxisSelfMax(box1, box2, a1, a2, b1, b2, normal, -direction)) < min) \
00163 { \
00164 if ((min = d) < EPSILON) return 0; \
00165 if (min < 0) \
00166 LOGE " POZOR!!!" << endl; \
00167 }
00168
00169 double CollisionModel::computeMinimalAvoidDistance( const CollisionModel & model, GLVector3d & direction)
00170 {
00171
00172
00173 if (!mTransBox.quickCheckCollision(model.mTransBox))
00174 {
00175 return 0;
00176 }
00177
00178 const CDBox &box1 = mTransBox;
00179 const CDBox &box2 = model.mTransBox;
00180
00181 GLVector3d normal;
00182 double d, min = 10000;
00183
00184
00185 for (int i = 0; i < 2; i++)
00186 {
00187 for (int j = 0; j < 2; j++)
00188 SEP_TESTMAX(box1, box2, i, i+1, j, j+1);
00189
00190 SEP_TESTMAX(box1, box2, i, i+1, 0, 4);
00191 SEP_TESTMAX(box1, box2, 0, 4, i, i+1);
00192 }
00193 SEP_TESTMAX(box1, box2, 0, 4, 0, 4);
00194
00195
00196 SEPSELF_TESTMAX(box1, box2, 0, 1, 1, 2);
00197 SEPSELF_TESTMAX(box1, box2, 1, 2, 1, 5);
00198 SEPSELF_TESTMAX(box1, box2, 0, 1, 0, 4);
00199
00200
00201 SEPSELF_MINUSTESTMAX(box1, box2, 0, 1, 1, 2);
00202 SEPSELF_MINUSTESTMAX(box2, box1, 0, 1, 1, 2);
00203 SEPSELF_MINUSTESTMAX(box2, box1, 1, 2, 1, 5);
00204 SEPSELF_MINUSTESTMAX(box2, box1, 0, 1, 0, 4);
00205
00206 return min;
00207
00208 }