Loading...
Searching...
No Matches
PlannerData.cpp
1/*********************************************************************
2 * Software License Agreement (BSD License)
3 *
4 * Copyright (c) 2011, Rice University
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * * Redistributions in binary form must reproduce the above
14 * copyright notice, this list of conditions and the following
15 * disclaimer in the documentation and/or other materials provided
16 * with the distribution.
17 * * Neither the name of the Rice University nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32 * POSSIBILITY OF SUCH DAMAGE.
33 *********************************************************************/
34
35/* Author: Ryan Luna */
36
37#include "ompl/base/PlannerData.h"
38#include "ompl/base/PlannerDataGraph.h"
39#include "ompl/base/StateStorage.h"
40#include "ompl/base/OptimizationObjective.h"
41#include "ompl/base/objectives/PathLengthOptimizationObjective.h"
42#include "ompl/base/ScopedState.h"
43
44#include <boost/graph/graphviz.hpp>
45#include <boost/graph/graphml.hpp>
46#include <boost/graph/dijkstra_shortest_paths.hpp>
47#include <boost/property_map/function_property_map.hpp>
48#include <utility>
49
50// This is a convenient macro to cast the void* graph pointer as the
51// Boost.Graph structure from PlannerDataGraph.h
52#define graph_ (reinterpret_cast<ompl::base::PlannerData::Graph *>(graphRaw_))
53
56const unsigned int ompl::base::PlannerData::INVALID_INDEX = std::numeric_limits<unsigned int>::max();
57
58ompl::base::PlannerData::PlannerData(SpaceInformationPtr si) : si_(std::move(si))
59{
60 graphRaw_ = new Graph();
61}
62
64{
65 freeMemory();
66
67 if (graph_)
68 {
69 delete graph_;
70 graphRaw_ = nullptr;
71 }
72}
73
75{
76 freeMemory();
77 decoupledStates_.clear();
78}
79
81{
82 for (unsigned int i = 0; i < numVertices(); ++i)
83 {
85 // If this vertex's state is not in the decoupled list, clone it and add it
86 if (decoupledStates_.find(const_cast<State *>(vtx.getState())) == decoupledStates_.end())
87 {
88 const State *oldState = vtx.getState();
89 State *clone = si_->cloneState(oldState);
90 decoupledStates_.insert(clone);
91 // Replacing the shallow state pointer with our shiny new clone
92 vtx.state_ = clone;
93
94 // Remove oldState from stateIndexMap
95 stateIndexMap_.erase(oldState);
96 // Add the new, cloned state to stateIndexMap
97 stateIndexMap_[clone] = i;
98 }
99 }
100}
101
102unsigned int ompl::base::PlannerData::getEdges(unsigned int v, std::vector<unsigned int> &edgeList) const
103{
104 std::pair<Graph::AdjIterator, Graph::AdjIterator> iterators =
105 boost::adjacent_vertices(boost::vertex(v, *graph_), *graph_);
106
107 edgeList.clear();
108 boost::property_map<Graph::Type, boost::vertex_index_t>::type vertices = get(boost::vertex_index, *graph_);
109 for (Graph::AdjIterator iter = iterators.first; iter != iterators.second; ++iter)
110 edgeList.push_back(vertices[*iter]);
111
112 return edgeList.size();
113}
114
115unsigned int ompl::base::PlannerData::getEdges(unsigned int v,
116 std::map<unsigned int, const PlannerDataEdge *> &edgeMap) const
117{
118 std::pair<Graph::OEIterator, Graph::OEIterator> iterators = boost::out_edges(boost::vertex(v, *graph_), *graph_);
119
120 edgeMap.clear();
121 boost::property_map<Graph::Type, edge_type_t>::type edges = get(edge_type_t(), *graph_);
122 boost::property_map<Graph::Type, boost::vertex_index_t>::type vertices = get(boost::vertex_index, *graph_);
123 for (Graph::OEIterator iter = iterators.first; iter != iterators.second; ++iter)
124 edgeMap[vertices[boost::target(*iter, *graph_)]] = boost::get(edges, *iter);
125
126 return edgeMap.size();
127}
128
129unsigned int ompl::base::PlannerData::getIncomingEdges(unsigned int v, std::vector<unsigned int> &edgeList) const
130{
131 std::pair<Graph::IEIterator, Graph::IEIterator> iterators = boost::in_edges(boost::vertex(v, *graph_), *graph_);
132
133 edgeList.clear();
134 boost::property_map<Graph::Type, boost::vertex_index_t>::type vertices = get(boost::vertex_index, *graph_);
135 for (Graph::IEIterator iter = iterators.first; iter != iterators.second; ++iter)
136 edgeList.push_back(vertices[boost::source(*iter, *graph_)]);
137
138 return edgeList.size();
139}
140
142 std::map<unsigned int, const PlannerDataEdge *> &edgeMap) const
143{
144 std::pair<Graph::IEIterator, Graph::IEIterator> iterators = boost::in_edges(boost::vertex(v, *graph_), *graph_);
145
146 edgeMap.clear();
147 boost::property_map<Graph::Type, edge_type_t>::type edges = get(edge_type_t(), *graph_);
148 boost::property_map<Graph::Type, boost::vertex_index_t>::type vertices = get(boost::vertex_index, *graph_);
149 for (Graph::IEIterator iter = iterators.first; iter != iterators.second; ++iter)
150 edgeMap[vertices[boost::source(*iter, *graph_)]] = boost::get(edges, *iter);
151
152 return edgeMap.size();
153}
154
155bool ompl::base::PlannerData::getEdgeWeight(unsigned int v1, unsigned int v2, Cost *weight) const
156{
157 Graph::Edge e;
158 bool exists;
159 boost::tie(e, exists) = boost::edge(boost::vertex(v1, *graph_), boost::vertex(v2, *graph_), *graph_);
160
161 if (exists)
162 {
163 boost::property_map<Graph::Type, boost::edge_weight_t>::type edges = get(boost::edge_weight, *graph_);
164 *weight = edges[e];
165 return true;
166 }
167
168 return false;
169}
170
171bool ompl::base::PlannerData::setEdgeWeight(unsigned int v1, unsigned int v2, Cost weight)
172{
173 Graph::Edge e;
174 bool exists;
175 boost::tie(e, exists) = boost::edge(boost::vertex(v1, *graph_), boost::vertex(v2, *graph_), *graph_);
176
177 if (exists)
178 {
179 boost::property_map<Graph::Type, boost::edge_weight_t>::type edges = get(boost::edge_weight, *graph_);
180 edges[e] = weight;
181 }
182
183 return exists;
184}
185
186bool ompl::base::PlannerData::edgeExists(unsigned int v1, unsigned int v2) const
187{
188 Graph::Edge e;
189 bool exists;
190
191 boost::tie(e, exists) = boost::edge(boost::vertex(v1, *graph_), boost::vertex(v2, *graph_), *graph_);
192 return exists;
193}
194
199
201{
202 return boost::num_vertices(*graph_);
203}
204
206{
207 return boost::num_edges(*graph_);
208}
209
211{
212 if (index >= boost::num_vertices(*graph_))
213 return NO_VERTEX;
214
215 boost::property_map<Graph::Type, vertex_type_t>::type vertices = get(vertex_type_t(), *graph_);
216 return *(vertices[boost::vertex(index, *graph_)]);
217}
218
220{
221 if (index >= boost::num_vertices(*graph_))
222 return const_cast<ompl::base::PlannerDataVertex &>(NO_VERTEX);
223
224 boost::property_map<Graph::Type, vertex_type_t>::type vertices = get(vertex_type_t(), *graph_);
225 return *(vertices[boost::vertex(index, *graph_)]);
226}
227
228const ompl::base::PlannerDataEdge &ompl::base::PlannerData::getEdge(unsigned int v1, unsigned int v2) const
229{
230 Graph::Edge e;
231 bool exists;
232 boost::tie(e, exists) = boost::edge(boost::vertex(v1, *graph_), boost::vertex(v2, *graph_), *graph_);
233
234 if (exists)
235 {
236 boost::property_map<Graph::Type, edge_type_t>::type edges = get(edge_type_t(), *graph_);
237 return *(boost::get(edges, e));
238 }
239
240 return NO_EDGE;
241}
242
244{
245 Graph::Edge e;
246 bool exists;
247 boost::tie(e, exists) = boost::edge(boost::vertex(v1, *graph_), boost::vertex(v2, *graph_), *graph_);
248
249 if (exists)
250 {
251 boost::property_map<Graph::Type, edge_type_t>::type edges = get(edge_type_t(), *graph_);
252 return *(boost::get(edges, e));
253 }
254
255 return const_cast<ompl::base::PlannerDataEdge &>(NO_EDGE);
256}
257
258void ompl::base::PlannerData::printGraphviz(std::ostream &out) const
259{
260 boost::write_graphviz(out, *graph_);
261}
262
263namespace
264{
265 // Property map for extracting states as arrays of doubles
266 std::string vertexCoords(ompl::base::PlannerData::Graph::Type &g, ompl::base::ScopedState<> &s,
267 ompl::base::PlannerData::Graph::Vertex v)
268 {
269 s = *get(vertex_type_t(), g)[v]->getState();
270 std::vector<double> coords(s.reals());
271 std::ostringstream sstream;
272 if (!coords.empty())
273 {
274 sstream << coords[0];
275 for (std::size_t i = 1; i < coords.size(); ++i)
276 sstream << ',' << coords[i];
277 }
278 return sstream.str();
279 }
280} // namespace
281
282void ompl::base::PlannerData::printGraphML(std::ostream &out) const
283{
284 // For some reason, make_function_property_map can't infer its
285 // template arguments corresponding to edgeWeightAsDouble's type
286 // signature. So, we have to use this horribly verbose
287 // instantiation of the property map.
288 //
289 // \todo Can we use make_function_property_map() here and have it
290 // infer the property template arguments?
291 using Edge = ompl::base::PlannerData::Graph::Edge;
292 boost::function_property_map<std::function<double(Edge)>, Edge> weightmap(
293 [this](Edge e) { return get(boost::edge_weight_t(), *graph_)[e].value(); });
295 using Vertex = ompl::base::PlannerData::Graph::Vertex;
296 boost::function_property_map<std::function<std::string(Vertex)>, Vertex> coordsmap(
297 [this, &s](Vertex v) { return vertexCoords(*graph_, s, v); });
298
299 // Not writing vertex or edge structures.
300 boost::dynamic_properties dp;
301 dp.property("weight", weightmap);
302 dp.property("coords", coordsmap);
303
304 boost::write_graphml(out, *graph_, dp);
305}
306
308{
309 auto it = stateIndexMap_.find(v.getState());
310 if (it != stateIndexMap_.end())
311 return it->second;
312 return INVALID_INDEX;
313}
314
316{
317 return startVertexIndices_.size();
318}
319
321{
322 return goalVertexIndices_.size();
323}
324
325unsigned int ompl::base::PlannerData::getStartIndex(unsigned int i) const
326{
327 if (i >= startVertexIndices_.size())
328 return INVALID_INDEX;
329
330 return startVertexIndices_[i];
331}
332
333unsigned int ompl::base::PlannerData::getGoalIndex(unsigned int i) const
334{
335 if (i >= goalVertexIndices_.size())
336 return INVALID_INDEX;
337
338 return goalVertexIndices_[i];
339}
340
341bool ompl::base::PlannerData::isStartVertex(unsigned int index) const
342{
343 return std::binary_search(startVertexIndices_.begin(), startVertexIndices_.end(), index);
344}
345
346bool ompl::base::PlannerData::isGoalVertex(unsigned int index) const
347{
348 return std::binary_search(goalVertexIndices_.begin(), goalVertexIndices_.end(), index);
349}
350
352{
353 if (i >= startVertexIndices_.size())
354 return NO_VERTEX;
355
357}
358
366
368{
369 if (i >= goalVertexIndices_.size())
370 return NO_VERTEX;
371
372 return getVertex(goalVertexIndices_[i]);
373}
374
382
384{
385 // Do not add vertices with null states
386 if (st.getState() == nullptr)
387 return INVALID_INDEX;
388
389 unsigned int index = vertexIndex(st);
390 if (index == INVALID_INDEX) // Vertex does not already exist
391 {
392 // Clone the state to prevent object slicing when retrieving this object
394 Graph::Vertex v = boost::add_vertex(clone, *graph_);
395 boost::property_map<Graph::Type, boost::vertex_index_t>::type vertexIndexMap =
396 get(boost::vertex_index, *graph_);
397
398 // Insert this entry into the stateIndexMap_ for fast lookup
399 stateIndexMap_[clone->getState()] = numVertices() - 1;
400 return vertexIndexMap[v];
401 }
402 return index;
403}
404
406{
407 unsigned int index = addVertex(v);
408 if (index != INVALID_INDEX)
410
411 return index;
412}
413
415{
416 unsigned int index = addVertex(v);
417
418 if (index != INVALID_INDEX)
420
421 return index;
422}
423
424bool ompl::base::PlannerData::addEdge(unsigned int v1, unsigned int v2, const PlannerDataEdge &edge, Cost weight)
425{
426 // If either of the vertices do not exist, don't add an edge
427 if (v1 >= numVertices() || v2 >= numVertices())
428 return false;
429
430 // If an edge already exists, do not add one
431 if (edgeExists(v1, v2))
432 return false;
433
434 // Clone the edge to prevent object slicing
435 ompl::base::PlannerDataEdge *clone = edge.clone();
436 const Graph::edge_property_type properties(clone, weight);
437
438 Graph::Edge e;
439 bool added = false;
440 tie(e, added) = boost::add_edge(boost::vertex(v1, *graph_), boost::vertex(v2, *graph_), properties, *graph_);
441
442 if (!added)
443 delete clone;
444
445 return added;
446}
447
449 const PlannerDataEdge &edge, Cost weight)
450{
451 unsigned int index1 = addVertex(v1);
452 unsigned int index2 = addVertex(v2);
453
454 // If neither vertex was added or already exists, return false
455 if (index1 == INVALID_INDEX && index2 == INVALID_INDEX)
456 return false;
457
458 // Only add the edge if both vertices exist
459 if (index1 != INVALID_INDEX && index2 != INVALID_INDEX)
460 return addEdge(index1, index2, edge, weight);
461
462 return true;
463}
464
466{
467 unsigned int index = vertexIndex(st);
468 if (index != INVALID_INDEX)
469 return removeVertex(index);
470 return false;
471}
472
474{
475 if (vIndex >= boost::num_vertices(*graph_))
476 return false;
477
478 // Retrieve a list of all edge structures
479 boost::property_map<Graph::Type, edge_type_t>::type edgePropertyMap = get(edge_type_t(), *graph_);
480
481 // Freeing memory associated with outgoing edges of this vertex
482 std::pair<Graph::OEIterator, Graph::OEIterator> oiterators =
483 boost::out_edges(boost::vertex(vIndex, *graph_), *graph_);
484 for (Graph::OEIterator iter = oiterators.first; iter != oiterators.second; ++iter)
485 delete edgePropertyMap[*iter];
486
487 // Freeing memory associated with incoming edges of this vertex
488 std::pair<Graph::IEIterator, Graph::IEIterator> initerators =
489 boost::in_edges(boost::vertex(vIndex, *graph_), *graph_);
490 for (Graph::IEIterator iter = initerators.first; iter != initerators.second; ++iter)
491 delete edgePropertyMap[*iter];
492
493 // Remove this vertex from stateIndexMap_, and update the map
494 stateIndexMap_.erase(getVertex(vIndex).getState());
495 boost::property_map<Graph::Type, vertex_type_t>::type vertices = get(vertex_type_t(), *graph_);
496 for (unsigned int i = vIndex + 1; i < boost::num_vertices(*graph_); ++i)
497 stateIndexMap_[vertices[boost::vertex(i, *graph_)]->getState()]--;
498
499 // Remove this vertex from the start and/or goal index list, if it exists. Update the lists.
500 auto it = std::find(startVertexIndices_.begin(), startVertexIndices_.end(), vIndex);
501 if (it != startVertexIndices_.end())
502 startVertexIndices_.erase(it);
503 for (unsigned int &startVertexIndex : startVertexIndices_)
504 if (startVertexIndex > vIndex)
505 startVertexIndex--;
506
507 it = std::find(goalVertexIndices_.begin(), goalVertexIndices_.end(), vIndex);
508 if (it != goalVertexIndices_.end())
509 goalVertexIndices_.erase(it);
510 for (unsigned int &goalVertexIndex : goalVertexIndices_)
511 if (goalVertexIndex > vIndex)
512 goalVertexIndex--;
513
514 // If the state attached to this vertex was decoupled, free it here
515 auto *vtxState = const_cast<State *>(getVertex(vIndex).getState());
516 if (decoupledStates_.find(vtxState) != decoupledStates_.end())
517 {
518 decoupledStates_.erase(vtxState);
519 si_->freeState(vtxState);
520 vtxState = nullptr;
521 }
522
523 // Slay the vertex
524 boost::clear_vertex(boost::vertex(vIndex, *graph_), *graph_);
525 boost::property_map<Graph::Type, vertex_type_t>::type vertexTypeMap = get(vertex_type_t(), *graph_);
526 delete vertexTypeMap[boost::vertex(vIndex, *graph_)];
527 boost::remove_vertex(boost::vertex(vIndex, *graph_), *graph_);
528
529 return true;
530}
531
532bool ompl::base::PlannerData::removeEdge(unsigned int v1, unsigned int v2)
533{
534 Graph::Edge e;
535 bool exists;
536 boost::tie(e, exists) = boost::edge(boost::vertex(v1, *graph_), boost::vertex(v2, *graph_), *graph_);
537
538 if (!exists)
539 return false;
540
541 // Freeing memory associated with this edge
542 boost::property_map<Graph::Type, edge_type_t>::type edges = get(edge_type_t(), *graph_);
543 delete edges[e];
544
545 boost::remove_edge(boost::vertex(v1, *graph_), boost::vertex(v2, *graph_), *graph_);
546 return true;
547}
548
550{
551 unsigned int index1, index2;
552 index1 = vertexIndex(v1);
553 index2 = vertexIndex(v2);
554
555 if (index1 == INVALID_INDEX || index2 == INVALID_INDEX)
556 return false;
557
558 return removeEdge(index1, index2);
559}
560
562{
563 std::map<const State *, unsigned int>::const_iterator it = stateIndexMap_.find(st);
564 if (it != stateIndexMap_.end())
565 {
566 getVertex(it->second).setTag(tag);
567 return true;
568 }
569 return false;
570}
571
573{
574 // Find the index in the stateIndexMap_
575 std::map<const State *, unsigned int>::const_iterator it = stateIndexMap_.find(st);
576 if (it != stateIndexMap_.end())
577 {
578 if (!isStartVertex(it->second))
579 {
580 startVertexIndices_.push_back(it->second);
581 // Sort the indices for quick lookup
582 std::sort(startVertexIndices_.begin(), startVertexIndices_.end());
583 }
584 return true;
585 }
586 return false;
587}
588
590{
591 // Find the index in the stateIndexMap_
592 std::map<const State *, unsigned int>::const_iterator it = stateIndexMap_.find(st);
593 if (it != stateIndexMap_.end())
594 {
595 if (!isGoalVertex(it->second))
596 {
597 goalVertexIndices_.push_back(it->second);
598 // Sort the indices for quick lookup
599 std::sort(startVertexIndices_.begin(), startVertexIndices_.end());
600 }
601 return true;
602 }
603 return false;
604}
605
607{
608 unsigned int nv = numVertices();
609 for (unsigned int i = 0; i < nv; ++i)
610 {
611 std::map<unsigned int, const PlannerDataEdge *> nbrs;
612 getEdges(i, nbrs);
613
614 std::map<unsigned int, const PlannerDataEdge *>::const_iterator it;
615 for (it = nbrs.begin(); it != nbrs.end(); ++it)
616 {
617 setEdgeWeight(i, it->first, opt.motionCost(getVertex(i).getState(), getVertex(it->first).getState()));
618 }
619 }
620}
621
623{
624 // Create a PathLengthOptimizationObjective to compute the edge
625 // weights according to state space distance
628}
629
631 base::PlannerData &mst) const
632{
633 std::vector<ompl::base::PlannerData::Graph::Vertex> pred(numVertices());
634
635 // This is how boost's minimum spanning tree is actually
636 // implemented, except it lacks the generality for specifying our
637 // own comparison function or zero/inf values.
638 //
639 // \todo Once (https://svn.boost.org/trac/boost/ticket/9368) gets
640 // into boost we can use the far more direct
641 // boost::prim_minimum_spanning_tree().
642 boost::dijkstra_shortest_paths(
643 *graph_, v,
644 boost::predecessor_map(&pred[0])
645 .distance_compare([&opt](Cost c1, Cost c2) { return opt.isCostBetterThan(c1, c2); })
646 .distance_combine([](Cost, Cost c) { return c; })
647 .distance_inf(opt.infiniteCost())
648 .distance_zero(opt.identityCost()));
649
650 // Adding vertices to MST
651 for (std::size_t i = 0; i < pred.size(); ++i)
652 {
653 if (isStartVertex(i))
655 else if (isGoalVertex(i))
656 mst.addGoalVertex(getVertex(i));
657 else
658 mst.addVertex(getVertex(i));
659 }
660
661 // Adding edges to MST
662 for (std::size_t i = 0; i < pred.size(); ++i)
663 {
664 if (pred[i] != i)
665 {
666 Cost c;
667 getEdgeWeight(pred[i], i, &c);
668 mst.addEdge(pred[i], i, getEdge(pred[i], i), c);
669 }
670 }
671}
672
674{
675 // If this vertex already exists in data, return
676 if (data.vertexExists(getVertex(v)))
677 return;
678
679 // Adding the vertex corresponding to v into data
680 unsigned int idx;
681 if (isStartVertex(v))
682 idx = data.addStartVertex(getVertex(v));
683 else if (isGoalVertex(v))
684 idx = data.addGoalVertex(getVertex(v));
685 else
686 idx = data.addVertex(getVertex(v));
687
688 assert(idx != INVALID_INDEX);
689
690 std::map<unsigned int, const PlannerDataEdge *> neighbors;
691 getEdges(v, neighbors);
692
693 // Depth-first traversal of reachable graph
694 std::map<unsigned int, const PlannerDataEdge *>::iterator it;
695 for (auto &it : neighbors)
696 {
697 extractReachable(it.first, data);
698 Cost weight;
699 getEdgeWeight(v, it.first, &weight);
700 data.addEdge(idx, data.vertexIndex(getVertex(it.first)), *it.second, weight);
701 }
702}
703
704ompl::base::StateStoragePtr ompl::base::PlannerData::extractStateStorage() const
705{
706 auto store(std::make_shared<GraphStateStorage>(si_->getStateSpace()));
707 if (graph_)
708 {
709 // copy the states
710 std::map<unsigned int, unsigned int> indexMap;
711 for (const auto &it : stateIndexMap_)
712 {
713 indexMap[it.second] = store->size();
714 store->addState(it.first);
715 }
716
717 // add the edges
718 for (const auto &it : indexMap)
719 {
720 std::vector<unsigned int> edgeList;
721 getEdges(it.first, edgeList);
722 GraphStateStorage::MetadataType &md = store->getMetadata(it.second);
723 md.resize(edgeList.size());
724 // map node indices to index values in StateStorage
725 for (std::size_t k = 0; k < edgeList.size(); ++k)
726 md[k] = indexMap[edgeList[k]];
727 }
728 }
729 return store;
730}
731
733{
734 auto *boostgraph = reinterpret_cast<ompl::base::PlannerData::Graph *>(graphRaw_);
735 return *boostgraph;
736}
737
739{
740 const auto *boostgraph = reinterpret_cast<const ompl::base::PlannerData::Graph *>(graphRaw_);
741 return *boostgraph;
742}
743
744const ompl::base::SpaceInformationPtr &ompl::base::PlannerData::getSpaceInformation() const
745{
746 return si_;
747}
748
749void ompl::base::PlannerData::freeMemory()
750{
751 // Freeing decoupled states, if any
752 for (auto decoupledState : decoupledStates_)
753 si_->freeState(decoupledState);
754
755 if (graph_)
756 {
757 std::pair<Graph::EIterator, Graph::EIterator> eiterators = boost::edges(*graph_);
758 boost::property_map<Graph::Type, edge_type_t>::type edges = get(edge_type_t(), *graph_);
759 for (Graph::EIterator iter = eiterators.first; iter != eiterators.second; ++iter)
760 delete boost::get(edges, *iter);
761
762 std::pair<Graph::VIterator, Graph::VIterator> viterators = boost::vertices(*graph_);
763 boost::property_map<Graph::Type, vertex_type_t>::type vertices = get(vertex_type_t(), *graph_);
764 for (Graph::VIterator iter = viterators.first; iter != viterators.second; ++iter)
765 delete vertices[*iter];
766
767 graph_->clear();
768 }
769}
770
772{
773 return false;
774}
775
776void ompl::base::PlannerData::printPLY(std::ostream &out, const bool asIs) const
777{
778 const base::StateSpace *space(si_->getStateSpace().get());
779
780 unsigned int dim = space->getDimension();
781 if (dim > 3)
782 throw Exception("Cannot output mesh of path in more than 3 dimensions!");
783
784 std::vector<double> reals;
785 std::stringstream v, f;
786 std::size_t vcount = 0;
787 std::size_t fcount = 0;
788
789 auto stateOutput = [&](const ompl::base::State *state)
790 {
791 space->copyToReals(reals, state);
792 std::copy(reals.begin(), reals.end(), std::ostream_iterator<double>(v, " "));
793 v << std::endl;
794 };
795
796 const Graph &graph = toBoostGraph();
797
798 BGL_FORALL_EDGES(edge, graph, PlannerData::Graph)
799 {
800 std::vector<ompl::base::State *> stateList;
801 const State *source = boost::get(vertex_type, graph, boost::source(edge, graph))->getState();
802 const State *target = boost::get(vertex_type, graph, boost::target(edge, graph))->getState();
803
804 unsigned int n = 0;
805 if (!asIs)
806 n = si_->getStateSpace()->validSegmentCount(source, target);
807 si_->getMotionStates(source, target, stateList, n, true, true);
808
809 stateOutput(stateList[0]);
810 vcount++;
811 for (std::size_t i = 1; i < stateList.size(); i++)
812 {
813 stateOutput(stateList[i]);
814 stateOutput(stateList[i - 1]);
815 vcount += 2;
816 f << 3 << " " << vcount - 3 << " " << vcount - 2 << " " << vcount - 1 << "\n";
817 fcount++;
818 si_->freeState(stateList[i - 1]);
819 }
820 si_->freeState(stateList.back());
821 }
822
823 out << "ply\n";
824 out << "format ascii 1.0\n";
825 out << "element vertex " << vcount << "\n";
826 out << "property float x\n";
827
828 if (dim > 1)
829 out << "property float y\n";
830
831 if (dim > 2)
832 out << "property float z\n";
833
834 out << "element face " << fcount << "\n";
835 out << "property list uchar int vertex_index\n";
836 out << "end_header\n";
837 out << v.str() << f.str();
838}
The exception type for ompl.
Definition Exception.h:47
Definition of a cost value. Can represent the cost of a motion or the cost of a state.
Definition Cost.h:48
Abstract definition of optimization objectives.
virtual Cost identityCost() const
Get the identity cost value. The identity cost value is the cost c_i such that, for all costs c,...
virtual bool isCostBetterThan(Cost c1, Cost c2) const
Check whether the the cost c1 is considered better than the cost c2. By default, this returns true if...
virtual Cost motionCost(const State *s1, const State *s2) const =0
Get the cost that corresponds to the motion segment between s1 and s2.
virtual Cost infiniteCost() const
Get a cost which is greater than all other costs in this OptimizationObjective; required for use in D...
An optimization objective which corresponds to optimizing path length.
Base class for a PlannerData edge.
virtual PlannerDataEdge * clone() const
Return a clone of this object, allocated from the heap.
Base class for a vertex in the PlannerData structure. All derived classes must implement the clone an...
Definition PlannerData.h:59
const State * state_
The state represented by this vertex.
virtual PlannerDataVertex * clone() const
Return a clone of this object, allocated from the heap.
Definition PlannerData.h:86
virtual const State * getState() const
Retrieve the state associated with this vertex.
Definition PlannerData.h:80
Wrapper class for the Boost.Graph representation of the PlannerData. This class inherits from a boost...
Object containing planner generated vertex and edge data. It is assumed that all vertices are unique,...
bool getEdgeWeight(unsigned int v1, unsigned int v2, Cost *weight) const
Returns the weight of the edge between the given vertex indices. If there exists an edge between v1 a...
unsigned int vertexIndex(const PlannerDataVertex &v) const
Return the index for the vertex associated with the given data. INVALID_INDEX is returned if this ver...
bool setEdgeWeight(unsigned int v1, unsigned int v2, Cost weight)
Sets the weight of the edge between the given vertex indices. If an edge between v1 and v2 does not e...
bool edgeExists(unsigned int v1, unsigned int v2) const
Check whether an edge between vertex index v1 and index v2 exists.
bool isGoalVertex(unsigned int index) const
Returns true if the given vertex index is marked as a goal vertex.
void printGraphviz(std::ostream &out=std::cout) const
Writes a Graphviz dot file of this structure to the given stream.
std::map< const State *, unsigned int > stateIndexMap_
A mapping of states to vertex indexes. For fast lookup of vertex index.
unsigned int getStartIndex(unsigned int i) const
Returns the index of the ith start state. INVALID_INDEX is returned if i is out of range....
void computeEdgeWeights()
Computes all edge weights using state space distance (i.e. getSpaceInformation()->distance()).
const SpaceInformationPtr & getSpaceInformation() const
Return the instance of SpaceInformation used in this PlannerData.
bool tagState(const State *st, int tag)
Set the integer tag associated with the given state. If the given state does not exist in a vertex,...
unsigned int addStartVertex(const PlannerDataVertex &v)
Adds the given vertex to the graph data, and marks it as a start vertex. The vertex index is returned...
unsigned int addGoalVertex(const PlannerDataVertex &v)
Adds the given vertex to the graph data, and marks it as a start vertex. The vertex index is returned...
unsigned int numEdges() const
Retrieve the number of edges in this structure.
StateStoragePtr extractStateStorage() const
Extract a ompl::base::GraphStateStorage object from this PlannerData. Memory for states is copied (th...
bool markStartState(const State *st)
Mark the given state as a start vertex. If the given state does not exist in a vertex,...
static const PlannerDataVertex NO_VERTEX
Representation for a non-existant vertex.
std::vector< unsigned int > startVertexIndices_
A mutable listing of the vertices marked as start states. Stored in sorted order.
static const PlannerDataEdge NO_EDGE
Representation for a non-existant edge.
virtual void clear()
Clears the entire data structure.
virtual bool removeVertex(const PlannerDataVertex &st)
Removes the vertex associated with the given data. If the vertex does not exist, false is returned....
bool markGoalState(const State *st)
Mark the given state as a goal vertex. If the given state does not exist in a vertex,...
unsigned int getIncomingEdges(unsigned int v, std::vector< unsigned int > &edgeList) const
Returns a list of vertices with outgoing edges to the vertex with index v. The number of edges connec...
unsigned int numVertices() const
Retrieve the number of vertices in this structure.
std::set< State * > decoupledStates_
A list of states that are allocated during the decoupleFromPlanner method. These states are freed by ...
Graph & toBoostGraph()
Extract a Boost.Graph object from this PlannerData.
virtual bool removeEdge(unsigned int v1, unsigned int v2)
Removes the edge between vertex indexes v1 and v2. Success is returned.
SpaceInformationPtr si_
The space information instance for this data.
unsigned int numStartVertices() const
Returns the number of start vertices.
unsigned int getEdges(unsigned int v, std::vector< unsigned int > &edgeList) const
Returns a list of the vertex indexes directly connected to vertex with index v (outgoing edges)....
void extractMinimumSpanningTree(unsigned int v, const OptimizationObjective &opt, PlannerData &mst) const
Extracts the minimum spanning tree of the data rooted at the vertex with index v. The minimum spannin...
const PlannerDataEdge & getEdge(unsigned int v1, unsigned int v2) const
Retrieve a reference to the edge object connecting vertices with indexes v1 and v2....
void printPLY(std::ostream &out, bool asIs=false) const
Write a mesh of the planner graph to a stream. Insert additional vertices if asIs == true.
static const unsigned int INVALID_INDEX
Representation of an invalid vertex index.
const PlannerDataVertex & getStartVertex(unsigned int i) const
Retrieve a reference to the ith start vertex object. If i is greater than the number of start vertice...
unsigned int getGoalIndex(unsigned int i) const
Returns the index of the ith goal state. INVALID_INDEX is returned if i is out of range Indexes are v...
const PlannerDataVertex & getVertex(unsigned int index) const
Retrieve a reference to the vertex object with the given index. If this vertex does not exist,...
std::vector< unsigned int > goalVertexIndices_
A mutable listing of the vertices marked as goal states. Stored in sorted order.
void computeEdgeWeights(const OptimizationObjective &opt)
Computes the weight for all edges given the OptimizationObjective opt.
virtual bool addEdge(unsigned int v1, unsigned int v2, const PlannerDataEdge &edge=PlannerDataEdge(), Cost weight=Cost(1.0))
Adds a directed edge between the given vertex indexes. An optional edge structure and weight can be s...
virtual bool hasControls() const
Indicate whether any information about controls (ompl::control::Control) is stored in this instance.
void extractReachable(unsigned int v, PlannerData &data) const
Extracts the subset of PlannerData reachable from the vertex with index v. For tree structures,...
unsigned int addVertex(const PlannerDataVertex &st)
Adds the given vertex to the graph data. The vertex index is returned. Duplicates are not added....
std::map< std::string, std::string > properties
Any extra properties (key-value pairs) the planner can set.
bool vertexExists(const PlannerDataVertex &v) const
Check whether a vertex exists with the given vertex data.
unsigned int numGoalVertices() const
Returns the number of goal vertices.
const PlannerDataVertex & getGoalVertex(unsigned int i) const
Retrieve a reference to the ith goal vertex object. If i is greater than the number of goal vertices,...
void printGraphML(std::ostream &out=std::cout) const
Writes a GraphML file of this structure to the given stream.
bool isStartVertex(unsigned int index) const
Returns true if the given vertex index is marked as a start vertex.
virtual ~PlannerData()
Destructor.
virtual void decoupleFromPlanner()
Creates a deep copy of the states contained in the vertices of this PlannerData structure so that whe...
Definition of a scoped state.
Definition ScopedState.h:57
std::vector< double > reals() const
Return the real values corresponding to this state. If a conversion is not possible,...
A shared pointer wrapper for ompl::base::SpaceInformation.
Representation of a space in which planning can be performed. Topology specific sampling,...
Definition StateSpace.h:71
virtual unsigned int getDimension() const =0
Get the dimension of the space (not the dimension of the surrounding ambient space).
virtual void copyToReals(std::vector< double > &reals, const State *source) const
Copy all the real values from a state source to the array reals using getValueAddressAtLocation().
Definition of an abstract state.
Definition State.h:50
STL namespace.