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 
56 const unsigned int ompl::base::PlannerData::INVALID_INDEX = std::numeric_limits<unsigned int>::max();
57 
58 ompl::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  {
84  PlannerDataVertex &vtx = getVertex(i);
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 
102 unsigned 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 
115 unsigned 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 
129 unsigned 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 
141 unsigned int ompl::base::PlannerData::getIncomingEdges(unsigned int v,
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 
155 bool 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 
171 bool 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 
186 bool 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 
196 {
197  return vertexIndex(v) != INVALID_INDEX;
198 }
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 
228 const 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 
258 void ompl::base::PlannerData::printGraphviz(std::ostream &out) const
259 {
260  boost::write_graphviz(out, *graph_);
261 }
262 
263 namespace
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,
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 }
281 
282 void 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?
292  boost::function_property_map<std::function<double(Edge)>, Edge> weightmap([this](Edge e)
293  {
294  return get(boost::edge_weight_t(),
295  *graph_)[e].value();
296  });
299  boost::function_property_map<std::function<std::string(Vertex)>, Vertex> coordsmap([this, &s](Vertex v)
300  {
301  return vertexCoords(*graph_,
302  s, v);
303  });
304 
305  // Not writing vertex or edge structures.
306  boost::dynamic_properties dp;
307  dp.property("weight", weightmap);
308  dp.property("coords", coordsmap);
309 
310  boost::write_graphml(out, *graph_, dp);
311 }
312 
314 {
315  auto it = stateIndexMap_.find(v.getState());
316  if (it != stateIndexMap_.end())
317  return it->second;
318  return INVALID_INDEX;
319 }
320 
322 {
323  return startVertexIndices_.size();
324 }
325 
327 {
328  return goalVertexIndices_.size();
329 }
330 
331 unsigned int ompl::base::PlannerData::getStartIndex(unsigned int i) const
332 {
333  if (i >= startVertexIndices_.size())
334  return INVALID_INDEX;
335 
336  return startVertexIndices_[i];
337 }
338 
339 unsigned int ompl::base::PlannerData::getGoalIndex(unsigned int i) const
340 {
341  if (i >= goalVertexIndices_.size())
342  return INVALID_INDEX;
343 
344  return goalVertexIndices_[i];
345 }
346 
347 bool ompl::base::PlannerData::isStartVertex(unsigned int index) const
348 {
349  return std::binary_search(startVertexIndices_.begin(), startVertexIndices_.end(), index);
350 }
351 
352 bool ompl::base::PlannerData::isGoalVertex(unsigned int index) const
353 {
354  return std::binary_search(goalVertexIndices_.begin(), goalVertexIndices_.end(), index);
355 }
356 
358 {
359  if (i >= startVertexIndices_.size())
360  return NO_VERTEX;
361 
362  return getVertex(startVertexIndices_[i]);
363 }
364 
366 {
367  if (i >= startVertexIndices_.size())
368  return const_cast<ompl::base::PlannerDataVertex &>(NO_VERTEX);
369 
370  return getVertex(startVertexIndices_[i]);
371 }
372 
374 {
375  if (i >= goalVertexIndices_.size())
376  return NO_VERTEX;
377 
378  return getVertex(goalVertexIndices_[i]);
379 }
380 
382 {
383  if (i >= goalVertexIndices_.size())
384  return const_cast<ompl::base::PlannerDataVertex &>(NO_VERTEX);
385 
386  return getVertex(goalVertexIndices_[i]);
387 }
388 
390 {
391  // Do not add vertices with null states
392  if (st.getState() == nullptr)
393  return INVALID_INDEX;
394 
395  unsigned int index = vertexIndex(st);
396  if (index == INVALID_INDEX) // Vertex does not already exist
397  {
398  // Clone the state to prevent object slicing when retrieving this object
399  ompl::base::PlannerDataVertex *clone = st.clone();
400  Graph::Vertex v = boost::add_vertex(clone, *graph_);
401  boost::property_map<Graph::Type, boost::vertex_index_t>::type vertexIndexMap =
402  get(boost::vertex_index, *graph_);
403 
404  // Insert this entry into the stateIndexMap_ for fast lookup
405  stateIndexMap_[clone->getState()] = numVertices() - 1;
406  return vertexIndexMap[v];
407  }
408  return index;
409 }
410 
412 {
413  unsigned int index = addVertex(v);
414  if (index != INVALID_INDEX)
415  markStartState(v.getState());
416 
417  return index;
418 }
419 
421 {
422  unsigned int index = addVertex(v);
423 
424  if (index != INVALID_INDEX)
425  markGoalState(v.getState());
426 
427  return index;
428 }
429 
430 bool ompl::base::PlannerData::addEdge(unsigned int v1, unsigned int v2, const PlannerDataEdge &edge, Cost weight)
431 {
432  // If either of the vertices do not exist, don't add an edge
433  if (v1 >= numVertices() || v2 >= numVertices())
434  return false;
435 
436  // If an edge already exists, do not add one
437  if (edgeExists(v1, v2))
438  return false;
439 
440  // Clone the edge to prevent object slicing
441  ompl::base::PlannerDataEdge *clone = edge.clone();
442  const Graph::edge_property_type properties(clone, weight);
443 
444  Graph::Edge e;
445  bool added = false;
446  tie(e, added) = boost::add_edge(boost::vertex(v1, *graph_), boost::vertex(v2, *graph_), properties, *graph_);
447 
448  if (!added)
449  delete clone;
450 
451  return added;
452 }
453 
455  const PlannerDataEdge &edge, Cost weight)
456 {
457  unsigned int index1 = addVertex(v1);
458  unsigned int index2 = addVertex(v2);
459 
460  // If neither vertex was added or already exists, return false
461  if (index1 == INVALID_INDEX && index2 == INVALID_INDEX)
462  return false;
463 
464  // Only add the edge if both vertices exist
465  if (index1 != INVALID_INDEX && index2 != INVALID_INDEX)
466  return addEdge(index1, index2, edge, weight);
467 
468  return true;
469 }
470 
472 {
473  unsigned int index = vertexIndex(st);
474  if (index != INVALID_INDEX)
475  return removeVertex(index);
476  return false;
477 }
478 
479 bool ompl::base::PlannerData::removeVertex(unsigned int vIndex)
480 {
481  if (vIndex >= boost::num_vertices(*graph_))
482  return false;
483 
484  // Retrieve a list of all edge structures
485  boost::property_map<Graph::Type, edge_type_t>::type edgePropertyMap = get(edge_type_t(), *graph_);
486 
487  // Freeing memory associated with outgoing edges of this vertex
488  std::pair<Graph::OEIterator, Graph::OEIterator> oiterators =
489  boost::out_edges(boost::vertex(vIndex, *graph_), *graph_);
490  for (Graph::OEIterator iter = oiterators.first; iter != oiterators.second; ++iter)
491  delete edgePropertyMap[*iter];
492 
493  // Freeing memory associated with incoming edges of this vertex
494  std::pair<Graph::IEIterator, Graph::IEIterator> initerators =
495  boost::in_edges(boost::vertex(vIndex, *graph_), *graph_);
496  for (Graph::IEIterator iter = initerators.first; iter != initerators.second; ++iter)
497  delete edgePropertyMap[*iter];
498 
499  // Remove this vertex from stateIndexMap_, and update the map
500  stateIndexMap_.erase(getVertex(vIndex).getState());
501  boost::property_map<Graph::Type, vertex_type_t>::type vertices = get(vertex_type_t(), *graph_);
502  for (unsigned int i = vIndex + 1; i < boost::num_vertices(*graph_); ++i)
503  stateIndexMap_[vertices[boost::vertex(i, *graph_)]->getState()]--;
504 
505  // Remove this vertex from the start and/or goal index list, if it exists. Update the lists.
506  auto it = std::find(startVertexIndices_.begin(), startVertexIndices_.end(), vIndex);
507  if (it != startVertexIndices_.end())
508  startVertexIndices_.erase(it);
509  for (unsigned int &startVertexIndex : startVertexIndices_)
510  if (startVertexIndex > vIndex)
511  startVertexIndex--;
512 
513  it = std::find(goalVertexIndices_.begin(), goalVertexIndices_.end(), vIndex);
514  if (it != goalVertexIndices_.end())
515  goalVertexIndices_.erase(it);
516  for (unsigned int &goalVertexIndex : goalVertexIndices_)
517  if (goalVertexIndex > vIndex)
518  goalVertexIndex--;
519 
520  // If the state attached to this vertex was decoupled, free it here
521  auto *vtxState = const_cast<State *>(getVertex(vIndex).getState());
522  if (decoupledStates_.find(vtxState) != decoupledStates_.end())
523  {
524  decoupledStates_.erase(vtxState);
525  si_->freeState(vtxState);
526  vtxState = nullptr;
527  }
528 
529  // Slay the vertex
530  boost::clear_vertex(boost::vertex(vIndex, *graph_), *graph_);
531  boost::property_map<Graph::Type, vertex_type_t>::type vertexTypeMap = get(vertex_type_t(), *graph_);
532  delete vertexTypeMap[boost::vertex(vIndex, *graph_)];
533  boost::remove_vertex(boost::vertex(vIndex, *graph_), *graph_);
534 
535  return true;
536 }
537 
538 bool ompl::base::PlannerData::removeEdge(unsigned int v1, unsigned int v2)
539 {
540  Graph::Edge e;
541  bool exists;
542  boost::tie(e, exists) = boost::edge(boost::vertex(v1, *graph_), boost::vertex(v2, *graph_), *graph_);
543 
544  if (!exists)
545  return false;
546 
547  // Freeing memory associated with this edge
548  boost::property_map<Graph::Type, edge_type_t>::type edges = get(edge_type_t(), *graph_);
549  delete edges[e];
550 
551  boost::remove_edge(boost::vertex(v1, *graph_), boost::vertex(v2, *graph_), *graph_);
552  return true;
553 }
554 
556 {
557  unsigned int index1, index2;
558  index1 = vertexIndex(v1);
559  index2 = vertexIndex(v2);
560 
561  if (index1 == INVALID_INDEX || index2 == INVALID_INDEX)
562  return false;
563 
564  return removeEdge(index1, index2);
565 }
566 
568 {
569  std::map<const State *, unsigned int>::const_iterator it = stateIndexMap_.find(st);
570  if (it != stateIndexMap_.end())
571  {
572  getVertex(it->second).setTag(tag);
573  return true;
574  }
575  return false;
576 }
577 
579 {
580  // Find the index in the stateIndexMap_
581  std::map<const State *, unsigned int>::const_iterator it = stateIndexMap_.find(st);
582  if (it != stateIndexMap_.end())
583  {
584  if (!isStartVertex(it->second))
585  {
586  startVertexIndices_.push_back(it->second);
587  // Sort the indices for quick lookup
588  std::sort(startVertexIndices_.begin(), startVertexIndices_.end());
589  }
590  return true;
591  }
592  return false;
593 }
594 
596 {
597  // Find the index in the stateIndexMap_
598  std::map<const State *, unsigned int>::const_iterator it = stateIndexMap_.find(st);
599  if (it != stateIndexMap_.end())
600  {
601  if (!isGoalVertex(it->second))
602  {
603  goalVertexIndices_.push_back(it->second);
604  // Sort the indices for quick lookup
605  std::sort(startVertexIndices_.begin(), startVertexIndices_.end());
606  }
607  return true;
608  }
609  return false;
610 }
611 
613 {
614  unsigned int nv = numVertices();
615  for (unsigned int i = 0; i < nv; ++i)
616  {
617  std::map<unsigned int, const PlannerDataEdge *> nbrs;
618  getEdges(i, nbrs);
619 
620  std::map<unsigned int, const PlannerDataEdge *>::const_iterator it;
621  for (it = nbrs.begin(); it != nbrs.end(); ++it)
622  {
623  setEdgeWeight(i, it->first, opt.motionCost(getVertex(i).getState(), getVertex(it->first).getState()));
624  }
625  }
626 }
627 
629 {
630  // Create a PathLengthOptimizationObjective to compute the edge
631  // weights according to state space distance
633  computeEdgeWeights(opt);
634 }
635 
637  base::PlannerData &mst) const
638 {
639  std::vector<ompl::base::PlannerData::Graph::Vertex> pred(numVertices());
640 
641  // This is how boost's minimum spanning tree is actually
642  // implemented, except it lacks the generality for specifying our
643  // own comparison function or zero/inf values.
644  //
645  // \todo Once (https://svn.boost.org/trac/boost/ticket/9368) gets
646  // into boost we can use the far more direct
647  // boost::prim_minimum_spanning_tree().
648  boost::dijkstra_shortest_paths(*graph_, v, boost::predecessor_map(&pred[0])
649  .distance_compare([&opt](Cost c1, Cost c2)
650  {
651  return opt.isCostBetterThan(c1, c2);
652  })
653  .distance_combine([](Cost, Cost c)
654  {
655  return c;
656  })
657  .distance_inf(opt.infiniteCost())
658  .distance_zero(opt.identityCost()));
659 
660  // Adding vertices to MST
661  for (std::size_t i = 0; i < pred.size(); ++i)
662  {
663  if (isStartVertex(i))
664  mst.addStartVertex(getVertex(i));
665  else if (isGoalVertex(i))
666  mst.addGoalVertex(getVertex(i));
667  else
668  mst.addVertex(getVertex(i));
669  }
670 
671  // Adding edges to MST
672  for (std::size_t i = 0; i < pred.size(); ++i)
673  {
674  if (pred[i] != i)
675  {
676  Cost c;
677  getEdgeWeight(pred[i], i, &c);
678  mst.addEdge(pred[i], i, getEdge(pred[i], i), c);
679  }
680  }
681 }
682 
684 {
685  // If this vertex already exists in data, return
686  if (data.vertexExists(getVertex(v)))
687  return;
688 
689  // Adding the vertex corresponding to v into data
690  unsigned int idx;
691  if (isStartVertex(v))
692  idx = data.addStartVertex(getVertex(v));
693  else if (isGoalVertex(v))
694  idx = data.addGoalVertex(getVertex(v));
695  else
696  idx = data.addVertex(getVertex(v));
697 
698  assert(idx != INVALID_INDEX);
699 
700  std::map<unsigned int, const PlannerDataEdge *> neighbors;
701  getEdges(v, neighbors);
702 
703  // Depth-first traversal of reachable graph
704  std::map<unsigned int, const PlannerDataEdge *>::iterator it;
705  for (auto &it : neighbors)
706  {
707  extractReachable(it.first, data);
708  Cost weight;
709  getEdgeWeight(v, it.first, &weight);
710  data.addEdge(idx, data.vertexIndex(getVertex(it.first)), *it.second, weight);
711  }
712 }
713 
714 ompl::base::StateStoragePtr ompl::base::PlannerData::extractStateStorage() const
715 {
716  auto store(std::make_shared<GraphStateStorage>(si_->getStateSpace()));
717  if (graph_)
718  {
719  // copy the states
720  std::map<unsigned int, unsigned int> indexMap;
721  for (const auto &it : stateIndexMap_)
722  {
723  indexMap[it.second] = store->size();
724  store->addState(it.first);
725  }
726 
727  // add the edges
728  for (const auto &it : indexMap)
729  {
730  std::vector<unsigned int> edgeList;
731  getEdges(it.first, edgeList);
732  GraphStateStorage::MetadataType &md = store->getMetadata(it.second);
733  md.resize(edgeList.size());
734  // map node indices to index values in StateStorage
735  for (std::size_t k = 0; k < edgeList.size(); ++k)
736  md[k] = indexMap[edgeList[k]];
737  }
738  }
739  return store;
740 }
741 
743 {
744  auto *boostgraph = reinterpret_cast<ompl::base::PlannerData::Graph *>(graphRaw_);
745  return *boostgraph;
746 }
747 
749 {
750  const auto *boostgraph =
751  reinterpret_cast<const ompl::base::PlannerData::Graph *>(graphRaw_);
752  return *boostgraph;
753 }
754 
756 {
757  return si_;
758 }
759 
760 void ompl::base::PlannerData::freeMemory()
761 {
762  // Freeing decoupled states, if any
763  for (auto decoupledState : decoupledStates_)
764  si_->freeState(decoupledState);
765 
766  if (graph_)
767  {
768  std::pair<Graph::EIterator, Graph::EIterator> eiterators = boost::edges(*graph_);
769  boost::property_map<Graph::Type, edge_type_t>::type edges = get(edge_type_t(), *graph_);
770  for (Graph::EIterator iter = eiterators.first; iter != eiterators.second; ++iter)
771  delete boost::get(edges, *iter);
772 
773  std::pair<Graph::VIterator, Graph::VIterator> viterators = boost::vertices(*graph_);
774  boost::property_map<Graph::Type, vertex_type_t>::type vertices = get(vertex_type_t(), *graph_);
775  for (Graph::VIterator iter = viterators.first; iter != viterators.second; ++iter)
776  delete vertices[*iter];
777 
778  graph_->clear();
779  }
780 }
781 
783 {
784  return false;
785 }
786 
787 void ompl::base::PlannerData::printPLY(std::ostream &out, const bool asIs) const
788 {
789  const base::StateSpace *space(si_->getStateSpace().get());
790 
791  unsigned int dim = space->getDimension();
792  if (dim > 3)
793  throw Exception("Cannot output mesh of path in more than 3 dimensions!");
794 
795  std::vector<double> reals;
796  std::stringstream v, f;
797  std::size_t vcount = 0;
798  std::size_t fcount = 0;
799 
800  auto stateOutput = [&](const ompl::base::State *state) {
801  space->copyToReals(reals, state);
802  std::copy(reals.begin(), reals.end(), std::ostream_iterator<double>(v, " "));
803  v << std::endl;
804  };
805 
806  const Graph &graph = toBoostGraph();
807 
808  BGL_FORALL_EDGES(edge, graph, PlannerData::Graph)
809  {
810  std::vector<ompl::base::State *> stateList;
811  const State *source = boost::get(vertex_type, graph, boost::source(edge, graph))->getState();
812  const State *target = boost::get(vertex_type, graph, boost::target(edge, graph))->getState();
813 
814  unsigned int n = 0;
815  if (!asIs)
816  n = si_->getStateSpace()->validSegmentCount(source, target);
817  si_->getMotionStates(source, target, stateList, n, true, true);
818 
819  stateOutput(stateList[0]);
820  vcount++;
821  for (std::size_t i = 1; i < stateList.size(); i++)
822  {
823  stateOutput(stateList[i]);
824  stateOutput(stateList[i - 1]);
825  vcount += 2;
826  f << 3 << " " << vcount - 3 << " " << vcount - 2 << " " << vcount - 1 << "\n";
827  fcount++;
828  si_->freeState(stateList[i - 1]);
829  }
830  si_->freeState(stateList.back());
831  }
832 
833  out << "ply\n";
834  out << "format ascii 1.0\n";
835  out << "element vertex " << vcount << "\n";
836  out << "property float x\n";
837 
838  if (dim > 1)
839  out << "property float y\n";
840 
841  if (dim > 2)
842  out << "property float z\n";
843 
844  out << "element face " << fcount << "\n";
845  out << "property list uchar int vertex_index\n";
846  out << "end_header\n";
847  out << v.str() << f.str();
848 }
bool edgeExists(unsigned int v1, unsigned int v2) const
Check whether an edge between vertex index v1 and index v2 exists.
unsigned int numGoalVertices() const
Returns the number of goal vertices.
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...
virtual Cost identityCost() const
Get the identity cost value. The identity cost value is the cost c_i such that, for all costs c,...
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....
virtual bool removeEdge(unsigned int v1, unsigned int v2)
Removes the edge between vertex indexes v1 and v2. Success is returned.
A shared pointer wrapper for ompl::base::SpaceInformation.
virtual PlannerDataEdge * clone() const
Return a clone of this object, allocated from the heap.
Definition: PlannerData.h:196
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)....
Representation of a space in which planning can be performed. Topology specific sampling,...
Definition: StateSpace.h:134
const SpaceInformationPtr & getSpaceInformation() const
Return the instance of SpaceInformation used in this PlannerData.
bool isStartVertex(unsigned int index) const
Returns true if the given vertex index is marked as a start vertex.
Wrapper class for the Boost.Graph representation of the PlannerData. This class inherits from a boost...
An optimization objective which corresponds to optimizing path length.
bool isGoalVertex(unsigned int index) const
Returns true if the given vertex index is marked as a goal vertex.
static const PlannerDataEdge NO_EDGE
Representation for a non-existant edge.
Definition: PlannerData.h:241
Definition of an abstract state.
Definition: State.h:113
virtual PlannerDataVertex * clone() const
Return a clone of this object, allocated from the heap.
Definition: PlannerData.h:182
bool vertexExists(const PlannerDataVertex &v) const
Check whether a vertex exists with the given vertex data.
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.
virtual Cost infiniteCost() const
Get a cost which is greater than all other costs in this OptimizationObjective; required for use in D...
M MetadataType
the datatype of the metadata
Definition: StateStorage.h:282
Definition of a cost value. Can represent the cost of a motion or the cost of a state.
Definition: Cost.h:111
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,...
virtual void decoupleFromPlanner()
Creates a deep copy of the states contained in the vertices of this PlannerData structure so that whe...
Definition: PlannerData.cpp:80
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...
boost::graph_traits< Type >::vertex_descriptor Vertex
Boost.Graph vertex descriptor.
Object containing planner generated vertex and edge data. It is assumed that all vertices are unique,...
Definition: PlannerData.h:238
static const unsigned int INVALID_INDEX
Representation of an invalid vertex index.
Definition: PlannerData.h:248
Abstract definition of optimization objectives.
void printGraphML(std::ostream &out=std::cout) const
Writes a GraphML file of this structure to the given stream.
unsigned int numVertices() const
Retrieve the number of vertices in this structure.
unsigned int numStartVertices() const
Returns the number of start vertices.
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...
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...
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...
virtual Cost motionCost(const State *s1, const State *s2) const =0
Get the cost that corresponds to the motion segment between s1 and s2.
bool markGoalState(const State *st)
Mark the given state as a goal vertex. If the given state does not exist in a vertex,...
void printGraphviz(std::ostream &out=std::cout) const
Writes a Graphviz dot file of this structure to the given stream.
void extractReachable(unsigned int v, PlannerData &data) const
Extracts the subset of PlannerData reachable from the vertex with index v. For tree structures,...
const PlannerDataVertex & getVertex(unsigned int index) const
Retrieve a reference to the vertex object with the given index. If this vertex does not exist,...
virtual const State * getState() const
Retrieve the state associated with this vertex.
Definition: PlannerData.h:176
bool markStartState(const State *st)
Mark the given state as a start vertex. If the given state does not exist in a vertex,...
Base class for a PlannerData edge.
Definition: PlannerData.h:190
virtual bool removeVertex(const PlannerDataVertex &st)
Removes the vertex associated with the given data. If the vertex does not exist, false is returned....
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...
unsigned int addVertex(const PlannerDataVertex &st)
Adds the given vertex to the graph data. The vertex index is returned. Duplicates are not added....
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 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...
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...
virtual void clear()
Clears the entire data structure.
Definition: PlannerData.cpp:74
void computeEdgeWeights()
Computes all edge weights using state space distance (i.e. getSpaceInformation()->distance())
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...
const State * state_
The state represented by this vertex.
Definition: PlannerData.h:213
static const PlannerDataVertex NO_VERTEX
Representation for a non-existant vertex.
Definition: PlannerData.h:246
boost::graph_traits< Type >::edge_descriptor Edge
Boost.Graph edge descriptor.
Definition of a scoped state.
Definition: ScopedState.h:120
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...
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...
The exception type for ompl.
Definition: Exception.h:78
Graph & toBoostGraph()
Extract a Boost.Graph object from this PlannerData.
PlannerDataGraph Type
Data type for the Boost.Graph representation.
Base class for a vertex in the PlannerData structure. All derived classes must implement the clone an...
Definition: PlannerData.h:122
virtual ~PlannerData()
Destructor.
Definition: PlannerData.cpp:63
virtual bool hasControls() const
Indicate whether any information about controls (ompl::control::Control) is stored in this instance.
const PlannerDataEdge & getEdge(unsigned int v1, unsigned int v2) const
Retrieve a reference to the edge object connecting vertices with indexes v1 and v2....
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...