NavMeshArea.cpp

Go to the documentation of this file.
00001 #include "BasicPre.hpp"
00002 #include "NavMeshArea.hpp"
00003 #include "NavMesh.hpp"
00004 #include "sim/pos/PosComponent.hpp"
00005 #include "sim/react/CollisionAreaComponent.hpp"
00006 
00007 using namespace se_core;
00008 
00009 namespace se_basic {
00010     NavMeshArea
00011     ::NavMeshArea(Composite* owner, const ComponentFactory* factory, coor_tile_t w, coor_tile_t h, const NavMesh* navMesh)
00012             : Area (owner, factory, w, h), navMesh_(navMesh) {
00013         //LogDetail(owner->name() << " area created with size " << w << ", " << h);
00014         navMesh_->walls(CollisionAreaComponent::Ptr(*this)->areaEdge());
00015     }
00016 
00017 
00018     NavMeshArea
00019     ::~NavMeshArea() {
00020         //LogDetail(owner()->name() << " area destroyed.");
00021     }
00022 
00023 
00024     bool NavMeshArea
00025     ::isNeighbour(const Area& area) const {
00026         if(!Area::isNeighbour(area))
00027             return false;
00028         
00029         PosComponent::Ptr aPos(area);
00030         Point3 p(aPos->pos().worldCoor());
00031         p.sub(posComponent_->pos().worldCoor());
00032         BoundingBox toArea(p, aPos->pos().bounds_);
00033 
00034         Point3 tmp;
00035         short index = navMesh_->findExit(toArea, tmp);
00036 
00037         return (index >= 0);
00038     }
00039 
00040 
00041     coor_t NavMeshArea
00042     ::groundHeight(const Point3& coor, short index) const {
00043         static Tuple3 b;
00044         Point2 p(coor.x_, coor.z_);
00045         short tri = (index >= 0) ? index : navMesh_->find(p);
00046         AssertFatal(tri >= 0, "Make sure coor is legal before calling groundHeight");
00047         if(tri < 0)
00048             return 0;
00049         navMesh_->barycentric(tri, p, b);
00050         return navMesh_->height(tri, b);
00051     }
00052 
00053 
00054     short NavMeshArea
00055     ::index(const se_core::Point3& worldCoor, short oldIndex) const {
00056         //Assert(nextPosition_.face().isIdentity() 
00057         //     && "Rotation of area not supported");
00058 
00059         Point2 p(worldCoor.x_ - posComponent_->nextPos().world_.coor_.x_
00060                  , worldCoor.z_ - posComponent_->nextPos().world_.coor_.z_);
00061 
00062         //LogDetail(p.x_ << ", " << p.y_);
00063 
00064         short index;
00065         if(oldIndex >= 0) {
00066             index = navMesh_->find(oldIndex, p);
00067         }
00068         else {
00069             index = navMesh_->find(p);
00070         }
00071 
00072         //LogDetail(index);
00073         return index;
00074     }
00075 
00076 
00077     bool NavMeshArea
00078     ::doesTouchVoid(const Point3& wc, short index, coor_t radius) const {
00079         if(index < 0)
00080             return true;
00081         Point3 p(wc);
00082         p.sub(posComponent_->nextPos().worldCoor());
00083         return navMesh_->doesTouchVoid(p, index, radius);
00084     }
00085 
00086     void NavMeshArea
00087     ::force(const Point3& coor, Vector3& dest) const {
00088         // No up or down in NavMeshArea (yet)
00089         dest.set(0, 0, 0);
00090     }
00091 
00092 
00093     short NavMeshArea
00094     ::terrainStyle(const Point3& coor, short index) const {
00095         Point2 p(coor.x_, coor.z_);
00096         short tri = (index >= 0) ? index : navMesh_->find(p);
00097         //short tri = navMesh_->find(p);
00098         //LogDetail(tri << ": " << coor.x_ << ", " << coor.z_);
00099 
00100         if(tri < 0) {
00101             return TS_VOID;
00102         }
00103 
00104         return TS_WALKABLE;
00105     }
00106 
00107 
00108     short NavMeshArea
00109     ::nextTerrainStyle(bray_t direction, const Point3& coor) {
00110         // May be deprecated soon??
00111         LogFatal("Not implemented");
00112         return 0;
00113     }
00114 
00115 
00116     bool NavMeshArea
00117     ::isLineOfSight(const Pos& from, const Pos& to) {
00118         const NavMeshArea::Ptr toArea(const_cast<PosComponent*>(to.area()));
00119 
00120         Point3 fromPoint, toPoint;
00121         short fromIndex, toIndex = -1;
00122 
00123         fromPoint.sub(from.worldCoor(), posComponent_->nextPos().worldCoor());
00124         fromIndex = from.index();
00125         toPoint.sub(to.worldCoor(), posComponent_->nextPos().worldCoor());
00126         if(toArea == this) {
00127             toIndex = to.index();
00128         }
00129         int linkType = navMesh_->isInLineOfSight(fromPoint, fromIndex, toPoint, toIndex);
00130 
00131         // Found correct triangle?
00132         if(linkType == 0)
00133             return true;
00134 
00135         // Found wall?
00136         if(linkType == -1)
00137             return false;
00138 
00139         // Found link to neighbour area?
00140         if(linkType == 1) {
00141             Assert(this != toArea);
00142             if(!Area::isNeighbour(*toArea))
00143                 return false;
00144 
00145             Point3 offset, tmp;
00146             PosComponent::Ptr fromAreaPos(*posComponent_);
00147             PosComponent::Ptr toAreaPos(*toArea->posComponent_);
00148             offset.sub(toAreaPos->pos().worldCoor(), fromAreaPos->pos().worldCoor());
00149             BoundingBox toAreaBounds(offset, toAreaPos->pos().bounds_);
00150 
00151             fromPoint.sub(offset);
00152             fromIndex = toArea->navMesh_->findExit(toAreaBounds, tmp);
00153             toPoint.sub(offset);
00154             toIndex = to.index();
00155 
00156             linkType = toArea->navMesh_->isInLineOfSight(fromPoint, fromIndex, toPoint, toIndex);
00157 
00158             // Found correct triangle?
00159             return (linkType == 0);
00160         }
00161         return false;
00162     }
00163 
00164 
00165 
00166     coor_t NavMeshArea
00167     ::farthestLineOfSight(const Point3& from, short fromIndex, bray_t yaw, coor_t maxLen, coor_t maxOffNavMesh) const {
00168         Point2 p;
00169         short toIndex;
00170         Point3 toPoint;
00171         Point3 fromPoint(from);
00172 
00173         toPoint.setForward(maxLen, yaw);
00174         toPoint.y_ = 0;
00175         toPoint.add(fromPoint);
00176         toIndex = index(toPoint, -1);
00177 
00178         // Send world coor to CAC
00179         coor_t obstructionLen = CollisionAreaComponent::Ptr(*this)->farthestLineOfSight(fromPoint, toPoint);
00180 
00181 
00182         const NavMeshArea* toArea = static_cast<const NavMeshArea*>(neighbour(toPoint));
00183         toPoint.sub(posComponent_->nextPos().worldCoor());
00184         fromPoint.sub(posComponent_->nextPos().worldCoor());
00185 
00186         int linkType = navMesh_->farthestLineOfSightXZ(fromIndex, fromPoint, toPoint, toIndex, p);
00187         if(linkType == 1 && toArea && toArea != this) {
00188 
00189             Point3 offset, tmp;
00190             PosComponent::Ptr fromAreaPos(*posComponent_);
00191             PosComponent::Ptr toAreaPos(*toArea->posComponent_);
00192             offset.sub(fromAreaPos->pos().worldCoor(), toAreaPos->pos().worldCoor());
00193             BoundingBox toAreaBounds(offset, toAreaPos->pos().bounds_);
00194 
00195             fromIndex = toArea->navMesh_->findExit(toAreaBounds, tmp);
00196             fromPoint.x_ = p.x_;
00197             fromPoint.z_ = p.y_;
00198             fromPoint.add(offset);
00199 
00200             toPoint.add(posComponent_->nextPos().worldCoor());
00201             toIndex = toArea->index(toPoint, -1);
00202             toPoint.sub(toAreaPos->nextPos().worldCoor());
00203 
00204             linkType = toArea->navMesh_->farthestLineOfSightXZ(fromIndex, fromPoint, toPoint, toIndex, p);
00205             toPoint.x_ = p.x_ + toAreaPos->nextPos().worldCoor().x_;
00206             toPoint.z_ = p.y_ + toAreaPos->nextPos().worldCoor().z_;
00207         }
00208         else {
00209             toPoint.x_ = p.x_ + posComponent_->nextPos().worldCoor().x_;
00210             toPoint.z_ = p.y_ + posComponent_->nextPos().worldCoor().z_;
00211         }
00212 
00213         Vector3 dist;
00214         dist.sub(from, toPoint);
00215         dist.y_ = 0;
00216         coor_t len = dist.length();
00217         len += maxOffNavMesh;
00218 
00219         if(len > obstructionLen)
00220             len = obstructionLen;
00221 
00222         if(len > maxLen)
00223             len = maxLen;
00224 
00225         return len;
00226     }
00227 
00228 
00229     coor_t NavMeshArea
00230     ::farthestLineOfSight(const Pos& from, bray_t yaw, coor_t maxLen, coor_t maxOffNavMesh, Point3& dest) const {
00231         coor_t len = farthestLineOfSight(from.worldCoor(), from.index(), yaw, maxLen, maxOffNavMesh);
00232         Point3 toPoint;
00233         toPoint.setForward(len, yaw);
00234         toPoint.add(from.worldCoor());
00235         if(toPoint.xzDistanceSquared(from.worldCoor()) < dest.xzDistanceSquared(from.worldCoor())) {
00236             dest.x_ = toPoint.x_;
00237             dest.z_ = toPoint.z_;
00238         }
00239 
00240         return len;
00241     }
00242 
00243 
00244     void NavMeshArea
00245     ::farthestLineOfSight(const Pos& from, const Pos& to, Point3& dest) const {
00246         Point3 toPoint(to.worldCoor());
00247         short toIndex = index(toPoint, from.index());
00248         toPoint.sub(posComponent_->nextPos().worldCoor());
00249 
00250         short fromIndex = from.index();
00251         Point3 fromPoint;
00252         fromPoint.sub(from.worldCoor(), posComponent_->nextPos().worldCoor());
00253 
00254         Point2 p;
00255         navMesh_->farthestLineOfSightXZ(fromIndex, fromPoint, toPoint, toIndex, p);
00256         dest.x_ = p.x_ + posComponent_->nextPos().worldCoor().x_;
00257         dest.z_ = p.y_ + posComponent_->nextPos().worldCoor().z_;
00258     }
00259 
00260 
00261     short NavMeshArea
00262     ::farthestLos(const Point3& from, short fromIndex, short toIndex) const {
00263         Point3 c;
00264         if(fromIndex == toIndex) {
00265             return toIndex;
00266         }
00267 
00268         short via = navMesh_->path(fromIndex, toIndex);
00269         navMesh_->center(via, c);
00270         if(navMesh_->isInLineOfSight(from, fromIndex, c, via) < 0) {
00271             LogDetail("Gave path that was not in LOS");
00272             return fromIndex;
00273         }
00274         if(via == toIndex)
00275             return via;
00276 
00277         short next = navMesh_->path(via, toIndex);
00278         navMesh_->center(next, c);
00279         while(navMesh_->isInLineOfSight(from, fromIndex, c, next) == 0) {
00280             via = next;
00281             if(via == toIndex)
00282                 break;
00283 
00284             next = navMesh_->path(via, toIndex);
00285             navMesh_->center(next, c);
00286         }
00287         return via;
00288     }
00289 
00290 
00291     void NavMeshArea
00292     ::path(const Pos& from, const Pos& to, Point3& out) const {
00293         // In different areas - search for triangles in this navmesh that
00294         // is inside the other
00295         if(from.area() != to.area()) {
00296             if(!from.hasArea() || !to.hasArea()) {
00297                 out.set(from.localCoor());
00298                 return;
00299             }
00300             Point3 p(to.area()->pos().worldCoor());
00301             p.sub(from.area()->pos().worldCoor());
00302             BoundingBox toArea(p, to.area()->pos().bounds_);
00303             short toIndex = navMesh_->findExit(toArea, out);
00304             //LogDetail(name() << p << toArea << " - " << out);
00305 
00306             if(toIndex < 0) {
00307                 out.set(to.localCoor());
00308                 return;
00309             }
00310 
00311             // Already in same triangle
00312             if(from.index() == toIndex) {
00313                 // At exit - walk to center of next area
00314                 toArea.center(out);
00315                 return;
00316             }
00317             if(navMesh_->isInLineOfSight(from.localCoor(), from.index(), out, toIndex) == 0) {
00318                 // Out is already set
00319                 return;
00320             }
00321             //short via = navMesh_->path(from.index(), toIndex);
00322             short via = farthestLos(from.localCoor(), from.index(), toIndex);
00323             navMesh_->center(via, out);
00324 
00325             return;
00326         }
00327         // Already in same triangle
00328         if(from.index() == to.index()) {
00329             out.set(to.localCoor());
00330             return;
00331         }
00332         if(to.index() < 0) {
00333             out.set(to.localCoor());
00334             return;
00335         }
00336         // In line of sight
00337         if(navMesh_->isInLineOfSight(from, to) == 0) {
00338             out.set(to.localCoor());
00339             return;
00340         }
00341         short via = farthestLos(from.localCoor(), from.index(), to.index());
00342         //short via = navMesh_->path(from.index(), to.index());
00343         //LogDetail("D:" << from.index() << ", " << to.index() << ": " << via);
00344         navMesh_->center(via, out);
00345     }
00346 
00347 
00348     bray_t NavMeshArea
00349     ::slideAngle(const se_core::Pos& from, const se_core::Point3& to) const {
00350         Point3 fromAc, toAc, np(posComponent_->nextPos().worldCoor());
00351         fromAc.sub(from.worldCoor(), np);
00352         toAc.sub(to, np);
00353         bray_t angle = navMesh_->slideAngle(fromAc, from.index(), toAc);
00354         return angle;
00355     }
00356 
00357 
00358     bray_t NavMeshArea
00359     ::wallAngle(const se_core::Pos& from, const se_core::Point3& to) const {
00360         Point3 fromAc, toAc;
00361         fromAc.sub(from.worldCoor(), posComponent_->nextPos().worldCoor());
00362         toAc.sub(to, posComponent_->nextPos().worldCoor());
00363         bray_t angle = navMesh_->wallAngle(fromAc, from.index(), toAc);
00364         return angle;
00365     }
00366 
00367 
00368     coor_double_t NavMeshArea
00369     ::findNearest(const se_core::Point3& wc, se_core::Point3& out) const {
00370         Point3 p(wc);
00371         p.sub(posComponent_->nextPos().worldCoor());
00372         return navMesh_->findNearest(p, out);
00373     }
00374 
00375 }

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