#ifndef NAVMESHRANDOM_H #define NAVMESHRANDOM_H #include #include #include "../math/DrawList.h" #include "../geo/Point3.h" #include "../misc/PerfCheck.h" #include "NavMeshLocation.h" namespace NM { /** * randomly pick points within the area of the nav-mesh. * points are picked evenly: * bigger triangles are used more often * */ template class NavMeshRandom { DrawList lst; std::minstd_rand gen; std::uniform_real_distribution dOnTriangle = std::uniform_real_distribution(0.0f, 1.0f); std::uniform_real_distribution dHeading = std::uniform_real_distribution(0, M_PI*2); std::vector triangles; uint32_t nextSeed() { static uint32_t seed = 0; return ++seed; } public: /** ctor (const/non-const using T) */ template NavMeshRandom(const std::vector& srcTriangles) : lst(nextSeed()), gen(nextSeed()) { // 1st = almost always the same number?! gen(); gen(); // construct a DrawList (probability = size[area] of the triangle // bigger triangles must be choosen more often for (size_t idx = 0; idx < srcTriangles.size(); ++idx) { this->triangles.push_back(srcTriangles[idx]); this->lst.add(idx, srcTriangles[idx]->getArea()); } } /** draw a random point */ NavMeshLocation draw() { PERF_REGION(3, "NavMeshRandom::draw()"); // pick a random triangle to draw from const size_t idx = lst.get(); const Tria* tria = triangles[idx]; // get random (u,v) on triangle float u = dOnTriangle(gen); float v = dOnTriangle(gen); // if the (u,v) is outside of the triangle, mirror it so its inside the triangle again if ((u+v) > 1) { u = 1.0f - u; v = 1.0f - v; } // done const Point3 pos = tria->getPoint(u,v); //tria->getA() + (tria.getAB() * u) + (tria.getAC() * v); return NavMeshLocation(pos, tria); } /** draw a random location within the given radius */ NavMeshLocation drawWithin(const Point3 center, const float radius) { std::uniform_real_distribution dDistance(0.001, radius); while(true) { const float head = dHeading(gen); const float dist = dDistance(gen); const float ox = std::cos(head) * dist; const float oy = std::sin(head) * dist; // 2D destination (ignore z) const Point2 dst(center.x + ox, center.y + oy); for (const Tria* t : triangles) { // if triangle contains 2D position if (t->contains(dst)) { // convert it to a 3D position const Point3 p3 = t->toPoint3(dst); const NavMeshLocation loc(p3, t); return loc; } } } } }; } #endif // NAVMESHRANDOM_H