worked on grid-walker
This commit is contained in:
@@ -6,10 +6,146 @@
|
||||
|
||||
#include "Structs.h"
|
||||
|
||||
#include <vector>
|
||||
#include <set>
|
||||
|
||||
#include <KLib/math/random/RandomIterator.h>
|
||||
|
||||
//#define SHOW_DEBUG_PLOT
|
||||
|
||||
#ifdef SHOW_DEBUG_PLOT
|
||||
#include <KLib/misc/gnuplot/Gnuplot.h>
|
||||
#include <KLib/misc/gnuplot/GnuplotPlot.h>
|
||||
#include <KLib/misc/gnuplot/GnuplotPlotElementColorPoints.h>
|
||||
#endif
|
||||
|
||||
namespace GW3 {
|
||||
|
||||
|
||||
/** get an iterator over all nodes reachable from the given start */
|
||||
template <typename Node> class ReachableIteratorSorted {
|
||||
|
||||
const Grid<Node>& grid;
|
||||
const Node& start;
|
||||
|
||||
struct Next {
|
||||
|
||||
uint32_t idx;
|
||||
float distToStart;
|
||||
|
||||
Next(uint32_t idx, float distToStart) : idx(idx), distToStart(distToStart) {;}
|
||||
|
||||
/** compare by weight. same weight? : compare by pointer */
|
||||
bool operator < (const Next& o) const {
|
||||
return (distToStart != o.distToStart) ? (distToStart < o.distToStart) : (idx < o.idx);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
Node* curNode = nullptr;
|
||||
std::unordered_set<uint32_t> visited;
|
||||
std::set<Next> toVisit;
|
||||
|
||||
public:
|
||||
|
||||
ReachableIteratorSorted(const Grid<Node>& grid, const Node& start) : grid(grid), start(start) {
|
||||
toVisit.insert(Next(start.getIdx(),0));
|
||||
}
|
||||
|
||||
bool hasNext() const {
|
||||
return !toVisit.empty();
|
||||
}
|
||||
|
||||
const Node& next() {
|
||||
|
||||
const Next cur = *(toVisit.begin()); // visit from inside out (needed for correct distance)
|
||||
toVisit.erase(toVisit.begin());
|
||||
visited.insert(cur.idx);
|
||||
|
||||
const Node& curNode = grid[cur.idx];
|
||||
|
||||
for (int i = 0; i < curNode.getNumNeighbors(); ++i) {
|
||||
|
||||
const int neighborIdx = curNode.getNeighborIdx(i);
|
||||
const Node& neighbor = grid[neighborIdx];
|
||||
const float newDist = cur.distToStart + curNode.getDistanceInMeter(neighbor);
|
||||
|
||||
// not yet reached -> store distance
|
||||
if (visited.find(neighborIdx) == visited.end()) {
|
||||
toVisit.insert(Next(neighborIdx, newDist));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// done
|
||||
return curNode;
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/** get an iterator over all nodes reachable from the given start */
|
||||
template <typename Node> class ReachableIteratorUnsorted {
|
||||
|
||||
const Grid<Node>& grid;
|
||||
const Node& start;
|
||||
|
||||
Node* curNode = nullptr;
|
||||
std::unordered_set<uint32_t> visited;
|
||||
std::vector<uint32_t> toVisit;
|
||||
|
||||
public:
|
||||
|
||||
ReachableIteratorUnsorted(const Grid<Node>& grid, const Node& start) : grid(grid), start(start) {
|
||||
toVisit.push_back(start.getIdx());
|
||||
}
|
||||
|
||||
bool hasNext() const {
|
||||
return !toVisit.empty();
|
||||
}
|
||||
|
||||
const Node& next(const std::function<bool(const Node&)>& skip) {
|
||||
|
||||
const uint32_t curIdx = toVisit.front(); //visit from inside out (needed for correct distance)
|
||||
toVisit.erase(toVisit.begin());
|
||||
visited.insert(curIdx);
|
||||
|
||||
const Node& curNode = grid[curIdx];
|
||||
|
||||
for (int i = 0; i < curNode.getNumNeighbors(); ++i) {
|
||||
|
||||
const int neighborIdx = curNode.getNeighborIdx(i);
|
||||
const Node& neighbor = grid[neighborIdx];
|
||||
|
||||
// not yet reached -> store distance
|
||||
if (!skip(neighbor)) {
|
||||
if (visited.find(neighborIdx) == visited.end()) {
|
||||
toVisit.push_back(neighborIdx);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// done
|
||||
return curNode;
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
struct ReachableSettings {
|
||||
|
||||
float dist_m;
|
||||
bool limitDistance = true;
|
||||
|
||||
Heading heading = Heading(0);
|
||||
float maxHeadingDiff_rad;
|
||||
bool limitHeading = false;
|
||||
|
||||
};
|
||||
|
||||
|
||||
template <typename Node> class Helper {
|
||||
|
||||
public:
|
||||
@@ -74,54 +210,80 @@ namespace GW3 {
|
||||
|
||||
return walks;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/** get all reachable nodes that are within a given range */
|
||||
static Nodes<Node> getAllReachableNodes(Grid<Node>& grid, const Node* start, const float dist_m) {
|
||||
static Nodes<Node> getAllReachableNodes(Grid<Node>& grid, const Node* start, const ReachableSettings& set ) {
|
||||
|
||||
//auto tStart = std::chrono::system_clock::now();
|
||||
|
||||
Nodes<Node> res;
|
||||
std::unordered_map<uint32_t, float> distances;
|
||||
std::vector<uint32_t> toVisit;
|
||||
std::vector<uint32_t> toVisit; // std::queue was only barely faster: 900 vs 880 microseconds
|
||||
|
||||
toVisit.push_back(start->getIdx());
|
||||
distances[start->getIdx()] = 0.0f;
|
||||
|
||||
#ifdef SHOW_DEBUG_PLOT
|
||||
static K::Gnuplot gp;
|
||||
K::GnuplotPlot plot;
|
||||
K::GnuplotPlotElementColorPoints pts1; pts1.setPointType(7); pts1.setPointSize(1);
|
||||
plot.add(&pts1);
|
||||
#endif
|
||||
|
||||
while (!toVisit.empty()) {
|
||||
|
||||
int curIdx = toVisit.front();
|
||||
const int curIdx = toVisit.front(); // visit from inside out (needed for correct distance)
|
||||
toVisit.erase(toVisit.begin());
|
||||
|
||||
const Node& curNode = grid[curIdx];
|
||||
const float curDistance = distances[curIdx];
|
||||
res.push_back(&curNode); // remember for output
|
||||
res.push_back(&curNode); // remember for output
|
||||
|
||||
if (curDistance <= dist_m) {
|
||||
for (int i = 0; i < curNode.getNumNeighbors(); ++i) {
|
||||
#ifdef SHOW_DEBUG_PLOT
|
||||
pts1.add(K::GnuplotPoint2(curNode.x_cm, curNode.y_cm), curDistance);
|
||||
gp.draw(plot);
|
||||
gp.flush();
|
||||
#endif
|
||||
|
||||
const int neighborIdx = curNode.getNeighborIdx(i);
|
||||
const Node& neighbor = grid[neighborIdx];
|
||||
const float addDist = neighbor.inMeter().getDistance(curNode.inMeter());
|
||||
const float totalDist = curDistance + addDist;
|
||||
for (int i = 0; i < curNode.getNumNeighbors(); ++i) {
|
||||
|
||||
// this is like in dijkstra. keep the smallest distance to reach a node:
|
||||
const int neighborIdx = curNode.getNeighborIdx(i);
|
||||
const Node& neighbor = grid[neighborIdx];
|
||||
const float addDist = neighbor.getDistanceInMeter(curNode);
|
||||
const float totalDist = curDistance + addDist;
|
||||
|
||||
// not yet reached -> store distance
|
||||
if (distances.find(neighborIdx) == distances.end()) {
|
||||
toVisit.push_back(neighborIdx);
|
||||
distances[neighborIdx] = totalDist;
|
||||
// this is like in dijkstra. keep the smallest distance to reach a node:
|
||||
|
||||
// reached earlier but found shorter way
|
||||
} else {
|
||||
if (distances[neighborIdx] > totalDist) {
|
||||
distances[neighborIdx] = totalDist;
|
||||
}
|
||||
// not yet reached -> store distance
|
||||
if (distances.find(neighborIdx) == distances.end()) {
|
||||
distances[neighborIdx] = totalDist;
|
||||
|
||||
if (set.limitDistance) {
|
||||
if (totalDist > set.dist_m) {continue;}
|
||||
}
|
||||
if (set.limitHeading) {
|
||||
const Heading head(start->x_cm, start->y_cm, neighbor.x_cm, neighbor.y_cm); // angle between start and current node
|
||||
const float diff = head.getDiffHalfRAD(set.heading); // difference between above angle and requested angle
|
||||
if (diff > set.maxHeadingDiff_rad) {continue;} // more than 90 degree difference? -> ignore
|
||||
}
|
||||
toVisit.push_back(neighborIdx); // needs a visit? (still some distance left)
|
||||
|
||||
|
||||
// reached earlier but found shorter way
|
||||
} else if (distances[neighborIdx] > totalDist) {
|
||||
distances[neighborIdx] = totalDist;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//auto tEnd = std::chrono::system_clock::now();
|
||||
//auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(tEnd - tStart);
|
||||
//std::cout << elapsed.count() << std::endl;
|
||||
|
||||
return res;
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user