]> rtime.felk.cvut.cz Git - hubacji1/iamcar.git/blob - base/rrtbase.cc
Add node scaling macro for OpenGL
[hubacji1/iamcar.git] / base / rrtbase.cc
1 /*
2 This file is part of I am car.
3
4 I am car is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
8
9 I am car is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with I am car. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18 #include <cmath>
19 #include <omp.h>
20 #include "bcar.h"
21 #include "rrtbase.h"
22 // OpenGL
23 #include <GL/gl.h>
24 #include <GL/glu.h>
25 #include <SDL2/SDL.h>
26
27 extern SDL_Window* gw;
28 extern SDL_GLContext gc;
29
30 RRTBase::~RRTBase()
31 {
32         for (auto n: this->nodes_)
33                 if (n != this->root_)
34                         delete n;
35         for (auto n: this->dnodes_)
36                 if (n != this->root_ && n != this->goal_)
37                         delete n;
38         for (auto s: this->samples_)
39                 if (s != this->goal_)
40                         delete s;
41         for (auto edges: this->rlog_)
42                 for (auto e: edges)
43                         delete e;
44         delete this->root_;
45         delete this->goal_;
46 }
47
48 RRTBase::RRTBase():
49         root_(new RRTNode()),
50         goal_(new RRTNode())
51 {
52         this->nodes_.push_back(this->root_);
53         this->add_iy(this->root_);
54 }
55
56 RRTBase::RRTBase(RRTNode *init, RRTNode *goal):
57         root_(init),
58         goal_(goal)
59 {
60         this->nodes_.push_back(init);
61         this->add_iy(init);
62 }
63
64 RRTNode *RRTBase::root()
65 {
66         return this->root_;
67 }
68
69 RRTNode *RRTBase::goal()
70 {
71         return this->goal_;
72 }
73
74 std::vector<RRTNode *> &RRTBase::nodes()
75 {
76         return this->nodes_;
77 }
78
79 std::vector<RRTNode *> &RRTBase::dnodes()
80 {
81         return this->dnodes_;
82 }
83
84 std::vector<RRTNode *> &RRTBase::samples()
85 {
86         return this->samples_;
87 }
88
89 std::vector<CircleObstacle> *RRTBase::cos()
90 {
91         return this->cobstacles_;
92 }
93
94 std::vector<SegmentObstacle> *RRTBase::sos()
95 {
96         return this->sobstacles_;
97 }
98
99 std::vector<float> &RRTBase::clog()
100 {
101         return this->clog_;
102 }
103
104 std::vector<float> &RRTBase::nlog()
105 {
106         return this->nlog_;
107 }
108
109 std::vector<std::vector<RRTEdge *>> &RRTBase::rlog()
110 {
111         return this->rlog_;
112 }
113
114 std::vector<float> &RRTBase::slog()
115 {
116         return this->slog_;
117 }
118
119 std::vector<std::vector<RRTNode *>> &RRTBase::tlog()
120 {
121         return this->tlog_;
122 }
123
124 bool RRTBase::goal_found()
125 {
126         return this->goal_found_;
127 }
128
129 float RRTBase::elapsed()
130 {
131         std::chrono::duration<float> dt;
132         dt = std::chrono::duration_cast<std::chrono::duration<float>>(
133                         this->tend_ - this->tstart_);
134         return dt.count();
135 }
136
137 bool RRTBase::logr(RRTNode *root)
138 {
139         std::vector<RRTEdge *> e; // Edges to log
140         std::vector<RRTNode *> s; // DFS stack
141         std::vector<RRTNode *> r; // reset visited_
142         RRTNode *tmp;
143         s.push_back(root);
144         while (s.size() > 0) {
145                 tmp = s.back();
146                 s.pop_back();
147                 if (!tmp->visit()) {
148                         r.push_back(tmp);
149                         for (auto ch: tmp->children()) {
150                                 s.push_back(ch);
151                                 e.push_back(new RRTEdge(tmp, ch));
152                         }
153                 }
154         }
155         for (auto n: r)
156                 n->visit(false);
157         this->rlog_.push_back(e);
158         return true;
159 }
160
161 float RRTBase::ocost(RRTNode *n)
162 {
163         float dist = 9999;
164         for (auto o: *this->cobstacles_)
165                 if (o.dist_to(n) < dist)
166                         dist = o.dist_to(n);
167         for (auto o: *this->sobstacles_)
168                 if (o.dist_to(n) < dist)
169                         dist = o.dist_to(n);
170         return n->ocost(dist);
171 }
172
173 bool RRTBase::tlog(std::vector<RRTNode *> t)
174 {
175         if (t.size() > 0) {
176                 this->slog_.push_back(this->elapsed());
177                 this->clog_.push_back(t.front()->ccost() - t.back()->ccost());
178                 this->nlog_.push_back(this->nodes_.size());
179                 this->tlog_.push_back(t);
180                 return true;
181         } else {
182                 return false;
183         }
184 }
185
186 void RRTBase::tstart()
187 {
188         this->tstart_ = std::chrono::high_resolution_clock::now();
189 }
190
191 void RRTBase::tend()
192 {
193         this->tend_ = std::chrono::high_resolution_clock::now();
194 }
195
196 bool RRTBase::link_obstacles(
197                 std::vector<CircleObstacle> *cobstacles,
198                 std::vector<SegmentObstacle> *sobstacles)
199 {
200         this->cobstacles_ = cobstacles;
201         this->sobstacles_ = sobstacles;
202         if (!this->cobstacles_ || !this->sobstacles_) {
203                 return false;
204         }
205         return true;
206 }
207
208 bool RRTBase::add_iy(RRTNode *n)
209 {
210         int i = IYI(n->y());
211         if (i < 0)
212                 i = 0;
213         if (i >= IYSIZE)
214                 i = IYSIZE - 1;
215         this->iy_[i].push_back(n);
216         return true;
217 }
218
219 bool RRTBase::glplot()
220 {
221         glClear(GL_COLOR_BUFFER_BIT);
222         // Plot obstacles
223         glBegin(GL_LINES);
224         for (auto o: *this->sobstacles_) {
225                 glColor3f(0, 0, 0);
226                 glVertex2f(GLVERTEX(o.init()));
227                 glVertex2f(GLVERTEX(o.goal()));
228         }
229         glEnd();
230         // Plot nodes
231         std::vector<RRTNode *> s; // DFS stack
232         std::vector<RRTNode *> r; // reset visited_
233         RRTNode *tmp;
234         glBegin(GL_LINES);
235         s.push_back(this->root_);
236         while (s.size() > 0) {
237                 tmp = s.back();
238                 s.pop_back();
239                 if (!tmp->visit()) {
240                         r.push_back(tmp);
241                         for (auto ch: tmp->children()) {
242                                 s.push_back(ch);
243                                 glColor3f(0.5, 0.5, 0.5);
244                                 glVertex2f(GLVERTEX(tmp));
245                                 glVertex2f(GLVERTEX(ch));
246                         }
247                 }
248         }
249         glEnd();
250         SDL_GL_SwapWindow(gw);
251         for (auto n: r)
252                 n->visit(false);
253         return true;
254 }
255
256 bool RRTBase::goal_found(
257                 RRTNode *node,
258                 float (*cost)(RRTNode *, RRTNode* ))
259 {
260         float xx = pow(node->x() - this->goal_->x(), 2);
261         float yy = pow(node->y() - this->goal_->y(), 2);
262         float dh = std::abs(node->h() - this->goal_->h());
263         if (pow(xx + yy, 0.5) < this->GOAL_FOUND_DISTANCE &&
264                         dh < this->GOAL_FOUND_ANGLE) {
265                 if (this->goal_found_) {
266                         if (node->ccost() + (*cost)(node, this->goal_) <
267                                         this->goal_->ccost()) {
268                                 RRTNode *op; // old parent
269                                 float oc; // old cumulative cost
270                                 float od; // old direct cost
271                                 op = this->goal_->parent();
272                                 oc = this->goal_->ccost();
273                                 od = this->goal_->dcost();
274                                 node->add_child(this->goal_,
275                                                 (*cost)(node, this->goal_));
276                                 if (this->collide(node, this->goal_)) {
277                                         node->children().pop_back();
278                                         this->goal_->parent(op);
279                                         this->goal_->ccost(oc);
280                                         this->goal_->dcost(od);
281                                 } else {
282                                         op->rem_child(this->goal_);
283                                         return true;
284                                 }
285                         } else {
286                                 return false;
287                         }
288                 } else {
289                         node->add_child(
290                                         this->goal_,
291                                         (*cost)(node, this->goal_));
292                         if (this->collide(node, this->goal_)) {
293                                 node->children().pop_back();
294                                 this->goal_->remove_parent();
295                                 return false;
296                         }
297                         this->goal_found_ = true;
298                         return true;
299                 }
300         }
301         return false;
302 }
303
304 bool RRTBase::collide(RRTNode *init, RRTNode *goal)
305 {
306         std::vector<RRTEdge *> edges;
307         RRTNode *tmp = goal;
308         volatile bool col = false;
309         unsigned int i;
310         while (tmp != init) {
311                 BicycleCar bc(tmp->x(), tmp->y(), tmp->h());
312                 std::vector<RRTEdge *> bcframe = bc.frame();
313                 #pragma omp parallel for reduction(|: col)
314                 for (i = 0; i < (*this->cobstacles_).size(); i++) {
315                         if ((*this->cobstacles_)[i].collide(tmp)) {
316                                 col = true;
317                         }
318                         // TODO collide with car frame
319                 }
320                 if (col) {
321                         for (auto e: bcframe) {
322                                 delete e->init();
323                                 delete e->goal();
324                                 delete e;
325                         }
326                         for (auto e: edges) {
327                                 delete e;
328                         }
329                         return true;
330                 }
331                 #pragma omp parallel for reduction(|: col)
332                 for (i = 0; i < (*this->sobstacles_).size(); i++) {
333                         for (auto &e: bcframe) {
334                                 if ((*this->sobstacles_)[i].collide(e)) {
335                                         col = true;
336                                 }
337                         }
338                 }
339                 if (col) {
340                         for (auto e: bcframe) {
341                                 delete e->init();
342                                 delete e->goal();
343                                 delete e;
344                         }
345                         for (auto e: edges) {
346                                 delete e;
347                         }
348                         return true;
349                 }
350                 if (!tmp->parent()) {
351                         break;
352                 }
353                 edges.push_back(new RRTEdge(tmp, tmp->parent()));
354                 tmp = tmp->parent();
355                 for (auto e: bcframe) {
356                         delete e->init();
357                         delete e->goal();
358                         delete e;
359                 }
360         }
361         for (auto &e: edges) {
362                 #pragma omp parallel for reduction(|: col)
363                 for (i = 0; i < (*this->cobstacles_).size(); i++) {
364                         if ((*this->cobstacles_)[i].collide(e)) {
365                                 col = true;
366                         }
367                 }
368                 if (col) {
369                         for (auto e: edges) {
370                                 delete e;
371                         }
372                         return true;
373                 }
374                 #pragma omp parallel for reduction(|: col)
375                 for (i = 0; i < (*this->sobstacles_).size(); i++) {
376                         if ((*this->sobstacles_)[i].collide(e)) {
377                                 col = true;
378                         }
379                 }
380                 if (col) {
381                         for (auto e: edges) {
382                                 delete e;
383                         }
384                         return true;
385                 }
386         }
387         for (auto e: edges) {
388                 delete e;
389         }
390         return false;
391 }
392
393 bool RRTBase::rebase(RRTNode *nr)
394 {
395         if (this->goal_ == nr || this->root_ == nr)
396                 return false;
397         std::vector<RRTNode *> s; // DFS stack
398         RRTNode *tmp;
399         unsigned int i = 0;
400         unsigned int to_del = 0;
401         int iy = 0;
402         s.push_back(this->root_);
403         while (s.size() > 0) {
404                 tmp = s.back();
405                 s.pop_back();
406                 for (auto ch: tmp->children()) {
407                         if (ch != nr)
408                                 s.push_back(ch);
409                 }
410                 to_del = this->nodes_.size();
411                 #pragma omp parallel for reduction(min: to_del)
412                 for (i = 0; i < this->nodes_.size(); i++) {
413                         if (this->nodes_[i] == tmp)
414                                 to_del = i;
415                 }
416                 if (to_del < this->nodes_.size())
417                         this->nodes_.erase(this->nodes_.begin() + to_del);
418 #if NNVERSION > 1
419                 iy = IYI(tmp->y());
420                 to_del = this->iy_[iy].size();
421                 #pragma omp parallel  for reduction(min: to_del)
422                 for (i = 0; i < this->iy_[iy].size(); i++) {
423                         if (this->iy_[iy][i] == tmp)
424                                 to_del = i;
425                 }
426                 if (to_del < this->iy_[iy].size())
427                         this->iy_[iy].erase(this->iy_[iy].begin() + to_del);
428 #endif
429                 this->dnodes().push_back(tmp);
430         }
431         this->root_ = nr;
432         this->root_->remove_parent();
433         return true;
434 }
435
436 std::vector<RRTNode *> RRTBase::findt()
437 {
438         return this->findt(this->goal_);
439 }
440
441 std::vector<RRTNode *> RRTBase::findt(RRTNode *n)
442 {
443         std::vector<RRTNode *> nodes;
444         if (!n->parent())
445                 return nodes;
446         RRTNode *tmp = n;
447         while (tmp) {
448                 nodes.push_back(tmp);
449                 tmp = tmp->parent();
450         }
451         return nodes;
452 }