From 2a923dfabc635919d98916750f524589683fc3a0 Mon Sep 17 00:00:00 2001 From: frank Date: Sat, 10 Feb 2018 14:15:05 +0100 Subject: [PATCH] fixed issues with random walks --- math/stats/Histogram.h | 94 ++++++++++++++++++++++++++++++++ navMesh/NavMeshRandom.h | 32 ++++++++--- navMesh/walk/NavMeshWalkParams.h | 1 + 3 files changed, 120 insertions(+), 7 deletions(-) create mode 100644 math/stats/Histogram.h diff --git a/math/stats/Histogram.h b/math/stats/Histogram.h new file mode 100644 index 0000000..3a7d5da --- /dev/null +++ b/math/stats/Histogram.h @@ -0,0 +1,94 @@ +#ifndef STATS_HISTOGRAM_H +#define STATS_HISTOGRAM_H + +#define WITH_DEBUG_PLOT + +#ifdef WITH_DEBUG_PLOT +#include +#include +#include +#endif + +#include + +namespace Stats { + + template 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 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 diff --git a/navMesh/NavMeshRandom.h b/navMesh/NavMeshRandom.h index 01da8c9..595e65e 100644 --- a/navMesh/NavMeshRandom.h +++ b/navMesh/NavMeshRandom.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 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; + return seed += 13; } public: /** ctor (const/non-const using T) */ - template NavMeshRandom(const std::vector& srcTriangles) : lst(nextSeed()), gen(nextSeed()) { + template NavMeshRandom(const std::vector& 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 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 histU(0, 1, 200); + static Stats::Histogram 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 drawWithin(const Point3 center, const float radius) { + // re-use to provide stable random numbers! + static std::mt19937 gen; + 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; +#ifdef WITH_DEBUG_PLOT_2 + static Stats::Histogram 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); diff --git a/navMesh/walk/NavMeshWalkParams.h b/navMesh/walk/NavMeshWalkParams.h index 4a89d87..6b85190 100644 --- a/navMesh/walk/NavMeshWalkParams.h +++ b/navMesh/walk/NavMeshWalkParams.h @@ -20,6 +20,7 @@ namespace NM { template float inMeter(const int steps, const NavMeshLocation& 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;