1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 | #include "assignment8.h" #include <iostream> #include <string> #include <vector> #include <stdlib.h> #include <queue> #include <algorithm> #include <math.h> using std::vector; using std::cout; using std::endl; //=========== Constructor ======================================================== RRT::RRT(const cimg_library::CImg<unsigned char>& image) { image_ = image; node_vector_ = vector<Node>(); path_found_ = false; sample_x_ = -1; sample_y_ = -1; } //=========== Required Functions ================================================= /* A method which, given an input vector of nodes, and an input node, finds the closest Node in node vector to input node */ Node RRT::NearestNeighbor(vector<Node> node_vector, Node input_node) { //set a local variable to keep track of the distance. float smallest_dist = Distance(node_vector[0], input_node); int smallest_index = 0; //set to the distance between the first node in node_vector and input_node. //set a local variable to keep track of the index in vector. if(node_vector.size() < 2) { return node_vector[0]; } //if there is only one node, return that node //else else { for(int i = 0; i <= node_vector.size()-1; i++) { //go through each node if(Distance(node_vector[i], input_node) < smallest_dist) { //calculate it's distance between the input_node //if the new distance is shorter than the local distance variable smallest_dist = Distance(node_vector[i], input_node); //update local with new distance. smallest_index = i; //update the index } //identify the } } return node_vector[smallest_index]; } /* A method which given two Nodes, returns true if there is a collision on the path between those nodes in the given map, and false otherwise. Will not be expected to handle input nodes that are outside the map. Check collision using Bresenham’s line algorithm. */ bool RRT::CheckCollision(Node start, Node end) { int x1 = start.x, y1 = start.y, x2 = end.x, y2 = end.y; int delta_x(x2 - x1); // if x1 == x2, then it does not matter what we set here signed char const ix((delta_x > 0) - (delta_x < 0)); delta_x = std::abs(delta_x) << 1; int delta_y(y2 - y1); // if y1 == y2, then it does not matter what we set here signed char const iy((delta_y > 0) - (delta_y < 0)); delta_y = std::abs(delta_y) << 1; int value = image_(x1, y1, 0, 0); if(value == 0) { return false; } if (delta_x >= delta_y) { // error may go below zero int error(delta_y - (delta_x >> 1)); while (x1 != x2) { // reduce error, while taking into account the corner case of error == 0 if ((error > 0) || (!error && (ix > 0))) { error -= delta_x; y1 += iy; } // else do nothing error += delta_y; x1 += ix; value = image_(x1, y1, 0, 0); if(value == 0) { return false; } } } else { // error may go below zero int error(delta_x - (delta_y >> 1)); while (y1 != y2) { // reduce error, while taking into account the corner case of error == 0 if ((error > 0) || (!error && (iy > 0))) { error -= delta_y; x1 += ix; } // else do nothing error += delta_x; y1 += iy; value = image_(x1, y1, 0, 0); if(value == 0) { return false; } } } return true; // return BresenhamPoints(start.x, start.y, end.x, end.y); } /* A method which given two Nodes, and goal radius, returns a vector of Nodes representing a collision free path from the start Node to a node within the goal radius of the end node.. */ vector<Node> RRT::FindPath(Node start, Node end, int goal_radius, int extension_distance) { //initialize vector with the start and end Nodes cout << "start node: " << start.x << "," << start.y << "\nend node: " << end.x << "," << end.y << endl; node_vector_.clear(); start.SetID(0); start.SetParentId(-1); node_vector_.push_back(start); // node_vector_.push_back(end); //if the distance between the start and end is greater than threshold if(Distance(end, start) > goal_radius) { //path not found. path_found_ = false; } // update the end node's parent to be start node's id. // While the path not found while(!path_found_) { //generate random coordinate x,y Sample(); Node sample_node(sample_x_, sample_y_); Node temp_nearest_sample = NearestNeighbor(node_vector_, sample_node); //check if the nearest_node and sample are too far from each other. if(Distance(temp_nearest_sample, sample_node) > extension_distance) { //project sample from the neariest exisiting node toward new node Project(sample_x_, sample_y_, temp_nearest_sample, extension_distance); Node projected_sample(sample_x_, sample_y_); //check collision //if path is clear Node tempt_nearest = NearestNeighbor(node_vector_, projected_sample); bool collision = CheckCollision(tempt_nearest, projected_sample); if(collision) { projected_sample.SetID(GenerateNodeID()); Link_Path(projected_sample, tempt_nearest); if(!CheckNodeExist(projected_sample)){ node_vector_.push_back(projected_sample); //add the node into the vector // cout << "Node ADDED" << endl; } //check if the new node is within the threhold of the goal if(Distance(projected_sample, end) < goal_radius) { //found path path_found_ = true; } } } //if Path found //return the updated vector } PrintNodeVector(node_vector_); // BresenhamPoints(start.x, start.y, end.x, end.y); return node_vector_; } // ============== Helper Functions ============================================= void Node::SetParentId(const int& pid) { parent_id = pid; } void Node::SetID(const int& sid) { id = sid; } void RRT::DrawNodePath() { // if (occupancy_grid_ptr_ == nullptr) { // return; // } const unsigned char color[] = {200}; const unsigned char dColor[] = {100}; // for (size_t i = 0; i < sqrt(map_->GetNodeListLength()); i++) { // for (size_t j = 0; j < sqrt(map_->GetNodeListLength()); j++) { // int id = map_->GenerateNodeID( // 16 * i + 9, // 16 * j + 9); // Node* current_node = map_->GetNodeList()[id]; // if (IsVisited(current_node)) { // occupancy_grid_ptr_->draw_circle( // 16 * i + 9, // 16 * j + 9, // 6, // color); // } // if (id == goal_id) { // occupancy_grid_ptr_->draw_circle( // 16 * i + 9, // 16 * j + 9, // 6, // dColor); // } // } // } // display = *occupancy_grid_ptr_; // display.show(); // usleep(200000000); } void RRT::PrintNodeVector(const vector<Node> node_vector) { if(node_vector.size() < 1) { return; } for(Node n: node_vector) { cout << n.parent_id << " " << n.id <<"(" << n.x << "," << n.y << ") "; } cout << endl; } //return the sign of the given number as 0, +1, or -1. int RRT::sign(int& number) { if (number == 0) { return 0; } else if(number < 0) { return -1; } else { return 1; } } //return the distance between 2 nodes float RRT::Distance(Node n1, Node n2) { // cout << "distance " << sqrt(pow(n2.x - n1.x, 2) + pow(n2.y - n1.y, 2)) << endl; return sqrt(pow(n2.x - n1.x, 2) + pow(n2.y - n1.y, 2)); } // sample a random x based on given depth away from the void RRT::Sample() { const int range_from = 0; const int range_to_x = image_.width() -1; const int range_to_y = image_.height() -1; std:: random_device rand_dev; std::uniform_int_distribution<int> distribution_x(range_from, range_to_x); std::uniform_int_distribution<int> distribution_y(range_from, range_to_y); sample_x_ = distribution_x(rand_dev); // cout << "sample x: " << sample_x_ << endl; sample_y_ = distribution_y(rand_dev); // cout << "sample y: " << sample_y_ << endl; } //project the sample node to distance away from the nearest_node. //likely using the void RRT::Project(int sample_x, int sample_y, Node nearest_node, int distance) { // cout << "original sample_x_, sample_y_ " << sample_x << "," << sample_y << endl; float vector_x = sample_x - nearest_node.x; float vector_y = sample_y - nearest_node.y; //length between sample and nearest_node float length = sqrt(vector_x*vector_x + vector_y*vector_y); //normalize vector vector_x /= length; vector_y /= length; sample_x_ = static_cast<int>(((static_cast<float>(nearest_node.x)) + vector_x*(static_cast<float>(distance)))); sample_y_ = static_cast<int>(((static_cast<float>(nearest_node.y)) + vector_y*(static_cast<float>(distance)))); // cout << "projected sample_x_,sample_y_ " << sample_x_ << "," << sample_y_ << endl; } //link the new_node to the nearest. by assigning the parent id of new_node //with the id of nearest_node void RRT::Link_Path(Node& new_node, Node& nearest_node) { new_node.SetParentId(nearest_node.id); } int RRT::GenerateNodeID(){ return node_vector_.size(); }; //check if the new_node is an existed node // return true if it is, false otherwise. bool RRT::CheckNodeExist(Node new_node) { bool found = false; while(!found) { for (int a = 0; a < node_vector_.size(); a++) { if(node_vector_[a].x == new_node.x) { if(node_vector_[a].y == new_node.y) { found = true; // cout << "found!" << endl; } } } } return found; } // End of File |
Direct link: https://paste.plurk.com/show/9j88qlAKoqBJp7Ph3a03