This repository has been archived on 2020-04-08. You can view files and clone it, but cannot push or open issues or pull requests.
Files
Indoor/navMesh/NavMeshRandom.h
2018-10-25 11:50:12 +02:00

143 lines
3.6 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* © Copyright 2014 Urheberrechtshinweis
* Alle Rechte vorbehalten / All Rights Reserved
*
* Programmcode ist urheberrechtlich geschuetzt.
* Das Urheberrecht liegt, soweit nicht ausdruecklich anders gekennzeichnet, bei Frank Ebner.
* Keine Verwendung ohne explizite Genehmigung.
* (vgl. § 106 ff UrhG / § 97 UrhG)
*/
#ifndef NAVMESHRANDOM_H
#define NAVMESHRANDOM_H
#include <random>
#include <vector>
#include "../math/DrawList.h"
#include "../geo/Point3.h"
#include "../misc/PerfCheck.h"
#include "../math/stats/Histogram.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 <typename Tria> class NavMeshRandom {
DrawList<size_t> lst;
std::uniform_real_distribution<float> dOnTriangle = std::uniform_real_distribution<float>(0.0f, 1.0f);
std::uniform_real_distribution<float> dHeading = std::uniform_real_distribution<float>(0, M_PI*2);
std::vector<const Tria*> triangles;
uint32_t nextSeed() {
static uint32_t seed = 0;
return seed += 13;
}
public:
/** ctor (const/non-const using T) */
template <typename T> NavMeshRandom(const std::vector<T*>& srcTriangles) : lst(nextSeed()) {
Assert::isFalse(srcTriangles.empty(), "no triangles given. mesh is empty");
// 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<Tria> draw() {
// re-use to provide stable random numbers!
static std::mt19937 gen;
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);
#ifdef WITH_DEBUG_PLOT_2
static Stats::Histogram<float> histU(0, 1, 200);
static Stats::Histogram<float> histV(0, 1, 200);
if (histU.count() > 200) {histU.showPlot(); histU.clear();}
if (histV.count() > 200) {histV.showPlot(); histV.clear();}
histU.add(u);
histV.add(v);
#endif
// 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<Tria>(pos, tria);
}
/** draw a random location within the given radius */
NavMeshLocation<Tria> drawWithin(const Point3 center, const float radius) {
// re-use to provide stable random numbers!
static std::mt19937 gen;
std::uniform_real_distribution<float> 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;
#ifdef WITH_DEBUG_PLOT_2
static Stats::Histogram<float> hist(0, 10, 200);
if (hist.count() > 1000) {hist.showPlot(); hist.clear();}
hist.add(dist);
#endif
// 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<Tria> loc(p3, t);
return loc;
}
}
}
}
};
}
#endif // NAVMESHRANDOM_H