NavMesh.hpp

Go to the documentation of this file.
00001 #ifndef basic_area_NavMesh_hpp
00002 #define basic_area_NavMesh_hpp
00003 
00004 #include "BasicPre.hpp"
00005 #include "util/vecmath/Point2.hpp"
00006 #include "util/vecmath/Point3.hpp"
00007 #include "util/bounds/BoundingBox.hpp"
00008 #include "sim/react/AreaEdge.hpp"
00009 
00010 
00011 namespace se_basic {
00012 
00013     /*
00014     bool doLinesIntersectXZ(const se_core::Point3& a0
00015                           , const se_core::Point3& a1
00016                           , const se_core::Point3& b0
00017                           , const se_core::Point3& b1
00018                           , se_core::Point2* out);
00019     */
00020 
00021     bool doLinesIntersectXZ(const se_core::Point3& a0
00022                           , const se_core::Point3& a1
00023                           , const se_core::Point3& b0
00024                           , const se_core::Point3& b1);
00025 
00026 
00027     struct Triangle {
00028         short id_;
00029         short controlPoints_[3];
00030         short linkTo_[3];
00031         short linkType_[3];
00032         short type_;
00033     };
00034 
00035 
00036     struct Wall {
00037         short left_;
00038         short right_;
00039     };
00040 
00041 
00042     struct Exit {
00043         short triangle_;
00044         short side_;
00045     };
00046 
00047 
00048     class _SeBasicExport Path {
00049     public:
00055         Path(int triangleCount, unsigned char* paths = 0)
00056                 : triangleCount_(triangleCount) , paths_(paths) {
00057             if(!paths_) {
00058                 // 4 values per char so size * size / 4
00059                 paths_ = new unsigned char[ dataSize() ];
00060             }
00061         }
00062 
00063 
00065         ~Path() {}
00066 
00067 
00079         void set(short from, short to, int neighbourIndex) {
00080             int index = (from * triangleCount_ + to) >> 2;
00081             int shift = ((from * triangleCount_ + to) & 0x3) * 2;
00082 
00083             // Reset existing value
00084             paths_[ index ] &= ~(0x3 << shift);
00085 
00086             // Set new value
00087             // assert(neighbourIndex & 0x3 == neighbourIndex)
00088             paths_[ index ] ^= (neighbourIndex << shift);
00089         }
00090 
00091 
00097         int path(short from, short to) const {
00098             int index = (from * triangleCount_ + to) >> 2;
00099             int shift = ((from * triangleCount_ + to) & 0x3) * 2;
00100 
00101             int ret = (paths_[ index ] >> shift) & 0x3;
00102             return ret;
00103         }
00104 
00105 
00110         int dataSize() {
00111             return (triangleCount_ * triangleCount_ + 3) >> 2;
00112         }
00113 
00114 
00122         unsigned char* data() {
00123             return paths_;
00124         }
00125 
00126         void lineIntersect(const se_core::Point2& p0
00127                            , const se_core::Point2& p1
00128                            , const se_core::Point2& p2
00129                            , const se_core::Point2& p3
00130                            , se_core::Point2& out) {
00131             // this function computes the intersection of the sent lines
00132             // and returns the intersection point, note that the function assumes
00133             // the lines intersect. the function can handle vertical as well
00134             // as horizontal lines. note the function isn't very clever, it simply
00135             //applies the math, but we don't need speed since this is a
00136             //pre-processing step
00137 
00138             // b1 and b2 unused
00139             float a1, c1, // constants of linear equations
00140                 a2, c2,
00141                 det_inv,  // the inverse of the determinant of the coefficie matrix
00142                 m1, m2;    // the slopes of each line
00143 
00144             // compute slopes, note the cludge for infinity, however, this will
00145             // be close enough
00146 
00147             if ((p1.x_ - p0.x_) != 0)
00148                 m1 = (p1.y_ - p0.y_) / (p1.x_ - p0.x_);
00149             else
00150                 m1 = (float)1e+10;   // close enough to infinity
00151 
00152             if ((p3.x_ - p2.x_) != 0)
00153                 m2 = (p3.y_ - p2.y_) / (p3.x_ - p2.x_);
00154             else
00155                 m2 = (float)1e+10;   // close enough to infinity
00156 
00157             // compute constants
00158             a1 = m1;
00159             a2 = m2;
00160 
00161             c1 = (p0.y_ - m1 * p0.x_);
00162             c2 = (p2.y_ - m2 * p2.x_);
00163 
00164             // compute the inverse of the determinate
00165             det_inv = 1 / (a2 - a1);
00166 
00167             // use Kramers rule to compute xi and yi
00168             out.x_ = ((c1 - c2) * det_inv);
00169             //out.y_ = ((a2 * c1 - a1 * c2) * det_inv);
00170             out.y_ = m1 * ( (c2 - c1) / (m1 - m2) ) + c1;
00171         } // end Intersect_Lines        
00172         
00173 
00174 
00175 
00176     private:
00177         int triangleCount_;
00178         unsigned char* paths_;
00179     };
00180 
00181 
00182     class _SeBasicExport NavMesh {
00183     public:
00184         NavMesh(short controlPointCount, short triangleCount)
00185                 :  controlPointCount_(controlPointCount)
00186                  , triangleCount_(triangleCount)
00187                  , exitCount_(0), exits_(0), doDestroy_(true) {
00188             controlPoints_ = new se_core::Point3[ controlPointCount_ ];
00189             walls_ = new Wall[ controlPointCount_ ];
00190             triangles_ = new Triangle[ triangleCount_ ];
00191             paths_ = new Path(triangleCount_);
00192         }
00193 
00194 
00195         NavMesh(const void* data) : doDestroy_(false) {
00196             union {
00197                 const void* v;
00198                 //void* v;
00199                 unsigned char* ch;
00200                 short *sh;
00201                 se_core::Point3* cp;
00202                 Triangle* tri;
00203                 Wall* wall;
00204                 Exit* exit;
00205             } offset;
00206 
00207             offset.v = data;
00208 
00209             controlPointCount_ = *(offset.sh++);
00210             triangleCount_ = *(offset.sh++);
00211             exitCount_ = *(offset.sh++);
00212 
00213             controlPoints_ = offset.cp;
00214             offset.cp += controlPointCount_;
00215 
00216             walls_ = offset.wall;
00217             offset.wall += controlPointCount_;
00218 
00219             triangles_ = offset.tri;
00220             offset.tri += triangleCount_;
00221 
00222             exits_ = offset.exit;
00223             offset.exit += exitCount_;
00224 
00225             paths_ = new Path(triangleCount_, offset.ch);
00226             offset.ch += paths_->dataSize();
00227         }
00228 
00229 
00230         ~NavMesh() {
00231             delete paths_;
00232             if(doDestroy_) {
00233                 delete[] triangles_;
00234                 delete[] walls_;
00235                 delete[] controlPoints_;
00236             }
00237         }
00238 
00239 
00240         void walls(se_core::AreaEdge& areaEdge) const;
00241         int isInLineOfSight(const se_core::Pos& from, const se_core::Pos& to) const;
00242         int isInLineOfSight(const se_core::Point3& from, short fromIndex, const se_core::Point3& to, short toIndex) const;
00243         int farthestLineOfSightXZ(int fromIndex, const se_core::Point3& from, const se_core::Point3& to, short toIndex, se_core::Point2& dest) const;
00244         bray_t slideAngle(const se_core::Point3& from, short fromIndex, const se_core::Point3& to) const;
00245         bray_t wallAngle(const se_core::Point3& from, short fromIndex, const se_core::Point3& to) const;
00246         bool doesTouchVoid(const se_core::Point3& p, short pIndex, const coor_t radius) const;
00247 
00253         short path(short from, short to) const {
00254             int neighbourIndex = paths_->path(from, to);
00255             short via = triangles_[ from ].linkTo_[ neighbourIndex ];
00256             return via;
00257         }
00258 
00259 
00260         void center(short tri, se_core::Point3& out) const {
00261             const se_core::Point3& c1 = controlPoints_[ triangles_[tri].controlPoints_[0] ];
00262             const se_core::Point3& c2 = controlPoints_[ triangles_[tri].controlPoints_[1] ];
00263             const se_core::Point3& c3 = controlPoints_[ triangles_[tri].controlPoints_[2] ];
00264 
00265             out.x_ = (c1.x_ + c2.x_ + c3.x_) / 3.0f;
00266             out.y_ = (c1.y_ + c2.y_ + c3.y_) / 3.0f;
00267             out.z_ = (c1.z_ + c2.z_ + c3.z_) / 3.0f;
00268         }
00269 
00270 
00271         short type(short triangle) {
00272             return triangles_[ triangle ].type_;
00273         }
00274 
00275         void barycentric(const se_core::Point2& q, const se_core::Point3& c1, const se_core::Point3& c2, const se_core::Point3& c3, se_core::Tuple3& out) const {
00276             coor_t b0 =  (c2.x_ - c1.x_) * (c3.z_ - c1.z_) - (c3.x_ - c1.x_) * (c2.z_ - c1.z_);
00277             out.x_ = ((c2.x_ - q.x_) * (c3.z_ - q.y_) - (c3.x_ - q.x_) * (c2.z_ - q.y_)) / b0;
00278             out.y_ = ((c3.x_ - q.x_) * (c1.z_ - q.y_) - (c1.x_ - q.x_) * (c3.z_ - q.y_)) / b0;
00279             out.z_ = 1 - out.x_ - out.y_;
00280             //out.z = ((c1.x_ - q.x_) * (c2.z_ - q.y_) - (c2.x_ - q.x_) * (c1.z_ - q.y_)) / b0;
00281         }
00282 
00283 
00284         void barycentric(short tri, const se_core::Point2& q, se_core::Tuple3& out) const {
00285             const se_core::Point3& c1 = controlPoints_[ triangles_[tri].controlPoints_[0] ];
00286             const se_core::Point3& c2 = controlPoints_[ triangles_[tri].controlPoints_[1] ];
00287             const se_core::Point3& c3 = controlPoints_[ triangles_[tri].controlPoints_[2] ];
00288 
00289             coor_t b0 =  (c2.x_ - c1.x_) * (c3.z_ - c1.z_) - (c3.x_ - c1.x_) * (c2.z_ - c1.z_);
00290             out.x_ = ((c2.x_ - q.x_) * (c3.z_ - q.y_) - (c3.x_ - q.x_) * (c2.z_ - q.y_)) / b0;
00291             out.y_ = ((c3.x_ - q.x_) * (c1.z_ - q.y_) - (c1.x_ - q.x_) * (c3.z_ - q.y_)) / b0;
00292             //out.z = ((c1.x_ - q.x_) * (c2.z_ - q.y_) - (c2.x_ - q.x_) * (c1.z_ - q.y_)) / b0;
00293             out.z_ = 1 - out.x_ - out.y_;
00294         }
00295 
00296 
00297         coor_t height(short tri, const se_core::Tuple3& barycentric) const {
00298             const se_core::Point3& c1 = controlPoints_[ triangles_[tri].controlPoints_[0] ];
00299             const se_core::Point3& c2 = controlPoints_[ triangles_[tri].controlPoints_[1] ];
00300             const se_core::Point3& c3 = controlPoints_[ triangles_[tri].controlPoints_[2] ];
00301 
00302             coor_t h = barycentric.x_ * c1.y_
00303                 + barycentric.y_ * c2.y_
00304                 + barycentric.z_ * c3.y_;
00305 
00306             return h;
00307         }
00308 
00309 
00310         bool isInsideTriangle(se_core::Tuple3& barycentric) const {
00311             return (barycentric.x_ >= 0 && barycentric.y_ >= 0 && barycentric.z_ >= 0);
00312         }
00313 
00314 
00316         bool isInsideTriangle(se_core::Point2& q, se_core::Point3& c1, se_core::Point3& c2, se_core::Point3& c3) const {
00317             se_core::Tuple3 b;
00318             barycentric(q, c1, c2, c3, b);
00319             return isInsideTriangle(b);
00320         }
00321 
00322 
00324         bool isInsideTriangle(se_core::Point2& q, se_core::Point3* corners) const {
00325             using namespace se_core;
00326 
00327             static int index1[] = { 1, 2, 0 };
00328             static int index2[] = { 2, 0, 1 };
00329 
00330             for(int i = 0; i < 3; ++i) {
00331                 Point3& c0 = corners[ i ];
00332                 Point3& c1 = corners[ index1[ i ] ];
00333                 Point3& c2 = corners[ index2[ i ] ];
00334 
00335                 Vector2 n(-(c1.z_ - c0.z_), c1.x_ - c0.x_);
00336                 Vector2 F(c2.x_ - c0.x_, c2.z_ - c0.z_);
00337                 Vector2 G(q.x_ - c0.x_, q.y_ - c0.z_);
00338 
00339                 if(n.dot(F) * n.dot(G) < 0)
00340                     return false;
00341             }
00342             return true;
00343         }
00344 
00345 
00348         short find(const se_core::Point2& q) const {
00349             // TODO: Should organize triangles in a tree or grid structure
00350             se_core::Tuple3 b;
00351             for(int i = 0; i < triangleCount_; ++i) {
00352                 barycentric(i, q, b);
00353                 if(isInsideTriangle(b)) {
00354                     return i;
00355                 }
00356             }
00357             //LogDetail(q.x_ << ", " << q.y_);
00358             return -1;
00359         }
00360 
00361 
00364         short find(short from, const se_core::Point2& q) const {
00365             Assert(from >= 0);
00366             short count = 0;
00367 
00368             se_core::Tuple3 b;
00369 
00370             short tri = from;
00371             barycentric(tri, q, b);
00372             while(!isInsideTriangle(b)) {
00373                 if(++count > 20) {
00374                     return find(q);
00375                 }
00376                 short n = 0;
00377                 coor_t smallest = b.x_;
00378 
00379                 if(b.y_ < smallest) {
00380                     n = 1;
00381                     smallest = b.y_;
00382                 }
00383                 if(b.z_ < smallest) {
00384                     n = 2;
00385                     smallest = b.z_;
00386                 }
00387 
00388                 //LogDetail(tri << ": " << n << " (" << b.x_ << ", " << b.y_ << ", " << b.z_ << ") ");
00389                 //for(int c = 0; c < 3; ++c) {
00390                 //  int i = triangles_[ tri ].controlPoints_[ c ];
00391                     //LogDetail(" " << i << ": " << controlPoints_[ i ].x_ << ", " << controlPoints_[ i ].z_ );
00392                 //}
00393 
00394                 //LogDetail(" Link: " << triangles_[tri].linkTo_[0] << ", " << triangles_[tri].linkTo_[1] << ", " << triangles_[tri].linkTo_[2]);
00395                 tri = triangles_[tri].linkTo_[n];
00396                 if(tri < 0) {
00397                     return -1;
00398                 }
00399                 barycentric(tri, q, b);
00400             }
00401             return tri;
00402         }
00403 
00404         short findExit(const se_core::BoundingBox& bounds, se_core::Point3& out) const;
00405         coor_t findNearest(const se_core::Point3& p, se_core::Point3& out) const;
00406 
00407     protected:
00408         bool doDestroy_;
00409         short controlPointCount_;
00410         short triangleCount_;
00411         short exitCount_;
00412 
00413         se_core::Point3* controlPoints_;
00414         Triangle* triangles_;
00415         Path* paths_;
00416         Wall* walls_;
00417         Exit* exits_;
00418     };
00419 
00420 }
00421 
00422 
00423 #endif

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