AI_NavigationMesh.h

Go to the documentation of this file.
00001 #ifndef AI_NAVIGATION_MESH_H
00002 #define AI_NAVIGATION_MESH_H
00003 
00004 #include "AI_Global.h"
00005 #include "spatialdb/AI_SDB_VisitorBase.h"
00006 #include "spatialdb/AI_SDB_SpatialAABBTree.h"
00007 #include "./math/AI_Line.h"
00008 #include "AI_AStar.h"
00009 
00084 class AI_NavigationMesh
00085 {
00086 public:
00087     class Vertex;
00088     class Triangle;
00089     class Edge;
00090     class Corner;
00091     class Session;
00092 
00093 //*** Embedded
00094 private:
00101     struct Bundle {
00103         Triangle *ptr_tri;
00105         Edge *ptr_edge;
00106 
00107         Bundle ();
00108         Bundle (Triangle *ptr_tri, Edge *ptr_edge);
00109     };
00110 
00112     typedef AI_Array<Bundle> BundleArray;
00114     typedef BundleArray::iterator BundleArrayIt;
00115 
00117     enum INTERSECTION {NO_CROSS, CROSS, CROSS_BORDER};
00118 
00119 public:
00121     typedef AI_Array<Vertex*> VertexArray;
00123     typedef VertexArray::iterator VertexArrayIt;
00125     typedef AI_Array<Edge*> EdgeArray;
00127     typedef EdgeArray::iterator EdgeArrayIt;
00129     typedef AI_Array<Triangle*> TriangleArray;
00131     typedef TriangleArray::iterator TriangleArrayIt;
00133     typedef AI_Array<Corner*> CornerArray;
00135     typedef CornerArray::iterator CornerArrayIt;
00136 
00137 
00141     class Vertex {
00142         friend AI_NavigationMesh;
00143         friend Session;
00144 
00145     protected:
00147         AI_Vector3 m_v_coord;
00149         AI_Vector2 m_v_coord2d;
00151         Corner *m_ptr_corner;
00152 
00153     public:
00154         Vertex();
00155         const AI_Vector3 &getCoord( void ) const;
00156         Corner *getCorner( void ) const;
00157     };
00158 
00159 
00163     class Triangle {
00164         friend AI_NavigationMesh;
00165 
00166     protected:
00168         Vertex *m_ptr_vertices[3];
00170         Edge *m_ptr_edges[3];
00172         CornerArray m_arr_pvs_corners;
00173 
00174     public:
00175         Triangle ();
00176         bool addEdge( Edge *ptr_edge );
00177         void addPVS( Corner *ptr_corner );
00178         Edge *getEdgeOposedTo( const Vertex *ptr_vertex );
00179         Edge *getEdgeSharedVertex( const Vertex *ptr_vertex, const Edge *ptr_edge );
00180         void getOtherEdges( const Edge *ptr_edge, Edge *ptr_edges[] );
00181     };
00182 
00183 
00187     class Edge {
00188         friend AI_NavigationMesh;
00189         friend Triangle;
00190 
00191     protected:
00193         AI_Line2 m_line2d;
00195         Triangle *m_ptr_triangles[2];
00197         Vertex *m_ptr_vertex1;
00199         Vertex *m_ptr_vertex2;
00201         AI_Vector2 m_v_normal;
00203         void *m_ptr_user_data;
00204 
00205     public:
00206         Edge ();
00207         bool isBorder( void ) const;
00208         bool isVertexContained( const Vertex *ptr_vertex ) const;
00209         Triangle *getOppositeTriangle( const Triangle *ptr_triangle ) const;
00210     };
00211 
00212 
00216     class Corner {
00217         friend AI_NavigationMesh;
00218         friend Session;
00219 
00220     protected:
00222         Vertex *m_ptr_vertex;
00224         Edge *m_ptr_edges[2];
00227         AI_Vector2 m_v_shift;
00229         float m_f_width;
00231         bool m_b_concave;
00233         CornerArray m_arr_visible_corners;
00235         AI_AStar::Node *m_ptr_astar_node;
00236 
00237     protected:
00238         void addVisibleConcaveCorner( Corner *ptr_corner );
00239         void adjustWidth(float f);
00240 
00241     public:
00242         Corner();
00243         Vertex *getVertex( void );
00244     };
00245 
00246 
00252     class PointVisitor : public AI_SDB_VisibilityVisitor {
00253     private:
00255         AI_SDB_VisibilityVisitor::VisibleElements &m_visarray;
00256 
00257     public:
00258         PointVisitor(const AI_Vector3 &v_position, VisibleElements &foundarray);
00259         virtual AI_SDB_VisitorFlags VisibilityTest(const AI_BBox &testbox, AI_SDB_VisitorFlags flags);
00260         virtual AI_SDB_VisitorFlags VisibilityTest(const AI_Sphere &testsphere, AI_SDB_VisitorFlags flags);
00261         virtual void Visit(AI_SDB_SpatialElement *visitee);
00262         AI_SDB_SpatialElement *getNearestElement(void);
00263     };
00264 
00265 
00269     class Informator : public AI_AStar::Informator {
00270     protected:
00272         AI_NavigationMesh *m_ptr_navmesh;
00273 
00274     public:
00275         void setNavigationMesh ( AI_NavigationMesh *ptr_navmesh );
00276         virtual float getHeuristic ( AI_AStar::Node *ptr_node1, AI_AStar::Node *ptr_node2 );
00277     };
00278 
00279     enum { 
00281         INVALID_INDEX = 0xffff 
00282     };
00283 
00284 
00292     class Session {
00293         friend AI_NavigationMesh;
00294 
00295     protected:
00297         Corner m_corner_start;
00299         Corner m_corner_final;
00301         Vertex m_vertex_start;
00303         Vertex m_vertex_final;
00305         AI_AStar::Session m_session_astar;
00307         float m_f_width;
00309         bool m_b_direct_way;
00310 
00311     public:
00312         Session();
00313         void setMission(const AI_Vector3 &v_start, const AI_Vector3 &v_final);
00314         void setWidth(const float f_width);
00315         void getWay(AI_Array<AI_Vector3> &arr_way);
00316 
00317     protected:
00318         void reset( void );
00319         void resetCorner( Corner &corner );
00320     };
00321 
00322 //*** Attributes
00323 protected:
00325     VertexArray m_arr_vertices;
00327     TriangleArray m_arr_triangles;
00329     EdgeArray m_arr_edges;
00331     CornerArray m_arr_corners;
00333     AI_SDB_SpatialAABBTree m_spatial_tree;
00335     AI_SDB_VisibilityVisitor::VisibleElements m_spatial_elements;
00337     AI_SDB_VisibilityVisitor::VisibleElements m_visible_elements;
00339     AI_AStar m_astar;
00341     Informator m_astar_informator;
00343     bool m_b_preprocessed;
00345     bool m_b_wide_agents;
00346 
00347 //*** Methods
00348 private:
00349     bool findCorners(void);
00350     void findVisibleConcaveCorners(void);
00351     void getBundles( AI_Array< BundleArray > &arr_vert2edge );
00352     void adjustCornersWidth( AI_Array< EdgeArray > &arr_corner2edges );
00353     void buildVisibilityGraph(void);
00354     void buildSpatialTree(void);
00355     void updateLinkWidths(void);
00356     bool isCCW(const AI_Vector2 &v_1, const AI_Vector2 &v_2, const AI_Vector2 &v_3) const;
00357     float getHalfLinkMinWidth(const Corner *ptr_corner1, const Corner *ptr_corner2) const;
00358     float getLinkMaxWidth(const Corner *ptr_corner1, const Corner *ptr_corner2) const;
00359     float getStaticLinkMaxWidth(const Corner *ptr_corner1, const Corner *ptr_corner2) const;
00360     float getShiftToCollinearSimple(const Edge *ptr_edge, const Corner *ptr_corner) const;
00361     float getShiftToCollinear(const Corner *ptr_corner_a, const Corner *ptr_corner_b, const Corner *ptr_corner_c) const;
00362     float getShiftToCollinearStatic(const Corner *ptr_corner1, const Corner *ptr_corner2, const Corner *ptr_corner3) const;
00363     bool isCornerVisible(const AI_Line2 &l_ray, const Vertex *ptr_v_final, Triangle *ptr_tri_in, Edge *ptr_edges[], int i_num_edges) const;
00364     bool isPointVisible (const AI_Line2 &l_ray, const Triangle *ptr_tri_final, Triangle *ptr_tri_in, Edge *ptr_edges[], int i_num_edges) const;
00365     bool isMeaningfulLink( const Corner *ptr_corner_start, const Corner *ptr_corner_final ) const;
00366     bool isMeaningfulBend( const Vertex *ptr_v_start, const Corner *ptr_corner, const Vertex *ptr_v_end ) const;
00367     void findTemporaryVisibleCorners( Corner *ptr_corner_start, Triangle *ptr_tri );
00368     void addTemporarySubgraph( Corner *ptr_corner_start, AI_AStar::Session &session );
00369     ai_index addCorner( Edge *ptr_edge1, Edge *ptr_edge2 );
00370     Corner *getCorner( ai_index i ) const;
00371     int getCornersNumber(void) const;
00372     void addAStarLink (Corner *ptr_corner1, Corner *ptr_corner2);
00373     float getCornerWidth(const Corner *ptr_corner, const Edge *ptr_edge) const;
00374     float getLinkWidth(const Corner *ptr_corner_a, const Corner *ptr_corner_b, const Corner *ptr_corner_c) const;
00375     float getStaticLinkWidth(const Corner *ptr_corner_a, const Corner *ptr_corner_b, const Corner *ptr_corner_c) const;
00376     bool isOnShiftedEdge(const Corner *ptr_corner_a, const Corner *ptr_corner_b, const Corner *ptr_corner_c, const float f_k) const;
00377 
00378 public:
00379     AI_NavigationMesh(void);
00380     ~AI_NavigationMesh(void);
00381 
00382     ai_index addVertex( const AI_Vector3 &v_vertex );
00383     ai_index addTriangle( ai_index i_v1, ai_index i_v2, ai_index i_v3 );
00384     ai_index addEdge( ai_index i_t1, ai_index i_t2, ai_index i_v1, ai_index i_v2 );
00385     Vertex *getVertex( ai_index i ) const;
00386     Triangle *getTriangle( ai_index i ) const;
00387     Edge *getEdge( ai_index i ) const;
00388     bool preprocess( void );
00389     bool findWay( Session &session );
00390     bool testVisibility( const AI_Vector3 &v_first, const AI_Vector3 &v_second );
00391     const bool testBorderIntersection( const AI_Vector3 &v_first, const AI_Vector3 &v_second, float &f_distance );
00392     void clear( void );
00393     const AI_AStar &getVisibilityGraph( void ) const;
00394     void setWideAgents( bool b_support = true );
00395     bool isWideAgents( void ) const;
00396     bool isPreprocessed( void ) const;
00397     Triangle *identifyTriangle( const AI_Vector3 &v_coord );
00398     bool getNearestPosition( const AI_Vector3 &v_position,float width,bool cylinder,AI_Vector3 &v_nearest_position);
00399 };
00400 
00401 
00404 inline
00405 AI_NavigationMesh::Bundle::Bundle()
00406 {
00407 }
00408 
00409 
00412 inline
00413 AI_NavigationMesh::Bundle::Bundle (Triangle *ptr_tri, Edge *ptr_edge) : 
00414     ptr_tri(ptr_tri), 
00415     ptr_edge(ptr_edge)
00416 {
00417 }
00418 
00419 
00422 inline
00423 AI_NavigationMesh::Vertex::Vertex() : 
00424     m_ptr_corner(NULL)
00425 {
00426 }
00427 
00428 
00431 inline
00432 const AI_Vector3 &AI_NavigationMesh::Vertex::getCoord( void ) const
00433 {
00434     return m_v_coord;
00435 }
00436 
00437 
00441 inline
00442 AI_NavigationMesh::Corner *AI_NavigationMesh::Vertex::getCorner( void ) const
00443 {
00444     return m_ptr_corner;
00445 }
00446 
00447 
00450 inline
00451 AI_NavigationMesh::Triangle::Triangle ()
00452 {
00453     memset (m_ptr_edges, NULL, 3*sizeof(void*));
00454     memset (m_ptr_vertices, NULL, 3*sizeof(void*));
00455 }
00456 
00457 
00460 inline
00461 bool AI_NavigationMesh::Triangle::addEdge( Edge *ptr_edge )
00462 {
00463     int i = 0;
00464     while (i<3)
00465     {
00466         if ( m_ptr_edges[i]==NULL )
00467         {   m_ptr_edges[i]=ptr_edge;  
00468             return true;    
00469         }
00470 
00471         i++;
00472     }
00473 
00474     ai_log (AI_STR_TOO_MANY_TRI_EDGES);
00475     return false;
00476 }
00477 
00478 
00481 inline
00482 void AI_NavigationMesh::Triangle::addPVS( Corner *ptr_corner )
00483 {
00484     for (CornerArrayIt it=m_arr_pvs_corners.Begin(); it!=m_arr_pvs_corners.End(); it++)
00485     {
00486         if (*it==ptr_corner)
00487         {
00488             return;
00489         }
00490     }
00491 
00492     m_arr_pvs_corners.PushBack( ptr_corner );
00493 }
00494 
00495 
00498 inline
00499 AI_NavigationMesh::Edge *AI_NavigationMesh::Triangle::getEdgeOposedTo( const Vertex *ptr_vertex )
00500 {
00501     for (int i=0; i<3; i++)
00502     {
00503         Edge *ptr_edge = m_ptr_edges[i];
00504 
00505         if ( !(ptr_edge->m_ptr_vertex1==ptr_vertex || ptr_edge->m_ptr_vertex2==ptr_vertex) )
00506             return ptr_edge;
00507     }
00508 
00509     return NULL;
00510 }
00511 
00512 
00515 inline
00516 AI_NavigationMesh::Edge *AI_NavigationMesh::Triangle::getEdgeSharedVertex( const Vertex *ptr_vertex, const Edge *ptr_edge )
00517 {
00518     for (int i=0; i<3; i++)
00519     {
00520         Edge *ptr_edge_new = m_ptr_edges[i];
00521 
00522         if ( ptr_edge!=ptr_edge_new && (ptr_edge_new->m_ptr_vertex1==ptr_vertex || ptr_edge_new->m_ptr_vertex2==ptr_vertex) )
00523             return ptr_edge_new;
00524     }
00525 
00526     return NULL;
00527 }
00528 
00529 
00532 inline
00533 void AI_NavigationMesh::Triangle::getOtherEdges( const Edge *ptr_edge, Edge *ptr_edges[] )
00534 {
00535     int i2=0;
00536     for (int i=0; i<3; i++)
00537     {
00538         Edge *ptr_edge_new = m_ptr_edges[i];
00539 
00540         if ( ptr_edge!=ptr_edge_new )
00541         {   ptr_edges[i2] = ptr_edge_new;
00542             i2++;
00543         }
00544     }
00545 }
00546 
00547 
00550 inline
00551 AI_NavigationMesh::Edge::Edge () :
00552     m_ptr_vertex1(NULL),
00553     m_ptr_vertex2(NULL),
00554     m_ptr_user_data(NULL)
00555 {
00556     memset(m_ptr_triangles, 0, 2*sizeof(void*));
00557 }
00558 
00559 
00562 inline
00563 bool AI_NavigationMesh::Edge::isBorder ( void ) const
00564 {
00565     if (m_ptr_triangles[0]==NULL || m_ptr_triangles[1]==NULL)
00566         return true;
00567     return false;
00568 }
00569 
00570 
00573 inline
00574 bool AI_NavigationMesh::Edge::isVertexContained( const Vertex *ptr_vertex ) const
00575 {
00576     if (ptr_vertex==m_ptr_vertex1 || ptr_vertex==m_ptr_vertex2)
00577         return true;
00578     return false;
00579 }
00580 
00581 
00584 inline
00585 AI_NavigationMesh::Triangle *AI_NavigationMesh::Edge::getOppositeTriangle( const Triangle *ptr_triangle ) const
00586 {
00587     if (m_ptr_triangles[0]==ptr_triangle)   
00588         return m_ptr_triangles[1];
00589     else
00590         return m_ptr_triangles[0];
00591 }
00592 
00593 
00596 inline
00597 AI_NavigationMesh::Corner::Corner() : 
00598     m_f_width(AI_INFINITY), 
00599     m_ptr_astar_node(NULL), 
00600     m_b_concave(false)
00601 {
00602 }
00603 
00604 
00607 inline
00608 void AI_NavigationMesh::Corner::addVisibleConcaveCorner( Corner *ptr_corner )
00609 {
00610     CornerArrayIt it;
00611     for (it=m_arr_visible_corners.Begin(); it!=m_arr_visible_corners.End(); it++)
00612     {
00613         if (*it==ptr_corner)
00614         {
00615             return;
00616         }
00617     }
00618 
00619     m_arr_visible_corners.PushBack( ptr_corner );
00620 }
00621 
00622 
00625 inline
00626 void AI_NavigationMesh::Corner::adjustWidth(float f_width)
00627 { 
00628     if (f_width < m_f_width) 
00629     {
00630         m_f_width = f_width; 
00631     }
00632 }
00633 
00634 
00637 inline
00638 AI_NavigationMesh::Vertex *AI_NavigationMesh::Corner::getVertex( void )
00639 {
00640     return m_ptr_vertex;
00641 }
00642 
00643 
00646 inline
00647 void AI_NavigationMesh::Informator::setNavigationMesh( AI_NavigationMesh *ptr_navmesh )
00648 {
00649     m_ptr_navmesh = ptr_navmesh;
00650 }
00651 
00652 
00655 inline
00656 float AI_NavigationMesh::Informator::getHeuristic ( AI_AStar::Node *ptr_node1, AI_AStar::Node *ptr_node2 )
00657 {
00658     Vertex *ptr_vertex1 = ((Corner*)ptr_node1->getUserData())->getVertex();
00659     Vertex *ptr_vertex2 = ((Corner*)ptr_node2->getUserData())->getVertex();
00660 
00661     return (ptr_vertex1->getCoord() - ptr_vertex2->getCoord()).len();
00662 }
00663 
00664 
00667 inline
00668 AI_NavigationMesh::Session::Session() :
00669     m_f_width(0),
00670     m_b_direct_way(false)
00671 {
00672     m_corner_start.m_ptr_vertex = &m_vertex_start;
00673     m_corner_final.m_ptr_vertex = &m_vertex_final;
00674 }
00675 
00676 
00679 inline
00680 void AI_NavigationMesh::Session::setMission(const AI_Vector3 &v_start, const AI_Vector3 &v_final)
00681 {
00682     m_vertex_start.m_v_coord = v_start;
00683     m_vertex_final.m_v_coord = v_final;
00684 }
00685 
00686 
00689 inline
00690 void AI_NavigationMesh::Session::setWidth(const float f_width)
00691 {
00692     m_f_width = f_width;
00693 }
00694 
00695 
00698 inline
00699 void AI_NavigationMesh::Session::reset( void )
00700 {
00701     resetCorner( m_corner_start );
00702     resetCorner( m_corner_final );
00703 
00704     m_b_direct_way = false;
00705 }
00706 
00707 
00710 inline
00711 void AI_NavigationMesh::Session::resetCorner( Corner &corner )
00712 {
00713     corner.m_ptr_astar_node = NULL;
00714     corner.m_arr_visible_corners.Reset();
00715 
00716     corner.m_ptr_vertex->m_v_coord2d.x = corner.m_ptr_vertex->m_v_coord.x; 
00717     corner.m_ptr_vertex->m_v_coord2d.y = corner.m_ptr_vertex->m_v_coord.z;
00718 }
00719 
00720 
00723 inline
00724 AI_NavigationMesh::Vertex *AI_NavigationMesh::getVertex( ai_index i ) const
00725 {
00726     return m_arr_vertices[i];
00727 }
00728 
00729 
00732 inline
00733 AI_NavigationMesh::Triangle *AI_NavigationMesh::getTriangle( ai_index i ) const
00734 {
00735     return m_arr_triangles[i];
00736 }
00737 
00738 
00741 inline
00742 AI_NavigationMesh::Edge *AI_NavigationMesh::getEdge( ai_index i ) const
00743 {
00744     return m_arr_edges[i];
00745 }
00746 
00747 
00750 inline
00751 AI_NavigationMesh::Corner *AI_NavigationMesh::getCorner( ai_index i ) const
00752 {
00753     return m_arr_corners[i];
00754 }
00755 
00756 
00759 inline
00760 int AI_NavigationMesh::getCornersNumber( void ) const
00761 {
00762     return m_arr_corners.Size();
00763 }
00764 
00765 
00768 inline
00769 AI_NavigationMesh::PointVisitor::PointVisitor(const AI_Vector3 &v_position, VisibleElements &foundarray) :
00770     AI_SDB_VisibilityVisitor(v_position),
00771     m_visarray(foundarray)
00772 {
00773 }
00774 
00775 
00778 inline
00779 AI_SDB_VisitorFlags AI_NavigationMesh::PointVisitor::VisibilityTest(const AI_BBox &testbox, AI_SDB_VisitorFlags flags)
00780 {
00781     AI_Vector3 v_pos = GetViewPoint();
00782 
00783     if ((testbox.vmin.x < v_pos.x) && (testbox.vmax.x >= v_pos.x) &&
00784         (testbox.vmin.z < v_pos.z) && (testbox.vmax.z >= v_pos.z))
00785     {
00786         return AI_SDB_VisitorFlags(true,false);
00787     }
00788 
00789     return AI_SDB_VisitorFlags(false,true);
00790 }
00791 
00792 
00797 inline
00798 AI_SDB_VisitorFlags AI_NavigationMesh::PointVisitor::VisibilityTest(const AI_Sphere &testsphere, AI_SDB_VisitorFlags flags)
00799 {
00800     return flags;
00801 }
00802 
00803 
00806 inline
00807 void AI_NavigationMesh::PointVisitor::Visit(AI_SDB_SpatialElement *visitee)
00808 {
00809     m_visarray.Append( visitee );
00810 }
00811 
00812 
00815 inline
00816 const AI_AStar &AI_NavigationMesh::getVisibilityGraph( void ) const
00817 {
00818     return m_astar;
00819 }
00820 
00821 
00824 inline
00825 void AI_NavigationMesh::setWideAgents( bool b_support )
00826 {
00827     m_b_wide_agents = b_support;
00828 }
00829 
00830 
00833 inline
00834 bool AI_NavigationMesh::isWideAgents( void ) const
00835 {
00836     return m_b_wide_agents;
00837 }
00838 
00839 
00842 inline
00843 bool AI_NavigationMesh::isPreprocessed( void ) const
00844 {
00845     return m_b_preprocessed;
00846 }
00847 
00848 
00849 #endif