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
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
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
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