fixed issues with random walks

This commit is contained in:
2018-02-10 14:15:05 +01:00
parent 5e749d4da8
commit 2a923dfabc
3 changed files with 120 additions and 7 deletions

94
math/stats/Histogram.h Normal file
View 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

View File

@@ -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);

View File

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