fixed issues with random walks
This commit is contained in:
94
math/stats/Histogram.h
Normal file
94
math/stats/Histogram.h
Normal file
@@ -0,0 +1,94 @@
|
||||
#ifndef STATS_HISTOGRAM_H
|
||||
#define STATS_HISTOGRAM_H
|
||||
|
||||
#define WITH_DEBUG_PLOT
|
||||
|
||||
#ifdef WITH_DEBUG_PLOT
|
||||
#include <KLib/misc/gnuplot/Gnuplot.h>
|
||||
#include <KLib/misc/gnuplot/GnuplotPlot.h>
|
||||
#include <KLib/misc/gnuplot/GnuplotPlotElementLines.h>
|
||||
#endif
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace Stats {
|
||||
|
||||
template <typename Scalar> class Histogram {
|
||||
|
||||
#ifdef WITH_DEBUG_PLOT
|
||||
K::Gnuplot gp;
|
||||
K::GnuplotPlot plot;
|
||||
K::GnuplotPlotElementLines lines;
|
||||
#endif
|
||||
|
||||
Scalar min;
|
||||
Scalar max;
|
||||
int bins;
|
||||
int cnt = 0;
|
||||
|
||||
std::vector<Scalar> counts;
|
||||
|
||||
public:
|
||||
|
||||
/** ctor */
|
||||
Histogram(Scalar min, Scalar max, int bins) : min(min), max(max), bins(bins) {
|
||||
|
||||
clear();
|
||||
|
||||
#ifdef WITH_DEBUG_PLOT
|
||||
plot.add(&lines);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
int count() const {
|
||||
return cnt;
|
||||
}
|
||||
|
||||
void add(const Scalar x) {
|
||||
const int idx = binIdx(x);
|
||||
counts.at(idx) += 1;
|
||||
++cnt;
|
||||
if (cnt % 200 == 0) {showPlot();}
|
||||
}
|
||||
|
||||
void clear() {
|
||||
counts.clear();
|
||||
counts.resize(bins);
|
||||
cnt = 0;
|
||||
}
|
||||
|
||||
#ifdef WITH_DEBUG_PLOT
|
||||
void showPlot() {
|
||||
|
||||
lines.clear();
|
||||
|
||||
lines.add(K::GnuplotPoint2(-1,0));
|
||||
for (size_t idx = 0; idx < counts.size(); ++idx) {
|
||||
const Scalar val = binValue(idx);
|
||||
const Scalar sum = counts[idx];
|
||||
const K::GnuplotPoint2 gp2(val, sum);
|
||||
lines.add(gp2);
|
||||
}
|
||||
|
||||
gp.draw(plot);
|
||||
gp.flush();
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
private:
|
||||
|
||||
int binIdx(const Scalar val) const {
|
||||
return (val - min) / (max-min) * bins;
|
||||
}
|
||||
|
||||
Scalar binValue(const int idx) {
|
||||
return idx * (max-min) + min;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // STATS_HISTOGRAM_H
|
||||
@@ -6,6 +6,7 @@
|
||||
#include "../math/DrawList.h"
|
||||
#include "../geo/Point3.h"
|
||||
#include "../misc/PerfCheck.h"
|
||||
#include "../math/stats/Histogram.h"
|
||||
|
||||
#include "NavMeshLocation.h"
|
||||
|
||||
@@ -20,27 +21,22 @@ namespace NM {
|
||||
template <typename Tria> class NavMeshRandom {
|
||||
|
||||
DrawList<size_t> lst;
|
||||
std::minstd_rand gen;
|
||||
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;
|
||||
return seed += 13;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
/** ctor (const/non-const using T) */
|
||||
template <typename T> NavMeshRandom(const std::vector<T*>& srcTriangles) : lst(nextSeed()), gen(nextSeed()) {
|
||||
template <typename T> NavMeshRandom(const std::vector<T*>& srcTriangles) : lst(nextSeed()) {
|
||||
|
||||
Assert::isFalse(srcTriangles.empty(), "no triangles given. mesh is empty");
|
||||
|
||||
// 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) {
|
||||
@@ -53,6 +49,9 @@ namespace NM {
|
||||
/** 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
|
||||
@@ -63,6 +62,15 @@ namespace NM {
|
||||
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;
|
||||
@@ -78,15 +86,25 @@ namespace NM {
|
||||
/** 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);
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ namespace NM {
|
||||
template <typename Tria> float inMeter(const int steps, const NavMeshLocation<Tria>& start) const {
|
||||
|
||||
Assert::isTrue(isValid(), "invalid step-sizes given");
|
||||
Assert::isNotNull(start.tria, "no starting triangle given");
|
||||
|
||||
if (start.tria->getType() == (int) NM::NavMeshType::STAIR_SKEWED) {
|
||||
return stepSizeStair_m * steps;
|
||||
|
||||
Reference in New Issue
Block a user