geometry changes/fixes/new features
new grid walkers + fixes new test-cases worked on step/and turn detection android offline-data-reader worked on vap-grouping
This commit is contained in:
@@ -18,18 +18,7 @@
|
||||
#include <functional>
|
||||
|
||||
|
||||
/** listen for events during the build process */
|
||||
class GridFactoryListener {
|
||||
|
||||
public:
|
||||
|
||||
virtual void onGridBuildUpdateMajor(const std::string& what) = 0;
|
||||
virtual void onGridBuildUpdateMajor(const int cnt, const int cur) = 0;
|
||||
|
||||
virtual void onGridBuildUpdateMinor(const std::string& what) = 0;
|
||||
virtual void onGridBuildUpdateMinor(const int cnt, const int cur) = 0;
|
||||
|
||||
};
|
||||
#include "GridFactoryListener.h"
|
||||
|
||||
|
||||
template <typename T> class GridFactory {
|
||||
@@ -156,7 +145,7 @@ public:
|
||||
GridNodeBBox bbox(GridPoint(x_cm, y_cm, z_cm), helper.gridSize());
|
||||
|
||||
// slightly grow the bbox to ensure even obstacles that are directly aligned to the bbox are hit
|
||||
bbox.grow(0.012345);
|
||||
bbox.grow(0.42345);
|
||||
if (intersects(bbox, floor)) {continue;}
|
||||
|
||||
// add to the grid
|
||||
@@ -170,7 +159,7 @@ public:
|
||||
}
|
||||
|
||||
// connect the g
|
||||
connectAdjacent(z_cm);
|
||||
connectAdjacent(floor, z_cm);
|
||||
|
||||
}
|
||||
|
||||
@@ -186,6 +175,9 @@ public:
|
||||
if (listener) {listener->onGridBuildUpdateMinor(total, ++cur);}
|
||||
}
|
||||
|
||||
// cleanup
|
||||
stairs.finalize();
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -273,7 +265,7 @@ public:
|
||||
}
|
||||
|
||||
/** connect all neighboring nodes located on the given height-plane */
|
||||
void connectAdjacent(const float z_cm) {
|
||||
void connectAdjacent(const Floorplan::Floor* floor, const float z_cm) {
|
||||
|
||||
Log::add(name, "connecting all adjacent nodes at height " + std::to_string(z_cm), false);
|
||||
Log::tick();
|
||||
@@ -285,7 +277,7 @@ public:
|
||||
if (n1.z_cm != z_cm) {continue;}
|
||||
|
||||
// connect the node with its neighbors
|
||||
connectAdjacent(n1);
|
||||
connectAdjacent(floor, n1);
|
||||
|
||||
}
|
||||
|
||||
@@ -293,8 +285,13 @@ public:
|
||||
|
||||
}
|
||||
|
||||
/** connect the given node with its neighbors */
|
||||
void connectAdjacent(T& n1) {
|
||||
/**
|
||||
* connect the given node with its neighbors.
|
||||
* even though a node has a neighbor, it might still be blocked by an obstacle:
|
||||
* e.g. a 45° wall directly between nodes. a neighbor exists, but is unreachable due to the wall.
|
||||
* we thus perform an additional intersection check with all obstacles within the floor the node n1 belongs to
|
||||
*/
|
||||
void connectAdjacent(const Floorplan::Floor* floor, T& n1) {
|
||||
|
||||
const int gridSize_cm = grid.getGridSize_cm();
|
||||
|
||||
@@ -313,6 +310,7 @@ public:
|
||||
// does the grid contain the potential neighbor?
|
||||
const T* n2 = grid.getNodePtrFor(p);
|
||||
if (n2 != nullptr) {
|
||||
if (isBlocked(floor, n1, *n2)) {continue;} // is there a (e.g. small) obstacle between the two?
|
||||
grid.connectUniDir(n1, *n2); // UNI-dir connection as EACH node is processed!
|
||||
}
|
||||
|
||||
@@ -479,7 +477,46 @@ private:
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* normally, the algorithm will not try to connect two nodes that are neighbors but have an obstacle between them.
|
||||
* however, especially for 45° obstacles it might happen that a neighbor exists but is blocked by an obstacle.
|
||||
* we thus need this additional check to ensure everything is fine... even though it needs performance...
|
||||
*/
|
||||
static inline bool isBlocked(const Floorplan::Floor* floor, const GridPoint& n1, const GridPoint& n2) {
|
||||
|
||||
// (obstacles use meter, while the nodes are in centimeter!
|
||||
const Point2 p1_m = n1.inMeter().xy();
|
||||
const Point2 p2_m = n2.inMeter().xy();
|
||||
const Line2 lineNodes(p1_m, p2_m);
|
||||
|
||||
// process each obstacle
|
||||
for (Floorplan::FloorObstacle* fo : floor->obstacles) {
|
||||
|
||||
// depends on the type of obstacle
|
||||
if (dynamic_cast<Floorplan::FloorObstacleLine*>(fo)) {
|
||||
const Floorplan::FloorObstacleLine* line = (Floorplan::FloorObstacleLine*) fo;
|
||||
const Line2 lineObstacle(line->from, line->to);
|
||||
if (lineObstacle.getSegmentIntersection(lineNodes)) {return true;}
|
||||
|
||||
} else if (dynamic_cast<Floorplan::FloorObstacleCircle*>(fo)) {
|
||||
throw Exception("should not happen");
|
||||
|
||||
} else if (dynamic_cast<Floorplan::FloorObstacleDoor*>(fo)) {
|
||||
// DOORS ARE NOT AN OBSTACLE
|
||||
|
||||
} else {
|
||||
throw Exception("TODO: not yet implemented obstacle type");
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
/** does the bbox intersect with any of the floor's walls? */
|
||||
|
||||
19
grid/factory/v2/GridFactoryListener.h
Normal file
19
grid/factory/v2/GridFactoryListener.h
Normal file
@@ -0,0 +1,19 @@
|
||||
#ifndef GRIDFACTORYLISTENER_H
|
||||
#define GRIDFACTORYLISTENER_H
|
||||
|
||||
#include <string>
|
||||
|
||||
/** listen for events during the build process */
|
||||
class GridFactoryListener {
|
||||
|
||||
public:
|
||||
|
||||
virtual void onGridBuildUpdateMajor(const std::string& what) = 0;
|
||||
virtual void onGridBuildUpdateMajor(const int cnt, const int cur) = 0;
|
||||
|
||||
virtual void onGridBuildUpdateMinor(const std::string& what) = 0;
|
||||
virtual void onGridBuildUpdateMinor(const int cnt, const int cur) = 0;
|
||||
|
||||
};
|
||||
|
||||
#endif // GRIDFACTORYLISTENER_H
|
||||
@@ -1,8 +1,11 @@
|
||||
#ifndef IMPORTANCE_H
|
||||
#define IMPORTANCE_H
|
||||
|
||||
|
||||
|
||||
#include "../../../geo/Units.h"
|
||||
#include "../../Grid.h"
|
||||
#include "GridFactoryListener.h"
|
||||
|
||||
#include "../../../misc/KNN.h"
|
||||
#include "../../../misc/KNNArray.h"
|
||||
@@ -35,9 +38,14 @@ public:
|
||||
}
|
||||
|
||||
/** attach importance-factors to the grid */
|
||||
template <typename T> static void addImportance(Grid<T>& g) {
|
||||
template <typename T> static void addImportance(Grid<T>& g, GridFactoryListener* l = nullptr) {
|
||||
|
||||
Log::add(name, "adding importance information to all nodes");// at height " + std::to_string(z_cm));
|
||||
Log::add(name, "adding importance information to all nodes");
|
||||
if (l) {
|
||||
l->onGridBuildUpdateMajor(2, 0);
|
||||
l->onGridBuildUpdateMajor("adding importance information");
|
||||
l->onGridBuildUpdateMinor("performing initial setups");
|
||||
}
|
||||
|
||||
// get an inverted version of the grid
|
||||
Grid<T> inv(g.getGridSize_cm());
|
||||
@@ -51,15 +59,13 @@ public:
|
||||
// construct KNN search
|
||||
KNN<Grid<T>, 3> knn(inv);
|
||||
|
||||
// the number of neighbors to use
|
||||
static constexpr int numNeighbors = 12;
|
||||
|
||||
// create list of all door-nodes
|
||||
std::vector<T> doors;
|
||||
|
||||
// create list of all stair-nodes
|
||||
std::vector<T> stairs;
|
||||
|
||||
|
||||
// process each node
|
||||
for (T& n1 : g) {
|
||||
|
||||
@@ -83,9 +89,26 @@ public:
|
||||
Distribution::Normal<float> favorDoors(0.0f, 0.5f);
|
||||
Distribution::Normal<float> favorStairs(0.0f, 3.5f);
|
||||
|
||||
if (l) {
|
||||
l->onGridBuildUpdateMajor(2, 1);
|
||||
l->onGridBuildUpdateMinor("calculating importance for each node");
|
||||
}
|
||||
|
||||
std::cout << "dunno why, but the KNN for stairs searches extremely slow!" << std::endl;
|
||||
|
||||
// process each node again
|
||||
for (T& n1 : g) {
|
||||
for (int i = 0; i < g.getNumNodes(); ++i) {
|
||||
|
||||
|
||||
// log
|
||||
if (i % (g.getNumNodes() / 20) == 0) {
|
||||
if (l) {
|
||||
l->onGridBuildUpdateMinor(g.getNumNodes(), i);
|
||||
}
|
||||
}
|
||||
|
||||
// get the node
|
||||
T& n1 = g[i];
|
||||
|
||||
// get the distance to the nearest wall
|
||||
const float distToWall_m = Units::cmToM(knn.getNearestDistance( {n1.x_cm, n1.y_cm, n1.z_cm} ));
|
||||
@@ -101,12 +124,16 @@ public:
|
||||
// final probability
|
||||
n1.navImportance = 1.0f;
|
||||
n1.navImportance += favorDoors.getProbability(distToDoor_m) * 1.25f;
|
||||
n1.navImportance += favorStairs.getProbability(distToStair_m) * 3.5f;
|
||||
n1.navImportance += favorStairs.getProbability(distToStair_m) * 2.5f;
|
||||
|
||||
// use wall avoidance
|
||||
if (useNormal) {
|
||||
n1.navImportance -= avoidWalls.getProbability(distToWall_m);
|
||||
n1.navImportance -= avoidWalls.getProbability(distToWall_m) * 0.5f;
|
||||
}
|
||||
|
||||
// sanity check
|
||||
Assert::isTrue(n1.navImportance >= 0, "detected negative importance. does not make sense!");
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -22,6 +22,9 @@ private:
|
||||
/** calculation helper */
|
||||
Helper<T> helper;
|
||||
|
||||
// keep a list of all vertices below stairwells and remove them hereafter
|
||||
std::vector<T*> toDelete;
|
||||
|
||||
|
||||
std::ofstream outStairs;
|
||||
std::ofstream outDelete;
|
||||
@@ -77,6 +80,7 @@ public:
|
||||
}
|
||||
|
||||
~Stairs() {
|
||||
finalize();
|
||||
outStairs.close();
|
||||
outDelete.close();
|
||||
}
|
||||
@@ -201,10 +205,6 @@ public:
|
||||
}
|
||||
|
||||
|
||||
// keep a list of all vertices below stairwells and remove them hereafter
|
||||
std::vector<T*> toDelete;
|
||||
|
||||
|
||||
// add all stair nodes or replace them with already existing ones
|
||||
for (Intermediate& iNode : stairNodes) {
|
||||
|
||||
@@ -288,13 +288,23 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
// delete all pending nodes and perform a cleanup
|
||||
for (T* n : toDelete) {grid.remove(*n);}
|
||||
grid.cleanup();
|
||||
// finalize after ALL stairs were added. much faster and should be safe!
|
||||
//finalize();
|
||||
|
||||
|
||||
}
|
||||
|
||||
void finalize() {
|
||||
|
||||
// delete all pending nodes and perform a cleanup
|
||||
if (!toDelete.empty()) {
|
||||
for (T* n : toDelete) {grid.remove(*n);}
|
||||
toDelete.clear();
|
||||
grid.cleanup();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static float minZ(const std::vector<XYZ>& points) {
|
||||
auto comp = [] (const XYZ& a, const XYZ& b) {return a.z < b.z;};
|
||||
auto it = std::min_element(points.begin(), points.end(), comp);
|
||||
|
||||
Reference in New Issue
Block a user