00001 #include "NavMesh.hpp" 00002 #include "util/math/all.hpp" 00003 #include "util/vecmath/Point3.hpp" 00004 #include "util/bounds/BoundingBox.hpp" 00005 #include "sim/pos/Pos.hpp" 00006 #include "sim/react/AreaEdge.hpp" 00007 00008 using namespace se_core; 00009 00010 namespace se_basic { 00011 // isLeft(): tests if point P2 is Left|On|Right of the line P0 to P1. 00012 // returns: >0 for left, 0 for on, and <0 for right of the line. 00013 // (see the January 2001 Algorithm on Area of Triangles) 00014 float left(const Point3& P0, const Point3& P1, const Point3& P2 ) { 00015 return (P1.x_ - P0.x_) * (P2.z_ - P0.z_) - (P2.x_ - P0.x_) * (P1.z_ - P0.z_); 00016 } 00017 00018 00019 bool doLinesIntersectXZ(const se_core::Point3& a0 00020 , const se_core::Point3& a1 00021 , const se_core::Point3& b0 00022 , const se_core::Point3& b1) { 00023 Point2 tmp; 00024 return (tmp.lineIntersect(a0, a1, b0, b1) != -1); 00025 /* 00026 float s1 = left( b0, b1, a0) * left( b0, b1, a1); 00027 float s2 = left( a0, a1, b0) * left( a0, a1, b1); 00028 return (s1 <= 0 && s2 < 0); 00029 00030 //return doLinesIntersectXZ(a0, a1, b0, b1, 0); 00031 */ 00032 } 00033 00034 00035 bool willLineAIntersectBXZ(const se_core::Point3& a0 00036 , const se_core::Point3& a1 00037 , const se_core::Point3& b0 00038 , const se_core::Point3& b1) { 00039 Point2 tmp; 00040 return (tmp.willAIntersectB(a0, a1, b0, b1)); 00041 /* 00042 float s1 = left( b0, b1, a0) * left( b0, b1, a1); 00043 float s2 = left( a0, a1, b0) * left( a0, a1, b1); 00044 return (s1 <= 0 && s2 < 0); 00045 00046 //return doLinesIntersectXZ(a0, a1, b0, b1, 0); 00047 */ 00048 } 00049 00050 /* 00051 bool doLinesIntersectXZ(const se_core::Point3& a0 00052 , const se_core::Point3& a1 00053 , const se_core::Point3& b0 00054 , const se_core::Point3& b1 00055 , se_core::Point2* out) { 00056 // http://local.wasp.uwa.edu.au/~pbourke/geometry/lineline2d/ 00057 00058 coor_t numeratorA = ((b1.x_ - b0.x_) * (a0.z_ - b0.z_) 00059 - (b1.z_ - b0.z_) * (a0.x_ - b0.x_)); 00060 coor_t numeratorB = ((a1.x_ - a0.x_) * (a0.z_ - b0.z_) 00061 - (a1.z_ - a0.z_) * (a0.x_ - b0.x_)); 00062 00063 coor_t divisor = ((b1.z_ - b0.z_) * (a1.x_ - a0.x_) 00064 - (b1.x_ - b0.x_) * (a1.z_ - a0.z_)); 00065 00066 if(numeratorA == 0 && numeratorB == 0 && divisor == 0) { 00067 AssertWarning(!doLinesIntersectXZ(a0, a1, b0, b1), divisor); 00068 return false; 00069 } 00070 00071 if(divisor == 0) { 00072 AssertWarning(!doLinesIntersectXZ(a0, a1, b0, b1), divisor); 00073 return false; 00074 } 00075 00076 coor_t ua = numeratorA / divisor; 00077 coor_t ub = numeratorB / divisor; 00078 00079 bool res = (ua >= 0 && ua < 1 && ub >= 0 && ub < 1); 00080 if(res && out) { 00081 out->x_ = a0.x_ + ua * (a1.x_ - a0.x_); 00082 out->y_ = a0.z_ + ua * (a1.z_ - a0.z_); 00083 } 00084 //if(ua >= 0 && ua <= 1 && ub >= 0 && ub <= 1) 00085 AssertWarning(res == doLinesIntersectXZ(a0, a1, b0, b1), ua << " - " << ub); 00086 //LogDetail(ua << ", " << ub << ": " << a0.x_ + ua * (a1.x_ - a0.x_) << ", " << a0.z_ + ua * (a1.z_ - a0.z_) << ": " << (doLinesIntersectXZ(a0, a1, b0, b1) ? "true" : "false") ); 00087 return res; 00088 } 00089 */ 00090 00091 00092 int NavMesh 00093 ::isInLineOfSight(const se_core::Pos& from, const se_core::Pos& to) const { 00094 return isInLineOfSight(from.localCoor(), from.index(), to.localCoor(), to.index()); 00095 } 00096 00097 00098 int NavMesh 00099 ::isInLineOfSight(const se_core::Point3& from, short fromIndex, const se_core::Point3& to, short toIndex) const { 00100 static const short corners[][2] = { 00101 { 1, 2 }, 00102 { 2, 0 }, 00103 { 0, 1 } 00104 }; 00105 00106 short via = fromIndex; 00107 short prev = -1; 00108 while(via != toIndex) { 00109 Triangle& tri = triangles_[ via ]; 00110 Point3* b[] = { 00111 &controlPoints_[ tri.controlPoints_[ 0 ] ], 00112 &controlPoints_[ tri.controlPoints_[ 1 ] ], 00113 &controlPoints_[ tri.controlPoints_[ 2 ] ] 00114 }; 00115 short next = -1; 00116 for(int i = 0; i < 3; ++i) { 00117 short link = triangles_[ via ].linkTo_[ i ]; 00118 if(link != prev && link != -1) { 00119 if(willLineAIntersectBXZ(from, to, *b[ corners[ i ][ 0 ] ], *b[ corners[ i ][ 1 ] ])) { 00120 if(link < 0) { 00121 return tri.linkType_[ i ]; 00122 } 00123 next = link; 00124 } 00125 } 00126 } 00127 if(next < 0) { 00128 return -1; 00129 } 00130 prev = via; 00131 via = next; 00132 } 00133 return 0; 00134 } 00135 00136 00137 bool NavMesh 00138 ::doesTouchVoid(const se_core::Point3& p, short pIndex, const coor_t radius) const { 00139 static const int STACK_SIZE = 10; 00140 static const short corners[][2] = { 00141 { 1, 2 }, 00142 { 2, 0 }, 00143 { 0, 1 } 00144 }; 00145 00146 Point3 nearest; 00147 const coor_double_t radiusSq = CoorT::pow2(radius); 00148 00149 struct { 00150 short index_; 00151 short edge_; 00152 } stack[STACK_SIZE]; 00153 00154 int sp = 0; 00155 stack[sp].index_ = pIndex; 00156 stack[sp].edge_ = 0; 00157 short prev = -1; 00158 00159 while(sp > 0 || stack[sp].edge_ <= 2) { 00160 const short via = stack[sp].index_; 00161 const short i = stack[sp].edge_; 00162 ++stack[sp].edge_; 00163 00164 Point3* b[] = { 00165 &controlPoints_[ triangles_[ via ].controlPoints_[ 0 ] ], 00166 &controlPoints_[ triangles_[ via ].controlPoints_[ 1 ] ], 00167 &controlPoints_[ triangles_[ via ].controlPoints_[ 2 ] ] 00168 }; 00169 nearest.nearestPoint(*b[corners[ i ][ 0 ]], *b[corners[ i ][ 1 ]], p); 00170 if(nearest.distanceSquared(p) < radiusSq) { 00171 const short link = triangles_[ via ].linkTo_[ i ]; 00172 if(link == -1) { 00173 return true; 00174 } 00175 if(link == prev) { 00176 continue; 00177 } 00178 prev = stack[sp].index_; 00179 ++sp; 00180 Assert(sp < STACK_SIZE); 00181 stack[sp].index_ = link; 00182 stack[sp].edge_ = 0; 00183 } 00184 while(stack[sp].edge_ > 2 && sp > 0) { 00185 --sp; 00186 prev = (sp > 0) ? stack[sp - 1].index_ : -1; 00187 } 00188 } 00189 return false; 00190 } 00191 00192 00193 int NavMesh 00194 ::farthestLineOfSightXZ(int fromIndex, const se_core::Point3& from, const se_core::Point3& to, short toIndex, Point2& dest) const { 00195 static const short corners[][2] = { 00196 { 1, 2 }, 00197 { 2, 0 }, 00198 { 0, 1 } 00199 }; 00200 00201 short via = fromIndex; 00202 short prev = -2; 00203 Point2 test; 00204 dest.set(from.x_, from.z_); 00205 while(via != toIndex) { 00206 Triangle& tri = triangles_[ via ]; 00207 Point3* b[] = { 00208 &controlPoints_[ tri.controlPoints_[ 0 ] ], 00209 &controlPoints_[ tri.controlPoints_[ 1 ] ], 00210 &controlPoints_[ tri.controlPoints_[ 2 ] ] 00211 }; 00212 short next = -1; 00213 short side = -1; 00214 coor_double_t d = 0; 00215 for(int i = 0; i < 3; ++i) { 00216 short link = tri.linkTo_[ i ]; 00217 if(link != prev) { 00218 if(test.lineIntersect(*b[ corners[ i ][ 0 ] ], *b[ corners[ i ][ 1 ] ], from, to) != -1) { 00219 coor_t xDist = from.x_ - test.x_; 00220 coor_t zDist = from.z_ - test.y_; 00221 coor_double_t newD = xDist * xDist + zDist * zDist; 00222 if(newD >= d) { 00223 d = newD; 00224 side = i; 00225 next = link; 00226 dest.set(test); 00227 } 00228 } 00229 } 00230 } 00231 if(next < 0) { 00232 if(side >= 0) { 00233 return tri.linkType_[ side ]; 00234 } 00235 return -1; 00236 } 00237 00238 prev = via; 00239 via = next; 00240 } 00241 dest.set(to.x_, to.z_); 00242 return 0; 00243 } 00244 00245 void NavMesh 00246 ::walls(AreaEdge& areaEdge) const { 00247 static const short corners[][2] = { 00248 { 1, 2 }, 00249 { 2, 0 }, 00250 { 0, 1 } 00251 }; 00252 for(int i = 0; i < triangleCount_; ++i) { 00253 for(int j = 0; j < 3; ++j) { 00254 if(triangles_[ i ].linkTo_[ j ] < 0 && triangles_[ i ].linkType_[ j ] == -1) { 00255 Point3& c1 = controlPoints_[ triangles_[ i ].controlPoints_[ corners[ j ][ 0 ] ] ]; 00256 Point3& c2 = controlPoints_[ triangles_[ i ].controlPoints_[ corners[ j ][ 1 ] ] ]; 00257 00258 Point2 p1(c1.x_, c1.z_); 00259 Point2 p2(c2.x_, c2.z_); 00260 areaEdge.addLink(p1, p2); 00261 } 00262 } 00263 } 00264 } 00265 00266 00267 bray_t NavMesh 00268 ::slideAngle(const se_core::Point3& from, short fromIndex, const se_core::Point3& to) const { 00269 static const short corners[][2] = { 00270 { 1, 2 }, 00271 { 2, 0 }, 00272 { 0, 1 } 00273 }; 00274 bray_t currentYaw = from.yawTowards(to); 00275 00276 short via = fromIndex; 00277 short prev = -2; 00278 while(via != -1) { 00279 Triangle& tri = triangles_[ via ]; 00280 Point3* b[] = { 00281 &controlPoints_[ tri.controlPoints_[ 0 ] ], 00282 &controlPoints_[ tri.controlPoints_[ 1 ] ], 00283 &controlPoints_[ tri.controlPoints_[ 2 ] ] 00284 }; 00285 short next = -1; 00286 for(int i = 0; i < 3; ++i) { 00287 short link = tri.linkTo_[ i ]; 00288 if(link != prev) { 00289 if(doLinesIntersectXZ(*b[ corners[ i ][ 0 ] ], *b[ corners[ i ][ 1 ] ], from, to)) { 00290 if(link < 0) { 00291 int wall = tri.controlPoints_[ corners[ i ][ 0 ] ]; 00292 // NOTE: Found edge - exiting!!! 00293 Point3& left = controlPoints_[ wall ]; 00294 Point3& right = controlPoints_[ walls_[ wall ].right_ ]; 00295 bray_t slideYaw = left.yawTowards(right); 00296 00297 //bray_t slideYaw = b[ corners[ i ][ 0 ] ]->yawTowards(*b[ corners[ i ][ 1 ] ]); 00298 if(BrayT::abs(BrayT::sub(currentYaw, slideYaw)) > BrayT::DEG90) { 00299 slideYaw = BrayT::invert(slideYaw); 00300 slideYaw += BRAY_RES / 4; 00301 } 00302 else { 00303 slideYaw -= BRAY_RES / 4; 00304 } 00305 if(BrayT::abs(BrayT::sub(currentYaw, slideYaw)) >= 64 * BRAY_RES) { 00306 return currentYaw; 00307 } 00308 return slideYaw; 00309 } 00310 next = link; 00311 } 00312 } 00313 } 00314 00315 prev = via; 00316 via = next; 00317 } 00318 return currentYaw; 00319 } 00320 00321 00322 bray_t NavMesh 00323 ::wallAngle(const se_core::Point3& from, short fromIndex, const se_core::Point3& to) const { 00324 static const short corners[][2] = { 00325 { 1, 2 }, 00326 { 2, 0 }, 00327 { 0, 1 } 00328 }; 00329 Point2 tmp; 00330 00331 00332 bray_t currentYaw = from.yawTowards(to); 00333 short via = fromIndex; 00334 Assert(via != -1); 00335 short prev = -2; 00336 while(via != -1) { 00337 Point3* b[] = { 00338 &controlPoints_[ triangles_[ via ].controlPoints_[ 0 ] ], 00339 &controlPoints_[ triangles_[ via ].controlPoints_[ 1 ] ], 00340 &controlPoints_[ triangles_[ via ].controlPoints_[ 2 ] ] 00341 }; 00342 short next = -2; 00343 //short count = 0; 00344 for(int i = 0; i < 3; ++i) { 00345 short link = triangles_[ via ].linkTo_[ i ]; 00346 if(link != prev) { 00347 if(tmp.willAIntersectB(from, to, *b[ corners[ i ][ 0 ] ], *b[ corners[ i ][ 1 ] ])) { 00348 if(link < 0 && next != -1) { 00349 int wall = triangles_[ via ].controlPoints_[ corners[ i ][ 0 ] ]; 00350 scale_t alpha = tmp.lineIntersect(*b[ corners[ i ][ 0 ] ], *b[ corners[ i ][ 1 ] ], from, to); 00351 bray_t wallYaw; 00352 if(alpha < .25f) { 00353 Point3& middle = controlPoints_[ wall ]; 00354 Point3& leftP = controlPoints_[ walls_[ wall ].left_ ]; 00355 Point3& right = controlPoints_[ walls_[ wall ].right_ ]; 00356 if(left(leftP, right, middle) > 0) { 00357 wallYaw = leftP.yawTowards(right); 00358 } 00359 else { 00360 wallYaw = middle.yawTowards(right); 00361 } 00362 } 00363 else if(alpha > .75f) { 00364 wall = walls_[ wall ].right_; 00365 Point3& middle = controlPoints_[ wall ]; 00366 Point3& leftP = controlPoints_[ walls_[ wall ].left_ ]; 00367 Point3& right = controlPoints_[ walls_[ wall ].right_ ]; 00368 wallYaw = leftP.yawTowards(right); 00369 if(left(leftP, right, middle) > 0) { 00370 wallYaw = leftP.yawTowards(right); 00371 } 00372 else { 00373 wallYaw = leftP.yawTowards(middle); 00374 } 00375 } 00376 else { 00377 Assert(alpha > 0); 00378 Point3& left = controlPoints_[ wall ]; 00379 Point3& right = controlPoints_[ walls_[ wall ].right_ ]; 00380 wallYaw = left.yawTowards(right); 00381 } 00382 00383 if(BrayT::abs(BrayT::sub(currentYaw, wallYaw)) > BrayT::DEG90) { 00384 wallYaw = BrayT::invert(wallYaw); 00385 } 00386 return wallYaw; 00387 } 00388 next = link; 00389 } 00390 } 00391 } 00392 00393 prev = via; 00394 via = next; 00395 } 00396 LogFatal("Couldn't find wall yaw"); 00397 return currentYaw; 00398 } 00399 00400 00401 short NavMesh 00402 ::findExit(const BoundingBox& wantedAreaBounds, Point3& out) const { 00403 out.reset(); 00404 for(int i = 0; i < exitCount_; ++i) { 00405 int tri = exits_[i].triangle_; 00406 int c1 = (exits_[i].side_ + 1) % 3; 00407 int c2 = (exits_[i].side_ + 2) % 3; 00408 Point3 &p1 = controlPoints_[ triangles_[ tri ].controlPoints_[ c1 ] ]; 00409 Point3 &p2 = controlPoints_[ triangles_[ tri ].controlPoints_[ c2 ] ]; 00410 if(wantedAreaBounds.isTouching(p1) && wantedAreaBounds.isTouching(p2)) { 00411 // Is outside on right side?? 00412 out.reset(); 00413 00414 out.add(p1); 00415 out.add(p2); 00416 00417 out.scale(0.99f / 2); 00418 Point3 c; 00419 wantedAreaBounds.center(c); 00420 c.scale(0.01f); 00421 out.add(c); 00422 return tri; 00423 } 00424 } 00425 00426 /* 00427 for(int i = 0; i < triangleCount_; ++i) { 00428 out.reset(); 00429 match = 0; 00430 for(int j = 0; j < 3; ++j) { 00431 if(wantedAreaBounds.isTouching(controlPoints_[ triangles_[i].controlPoints_[j] ])) { 00432 // Is outside on right side?? 00433 out.add(controlPoints_[ triangles_[ i ].controlPoints_[j] ]); 00434 ++match; 00435 } 00436 if(match >= 2) { 00437 out.scale(0.999f / (float)match); 00438 Point3 c; 00439 wantedAreaBounds.center(c); 00440 c.scale(0.001f); 00441 out.add(c); 00442 return i; 00443 } 00444 } 00445 } 00446 */ 00447 return -1; 00448 } 00449 00450 00451 coor_double_t NavMesh 00452 ::findNearest(const Point3& p, Point3& out) const { 00453 Point3 tmp; 00454 coor_double_t minDistSq = 0; 00455 00456 for(int i = 0; i < triangleCount_; ++i) { 00457 for(int j = 0; j < 3; ++j) { 00458 tmp.nearestPoint(controlPoints_[ triangles_[ i ].controlPoints_[j] ] 00459 , controlPoints_[ triangles_[ i ].controlPoints_[(j + 1) % 3] ], p); 00460 if(minDistSq == 0 || tmp.distanceSquared(p) < minDistSq) { 00461 minDistSq = tmp.distanceSquared(p); 00462 out.set(tmp); 00463 } 00464 } 00465 } 00466 return minDistSq; 00467 } 00468 00469 } 00470
Home Page | SagaEngine trunk (updated nightly) reference generated Sun Dec 2 20:06:02 2007 by Doxygen version 1.3.9.1.