Program Listing for File utils.cpp¶
↰ Return to documentation for file (lib/utils/src/utils.cpp
)
#include <iomanip> // TODO(vss): replace setw
#include <iostream>
#include <random>
#include "utils/utils.hpp"
// constants
constexpr int spacing_for_grid = 10;
void Node::PrintStatus() const {
std::cout << "--------------" << '\n'
<< "Node :" << '\n'
<< "x : " << x_ << '\n'
<< "y : " << y_ << '\n'
<< "Cost : " << cost_ << '\n'
<< "Heuristic cost: " << h_cost_ << '\n'
<< "Id : " << id_ << '\n'
<< "Pid : " << pid_ << '\n'
<< "--------------" << '\n';
}
Node Node::operator+(const Node& p) const {
Node tmp;
tmp.x_ = this->x_ + p.x_;
tmp.y_ = this->y_ + p.y_;
tmp.cost_ = this->cost_ + p.cost_;
return tmp;
}
Node Node::operator-(const Node& p) const {
Node tmp;
tmp.x_ = this->x_ - p.x_;
tmp.y_ = this->y_ - p.y_;
return tmp;
}
bool Node::operator==(const Node& p) const {
return this->x_ == p.x_ && this->y_ == p.y_;
}
bool CompareCoordinates(const Node& p1, const Node& p2) {
return p1.x_ == p2.x_ && p1.y_ == p2.y_;
}
bool checkOutsideBoundary(const Node& node, const int n) {
return (node.x_ < 0 || node.y_ < 0
|| node.x_ >= n || node.y_ >= n);
}
bool compare_cost::operator()(const Node& p1, const Node& p2) const {
// Can modify this to allow tie breaks based on heuristic cost if required
return p1.cost_ + p1.h_cost_ > p2.cost_ + p2.h_cost_ ||
(p1.cost_ + p1.h_cost_ == p2.cost_ + p2.h_cost_ &&
p1.h_cost_ >= p2.h_cost_);
}
bool compare_coordinates::operator()(const Node& p1, const Node& p2) const {
return p1.x_ == p2.x_ && p1.y_ == p2.y_;
}
// Possible motions for dijkstra, A*, and similar algorithms.
// Not using this for RRT & RRT* to allow random direction movements.
// TODO(vss): Consider adding option for motion restriction in RRT and RRT* by
// replacing new node with nearest node that satisfies motion constraints
std::vector<Node> GetMotion() {
return {
Node(0, 1, 1, 0, 0, 0),
Node(1, 0, 1, 0, 0, 0),
Node(0, -1, 1, 0, 0, 0),
Node(-1, 0, 1, 0, 0, 0)
// Node(1, 1, sqrt(2), 0, 0, 0),
// Node(1, -1, sqrt(2), 0, 0, 0),
// Node(-1, 1, sqrt(2), 0, 0, 0),
// Node(-1, -1, sqrt(2), 0, 0, 0)
};
// NOTE: Add diagonal movements for A* and D* only after the heuristics in the
// algorithms have been modified. Refer to README.md. The heuristics currently
// implemented are based on Manhattan distance and dwill not account for
// diagonal/ any other motions
}
void MakeGrid(std::vector<std::vector<int>>& grid) {
int n = grid.size();
std::random_device rd; // obtain a random number from hardware
std::mt19937 eng(rd()); // seed the generator
std::uniform_int_distribution<int> distr(0, n); // define the range
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
grid[i][j] = distr(eng) / ((n - 1)); // probability of obstacle is 1/n
// grid[i][j] = 0; // For no obstacles
}
}
}
void PrintPath(const std::vector<Node>& path_vector, const Node& start,
const Node& goal, std::vector<std::vector<int>>& grid) {
#ifdef CUSTOM_DEBUG_HELPER_FUNCION
if (path_vector.empty()) {
std::cout << "No path exists" << '\n';
PrintGrid(grid);
return;
}
std::cout << "Path (goal to start):" << '\n';
for (size_t i = 0; i < path_vector.size(); i++) {
if (CompareCoordinates(goal, path_vector[i])) {
path_vector[i].PrintStatus();
grid[path_vector[i].x_][path_vector[i].y_] = 3;
while (path_vector[i].id_ != start.id_) {
if (path_vector[i].id_ == path_vector[i].pid_) {
break;
}
for (size_t j = 0; j < path_vector.size(); j++) {
if (path_vector[i].pid_ == path_vector[j].id_) {
i = j;
path_vector[j].PrintStatus();
grid[path_vector[j].x_][path_vector[j].y_] = 3;
}
}
}
break;
}
}
grid[start.x_][start.y_] = 3;
PrintGrid(grid);
#endif // CUSTOM_DEBUG_HELPER_FUNCION
}
void PrintCost(const std::vector<std::vector<int>>& grid,
const std::vector<Node>& point_list) {
#ifdef CUSTOM_DEBUG_HELPER_FUNCION
int n = grid.size();
std::vector<Node>::const_iterator it_v;
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
for (it_v = point_list.begin(); it_v != point_list.end(); ++it_v) {
if (i == it_v->x_ && j == it_v->y_) {
std::cout << std::setw(spacing_for_grid) << it_v->cost_ << " , ";
break;
}
}
if (it_v == point_list.end()) {
std::cout << std::setw(spacing_for_grid) << " , ";
}
}
std::cout << '\n' << '\n';
}
#endif // CUSTOM_DEBUG_HELPER_FUNCION
}
void PrintPathInOrder(const std::vector<Node>& path_vector,
const Node& /*start*/, const Node& goal,
std::vector<std::vector<int>>& grid) {
#ifdef CUSTOM_DEBUG_HELPER_FUNCION
if (path_vector.empty()) {
std::cout << "Path not found" << '\n';
PrintGrid(grid);
return;
}
std::cout << "Path (goal to start):" << '\n';
size_t i = 0;
while (!CompareCoordinates(path_vector[i], goal)) {
i++;
}
for (; i > 0; i = i - 1) {
path_vector[i].PrintStatus();
grid[path_vector[i].x_][path_vector[i].y_] = 3;
}
path_vector[0].PrintStatus();
grid[path_vector[0].x_][path_vector[0].y_] = 3;
PrintGrid(grid);
#endif // CUSTOM_DEBUG_HELPER_FUNCION
}
void LazyPQ::clear() {
s.clear();
while(!pq.empty()) {
pq.pop();
}
}
void LazyPQ::insert(const NodeKeyPair& t) {
if(auto p = s.insert(t); !p.second) {
s.erase(t);
s.insert(t);
}
pq.push(t);
}
void LazyPQ::pop() {
while(!pq.empty()) {
if (const auto it = s.find(pq.top()); it == s.end() ||
(it != s.end() && pq.top().key != it->key)) {
// Element been removed from set OR
// Element has been updated in set with new key, and inserted already into pq with new value
pq.pop();
} else if (it != s.end() && pq.top().key == it->key) {
// Found an elelment that is in set and priority queue
break;
}
}
if (s.empty()) {
return;
}
s.erase(pq.top());
pq.pop();
// The loop below allows top() to be const without making the
// std::priority_queue mutable
while(!pq.empty()) {
if (const auto it = s.find(pq.top()); it == s.end() ||
(it != s.end() && pq.top().key != it->key)) {
// Element been removed from set OR
// Element has been updated in set with new key, and inserted already into pq with new value
pq.pop();
} else if (it != s.end() && pq.top().key == it->key) {
// Found an elelment that is in set and priority queue
break;
}
}
}
const NodeKeyPair& LazyPQ::top() const {
return pq.top();
}
size_t LazyPQ::size() const {
return s.size();
}
bool LazyPQ::empty() const {
return s.empty();
}
bool LazyPQ::isElementInStruct(const NodeKeyPair& t) const {
return s.find(t) != s.end();
}
void LazyPQ::remove(const NodeKeyPair& t) {
if (s.find(t) != s.end()) {
s.erase(t);
}
// Ensure top() is const
while(!pq.empty()) {
if (const auto it = s.find(pq.top()); it == s.end() ||
(it != s.end() && pq.top().key != it->key)) {
// Element been removed from set OR
// Element has been updated in set with new key, and inserted already into pq with new value
pq.pop();
} else if (it != s.end() && pq.top().key == it->key) { // Found an elelment that is in set and priority queue
break;
}
}
}