NavMesh.cpp

Go to the documentation of this file.
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.

SourceForge.net Logo