]> rtime.felk.cvut.cz Git - hubacji1/iamcar.git/blob - base/rrtbase.cc
Add plot OpenGL RRTBase method
[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         std::vector<RRTNode *> s; // DFS stack
222         std::vector<RRTNode *> r; // reset visited_
223         RRTNode *tmp;
224         glClear(GL_COLOR_BUFFER_BIT);
225         glBegin(GL_LINES);
226         s.push_back(this->root_);
227         while (s.size() > 0) {
228                 tmp = s.back();
229                 s.pop_back();
230                 if (!tmp->visit()) {
231                         r.push_back(tmp);
232                         for (auto ch: tmp->children()) {
233                                 s.push_back(ch);
234                                 glColor3f(0.5, 0.5, 0.5);
235                                 glVertex2f(tmp->x() * GLPLWSCALE,
236                                                 tmp->y() * GLPLHSCALE);
237                                 glVertex2f(ch->x() * GLPLWSCALE,
238                                                 ch->y() *GLPLHSCALE);
239                         }
240                 }
241         }
242         glEnd();
243         SDL_GL_SwapWindow(gw);
244         for (auto n: r)
245                 n->visit(false);
246         return true;
247 }
248
249 bool RRTBase::goal_found(
250                 RRTNode *node,
251                 float (*cost)(RRTNode *, RRTNode* ))
252 {
253         float xx = pow(node->x() - this->goal_->x(), 2);
254         float yy = pow(node->y() - this->goal_->y(), 2);
255         float dh = std::abs(node->h() - this->goal_->h());
256         if (pow(xx + yy, 0.5) < this->GOAL_FOUND_DISTANCE &&
257                         dh < this->GOAL_FOUND_ANGLE) {
258                 if (this->goal_found_) {
259                         if (node->ccost() + (*cost)(node, this->goal_) <
260                                         this->goal_->ccost()) {
261                                 RRTNode *op; // old parent
262                                 float oc; // old cumulative cost
263                                 float od; // old direct cost
264                                 op = this->goal_->parent();
265                                 oc = this->goal_->ccost();
266                                 od = this->goal_->dcost();
267                                 node->add_child(this->goal_,
268                                                 (*cost)(node, this->goal_));
269                                 if (this->collide(node, this->goal_)) {
270                                         node->children().pop_back();
271                                         this->goal_->parent(op);
272                                         this->goal_->ccost(oc);
273                                         this->goal_->dcost(od);
274                                 } else {
275                                         op->rem_child(this->goal_);
276                                         return true;
277                                 }
278                         } else {
279                                 return false;
280                         }
281                 } else {
282                         node->add_child(
283                                         this->goal_,
284                                         (*cost)(node, this->goal_));
285                         if (this->collide(node, this->goal_)) {
286                                 node->children().pop_back();
287                                 this->goal_->remove_parent();
288                                 return false;
289                         }
290                         this->goal_found_ = true;
291                         return true;
292                 }
293         }
294         return false;
295 }
296
297 bool RRTBase::collide(RRTNode *init, RRTNode *goal)
298 {
299         std::vector<RRTEdge *> edges;
300         RRTNode *tmp = goal;
301         volatile bool col = false;
302         unsigned int i;
303         while (tmp != init) {
304                 BicycleCar bc(tmp->x(), tmp->y(), tmp->h());
305                 std::vector<RRTEdge *> bcframe = bc.frame();
306                 #pragma omp parallel for reduction(|: col)
307                 for (i = 0; i < (*this->cobstacles_).size(); i++) {
308                         if ((*this->cobstacles_)[i].collide(tmp)) {
309                                 col = true;
310                         }
311                         // TODO collide with car frame
312                 }
313                 if (col) {
314                         for (auto e: bcframe) {
315                                 delete e->init();
316                                 delete e->goal();
317                                 delete e;
318                         }
319                         for (auto e: edges) {
320                                 delete e;
321                         }
322                         return true;
323                 }
324                 #pragma omp parallel for reduction(|: col)
325                 for (i = 0; i < (*this->sobstacles_).size(); i++) {
326                         for (auto &e: bcframe) {
327                                 if ((*this->sobstacles_)[i].collide(e)) {
328                                         col = true;
329                                 }
330                         }
331                 }
332                 if (col) {
333                         for (auto e: bcframe) {
334                                 delete e->init();
335                                 delete e->goal();
336                                 delete e;
337                         }
338                         for (auto e: edges) {
339                                 delete e;
340                         }
341                         return true;
342                 }
343                 if (!tmp->parent()) {
344                         break;
345                 }
346                 edges.push_back(new RRTEdge(tmp, tmp->parent()));
347                 tmp = tmp->parent();
348                 for (auto e: bcframe) {
349                         delete e->init();
350                         delete e->goal();
351                         delete e;
352                 }
353         }
354         for (auto &e: edges) {
355                 #pragma omp parallel for reduction(|: col)
356                 for (i = 0; i < (*this->cobstacles_).size(); i++) {
357                         if ((*this->cobstacles_)[i].collide(e)) {
358                                 col = true;
359                         }
360                 }
361                 if (col) {
362                         for (auto e: edges) {
363                                 delete e;
364                         }
365                         return true;
366                 }
367                 #pragma omp parallel for reduction(|: col)
368                 for (i = 0; i < (*this->sobstacles_).size(); i++) {
369                         if ((*this->sobstacles_)[i].collide(e)) {
370                                 col = true;
371                         }
372                 }
373                 if (col) {
374                         for (auto e: edges) {
375                                 delete e;
376                         }
377                         return true;
378                 }
379         }
380         for (auto e: edges) {
381                 delete e;
382         }
383         return false;
384 }
385
386 bool RRTBase::rebase(RRTNode *nr)
387 {
388         if (this->goal_ == nr || this->root_ == nr)
389                 return false;
390         std::vector<RRTNode *> s; // DFS stack
391         RRTNode *tmp;
392         unsigned int i = 0;
393         unsigned int to_del = 0;
394         int iy = 0;
395         s.push_back(this->root_);
396         while (s.size() > 0) {
397                 tmp = s.back();
398                 s.pop_back();
399                 for (auto ch: tmp->children()) {
400                         if (ch != nr)
401                                 s.push_back(ch);
402                 }
403                 to_del = this->nodes_.size();
404                 #pragma omp parallel for reduction(min: to_del)
405                 for (i = 0; i < this->nodes_.size(); i++) {
406                         if (this->nodes_[i] == tmp)
407                                 to_del = i;
408                 }
409                 if (to_del < this->nodes_.size())
410                         this->nodes_.erase(this->nodes_.begin() + to_del);
411 #if NNVERSION > 1
412                 iy = IYI(tmp->y());
413                 to_del = this->iy_[iy].size();
414                 #pragma omp parallel  for reduction(min: to_del)
415                 for (i = 0; i < this->iy_[iy].size(); i++) {
416                         if (this->iy_[iy][i] == tmp)
417                                 to_del = i;
418                 }
419                 if (to_del < this->iy_[iy].size())
420                         this->iy_[iy].erase(this->iy_[iy].begin() + to_del);
421 #endif
422                 this->dnodes().push_back(tmp);
423         }
424         this->root_ = nr;
425         this->root_->remove_parent();
426         return true;
427 }
428
429 std::vector<RRTNode *> RRTBase::findt()
430 {
431         return this->findt(this->goal_);
432 }
433
434 std::vector<RRTNode *> RRTBase::findt(RRTNode *n)
435 {
436         std::vector<RRTNode *> nodes;
437         if (!n->parent())
438                 return nodes;
439         RRTNode *tmp = n;
440         while (tmp) {
441                 nodes.push_back(tmp);
442                 tmp = tmp->parent();
443         }
444         return nodes;
445 }