-
Notifications
You must be signed in to change notification settings - Fork 8
/
Copy pathrrt.cpp
408 lines (362 loc) · 10.2 KB
/
rrt.cpp
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
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
#include <iostream>
#include <cstdio>
#include <random>
#include <SFML/Graphics.hpp>
#include "geometry.h"
using namespace std ;
const int WIDTH = 800 ;
const int HEIGHT = 600 ;
const int RADIUS = 5 ;
const double GOAL_SAMPLING_PROB = 0.05;
const double INF = 1e18;
const double JUMP_SIZE = (WIDTH/100.0 * HEIGHT/100.0)/1.5;
const double DISK_SIZE = JUMP_SIZE ; // Ball radius around which nearby points are found
int whichRRT = 3 ;
vector < Polygon > obstacles ;
Point start, stop ;
int obstacle_cnt = 1 ;
vector < Point > nodes ;
vector < int > parent, nearby ;
vector < double > cost, jumps ;
int nodeCnt = 0, goalIndex = -1 ;
vector <sf::ConvexShape> polygons ;
sf::CircleShape startingPoint, endingPoint ;
bool pathFound = 0 ;
void getInput() {
cout << "NOTE:" << endl ;
cout << "Height of screen: " << HEIGHT << " pixels." ;
cout << " Width of screeen: " << WIDTH << " pixels." << endl ;
cout << "Maximum distance by which algorithm jumps from one point to another: " << JUMP_SIZE << " units" << endl ;
cout << "If you would like to change of any of these, please make modifications in code" << endl ;
cout << "Please provide your inputs keeping this in mind. " << endl << endl ;
cout << "Which type of RRT would you like to watch? 1 for RRT, 2 for RRT*, 3 for Anytime RRT" << endl ;
cin >> whichRRT ;
cout << "Input co-ordinates of starting and ending point respectively in this format X1 Y1 X2 Y2" << endl ;
cin >> start.x >> start.y >> stop.x >> stop.y ;
cout << "How many obstacles?" << endl ;
cin >> obstacle_cnt ;
obstacles.resize(obstacle_cnt);
int pnts = 0 ; Point pnt ;
vector < Point > poly ;
for(int i = 0; i < obstacle_cnt; i++) {
poly.clear();
cout << "How many points in " << i+1 << "th polygon?" << endl ;
cin >> pnts ;
poly.resize(pnts);
cout << "Input co-ordinates of " << i+1 << "th polygon in clockwise order" << endl ;
for(int j = 0; j < pnts; j++) {
cin >> pnt.x >> pnt.y ;
obstacles[i].addPoint(pnt);
}
}
}
// Prepares SFML objects of starting, ending point and obstacles
void prepareInput() {
// Make starting and ending point circles ready
startingPoint.setRadius(RADIUS); endingPoint.setRadius(RADIUS);
startingPoint.setFillColor(sf::Color(208, 0, 240)); endingPoint.setFillColor(sf::Color::Blue);
startingPoint.setPosition(start.x, start.y); endingPoint.setPosition(stop.x, stop.y);
startingPoint.setOrigin(RADIUS/2, RADIUS/2); endingPoint.setOrigin(RADIUS/2, RADIUS/2);
// Prepare polygon of obstacles
polygons.resize(obstacle_cnt);
for(int i = 0; i < obstacle_cnt; i++) {
polygons[i].setPointCount(obstacles[i].pointCnt);
polygons[i].setFillColor(sf::Color(89, 87, 98));
for(int j = 0; j < obstacles[i].pointCnt; j++)
polygons[i].setPoint(j, sf::Vector2f(obstacles[i].points[j].x, obstacles[i].points[j].y));
}
}
void draw(sf::RenderWindow& window) {
sf::Vertex line[2]; sf::CircleShape nodeCircle;
// Uncomment if circular nodes are to be drawn
/*
for(auto& node: nodes) {
nodeCircle.setRadius(RADIUS/2.5); // nodeCircle.setRadius(min(2.0, RADIUS/2.0));
nodeCircle.setOrigin(RADIUS/2.5, RADIUS/2.5);
nodeCircle.setFillColor(sf::Color(0, 255, 171)); nodeCircle.setPosition(node.x, node.y);
window.draw(nodeCircle);
}
*/
// Draw obstacles
for(auto& poly : polygons) window.draw(poly);
// Draw edges between nodes
for(int i = (int)nodes.size() - 1; i; i--) {
Point par = nodes[parent[i]] ;
line[0] = sf::Vertex(sf::Vector2f(par.x, par.y));
line[1] = sf::Vertex(sf::Vector2f(nodes[i].x, nodes[i].y));
window.draw(line, 2, sf::Lines);
}
window.draw(startingPoint); window.draw(endingPoint);
// If destination is reached then path is retraced and drawn
if(pathFound) {
int node = goalIndex;
while(parent[node] != node) {
int par = parent[node];
line[0] = sf::Vertex(sf::Vector2f(nodes[par].x, nodes[par].y));
line[1] = sf::Vertex(sf::Vector2f(nodes[node].x, nodes[node].y));
line[0].color = line[1].color = sf::Color::Red; // orange color
window.draw(line, 2, sf::Lines);
node = par ;
}
}
}
template <typename T> // Returns a random number in [low, high]
T randomCoordinate(T low, T high){
random_device random_device;
mt19937 engine{random_device()};
uniform_real_distribution<double> dist(low, high);
return dist(engine);
}
// Returns true if the line segment ab is obstacle free
bool isEdgeObstacleFree(Point a, Point b) {
for(auto& poly: obstacles)
if(lineSegmentIntersectsPolygon(a, b, poly))
return false ;
return true ;
}
// Returns a random point with some bias towards goal
Point pickRandomPoint() {
double random_sample = randomCoordinate(0.0, 1.0);
if((random_sample - GOAL_SAMPLING_PROB) <= EPS and !pathFound) return stop + Point(RADIUS, RADIUS) ;
return Point(randomCoordinate(0, WIDTH), randomCoordinate(0, HEIGHT));
}
void checkDestinationReached() {
sf::Vector2f position = endingPoint.getPosition();
if(checkCollision(nodes[parent[nodeCnt - 1]], nodes.back(), Point(position.x, position.y), RADIUS)) {
pathFound = 1 ;
goalIndex = nodeCnt - 1;
cout << "Reached!! With a distance of " << cost.back() << " units. " << endl << endl ;
}
}
/* Inserts nodes on the path from rootIndex till Point q such
that successive nodes on the path are not more than
JUMP_SIZE distance away */
void insertNodesInPath(int rootIndex, Point& q) {
Point p = nodes[rootIndex] ;
if(!isEdgeObstacleFree(p, q)) return ;
while(!(p == q)) {
Point nxt = p.steer(q, JUMP_SIZE);
nodes.push_back(nxt);
parent.push_back(rootIndex);
cost.push_back(cost[rootIndex] + distance(p, nxt));
rootIndex = nodeCnt++ ;
p = nxt ;
}
}
/* Rewires the parents of the tree greedily starting from
the new node found in this iterationsation as the parent */
void rewire() {
int lastInserted = nodeCnt - 1 ;
for(auto nodeIndex: nearby) {
int par = lastInserted, cur = nodeIndex;
// Rewire parents as much as possible (greedily)
while( ((cost[par] + distance(nodes[par], nodes[cur])) - cost[cur]) <= EPS) {
int oldParent = parent[cur] ;
parent[cur] = par; cost[cur] = cost[par] + distance(nodes[par], nodes[cur]);
par = cur, cur = oldParent;
}
}
}
/* Runs one iteration of RRT depending on user choice
At least one new node is added on the screen each iteration. */
void RRT() {
Point newPoint, nearestPoint, nextPoint ; bool updated = false ; int cnt = 0 ;
int nearestIndex = 0 ; double minCost = INF; nearby.clear(); jumps.resize(nodeCnt);
while(!updated) {
newPoint = pickRandomPoint();
// Find nearest point to the newPoint such that the next node
// be added in graph in the (nearestPoint, newPoint) while being obstacle free
nearestPoint = *nodes.begin(); nearestIndex = 0;
for(int i = 0; i < nodeCnt; i++) {
if(pathFound and randomCoordinate(0.0, 1.0) < 0.25) // Recalculate cost once in a while
cost[i] = cost[parent[i]] + distance(nodes[parent[i]], nodes[i]);
// Make smaller jumps sometimes to facilitate passing through narrow passages
jumps[i] = randomCoordinate(0.3, 1.0) * JUMP_SIZE ;
auto pnt = nodes[i] ;
if((pnt.distance(newPoint) - nearestPoint.distance(newPoint)) <= EPS and isEdgeObstacleFree(pnt, pnt.steer(newPoint, jumps[i])))
nearestPoint = pnt, nearestIndex = i ;
}
nextPoint = stepNear(nearestPoint, newPoint, jumps[nearestIndex]);
if(!isEdgeObstacleFree(nearestPoint, nextPoint)) continue ;
if( (whichRRT == 1) or (!pathFound and whichRRT == 3)) {
// This is where we don't do any RRT* optimization part
updated = true ;
nodes.push_back(nextPoint); nodeCnt++;
parent.push_back(nearestIndex);
cost.push_back(cost[nearestIndex] + distance(nearestPoint, nextPoint));
if(!pathFound) checkDestinationReached();
continue ;
}
// Find nearby nodes to the new node as center in ball of radius DISK_SIZE
for(int i = 0; i < nodeCnt; i++)
if((nodes[i].distance(nextPoint) - DISK_SIZE) <= EPS and isEdgeObstacleFree(nodes[i], nextPoint))
nearby.push_back(i);
// Find minimum cost path to the new node
int par = nearestIndex; minCost = cost[par] + distance(nodes[par], nextPoint);
for(auto nodeIndex: nearby) {
if( ( (cost[nodeIndex] + distance(nodes[nodeIndex], nextPoint)) - minCost) <= EPS)
minCost = cost[nodeIndex] + distance(nodes[nodeIndex], nextPoint), par = nodeIndex;
}
parent.push_back(par); cost.push_back(minCost);
nodes.push_back(nextPoint); nodeCnt++;
updated = true ;
if(!pathFound) checkDestinationReached();
rewire();
}
}
int main() {
getInput(); prepareInput();
sf::RenderWindow window(sf::VideoMode(WIDTH, HEIGHT), "Basic Anytime RRT");
nodeCnt = 1; nodes.push_back(start); int iterations = 0 ;
parent.push_back(0); cost.push_back(0);
sf::Time delayTime = sf::milliseconds(5);
cout << endl << "Starting node is in Pink and Destination node is in Blue" << endl << endl ;
while (window.isOpen())
{
sf::Event event;
while (window.pollEvent(event))
{
if (event.type == sf::Event::Closed)
{
window.close();
return 0; exit(0);
}
}
RRT(); iterations++;
if(iterations % 500 == 0) {
cout << "Iterations: " << iterations << endl ;
if(!pathFound) cout << "Not reached yet :( " << endl ;
else cout << "Shortest distance till now: " << cost[goalIndex] << " units." << endl ;
cout << endl ;
}
//sf::sleep(delayTime);
window.clear();
draw(window);
window.display();
}
}
/* SOME SAMPLE INPUTS ARE SHOWN BELOW (only cin part) without any RRT preference */
/*
100 70
600 400
2
4
200 480
200 100
250 100
250 480
5
400 0
300 100
350 250
450 250
500 100
*/
/*
50 50
750 180
3
4
100 0
200 0
200 400
100 400
4
250 200
350 200
350 600
250 600
4
400 50
550 50
550 250
400 250
*/
/*
50 50
750 580
3
4
100 0
200 0
200 400
100 400
4
250 200
350 200
350 600
250 600
4
400 32
700 32
700 575
400 575
*/
/*
190 30
660 500
5
3
200 50
200 200
350 200
3
220 50
370 50
370 200
3
400 250
400 450
600 450
3
430 250
630 250
630 450
3
640 470
640 550
680 550
*/
/*
190 55
660 500
9
4
740 360
750 350
680 540
670 530
3
710 290
780 350
630 380
3
520 450
620 540
349 580
4
450 70
700 70
700 240
450 240
3
200 50
200 200
350 200
3
220 50
370 50
370 200
3
400 250
400 450
600 450
3
430 250
630 250
630 450
3
640 470
640 550
680 550
*/