PathSimplifier.cpp
1 /*********************************************************************
2 * Software License Agreement (BSD License)
3 *
4 * Copyright (c) 2011, Rice University, Inc.
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: Ioan Sucan, Ryan Luna */
36 
37 #include "ompl/geometric/PathSimplifier.h"
38 #include "ompl/tools/config/MagicConstants.h"
39 #include <algorithm>
40 #include <limits>
41 #include <cstdlib>
42 #include <cmath>
43 #include <map>
44 
46 {
47  if (goal)
48  {
49  gsr_ = std::dynamic_pointer_cast<base::GoalSampleableRegion>(goal);
50  if (!gsr_)
51  OMPL_WARN("%s: Goal could not be cast to GoalSampleableRegion. Goal simplification will not be performed.", __FUNCTION__);
52  }
53 }
54 
56 {
57  return freeStates_;
58 }
59 
61 {
62  freeStates_ = flag;
63 }
64 
65 /* Based on COMP450 2010 project of Yun Yu and Linda Hill (Rice University) */
66 void ompl::geometric::PathSimplifier::smoothBSpline(PathGeometric &path, unsigned int maxSteps, double minChange)
67 {
68  if (path.getStateCount() < 3)
69  return;
70 
72  std::vector<base::State*> &states = path.getStates();
73 
74  base::State *temp1 = si->allocState();
75  base::State *temp2 = si->allocState();
76 
77  for (unsigned int s = 0 ; s < maxSteps ; ++s)
78  {
79  path.subdivide();
80 
81  unsigned int i = 2, u = 0, n1 = states.size() - 1;
82  while (i < n1)
83  {
84  if (si->isValid(states[i - 1]))
85  {
86  si->getStateSpace()->interpolate(states[i - 1], states[i], 0.5, temp1);
87  si->getStateSpace()->interpolate(states[i], states[i + 1], 0.5, temp2);
88  si->getStateSpace()->interpolate(temp1, temp2, 0.5, temp1);
89  if (si->checkMotion(states[i - 1], temp1) && si->checkMotion(temp1, states[i + 1]))
90  {
91  if (si->distance(states[i], temp1) > minChange)
92  {
93  si->copyState(states[i], temp1);
94  ++u;
95  }
96  }
97  }
98 
99  i += 2;
100  }
101 
102  if (u == 0)
103  break;
104  }
105 
106  si->freeState(temp1);
107  si->freeState(temp2);
108 }
109 
110 bool ompl::geometric::PathSimplifier::reduceVertices(PathGeometric &path, unsigned int maxSteps, unsigned int maxEmptySteps, double rangeRatio)
111 {
112  if (path.getStateCount() < 3)
113  return false;
114 
115  if (maxSteps == 0)
116  maxSteps = path.getStateCount();
117 
118  if (maxEmptySteps == 0)
119  maxEmptySteps = path.getStateCount();
120 
121  bool result = false;
122  unsigned int nochange = 0;
124  std::vector<base::State*> &states = path.getStates();
125 
126  if (si->checkMotion(states.front(), states.back()))
127  {
128  if (freeStates_)
129  for (std::size_t i = 2 ; i < states.size() ; ++i)
130  si->freeState(states[i-1]);
131  std::vector<base::State*> newStates(2);
132  newStates[0] = states.front();
133  newStates[1] = states.back();
134  states.swap(newStates);
135  result = true;
136  }
137  else
138  for (unsigned int i = 0 ; i < maxSteps && nochange < maxEmptySteps ; ++i, ++nochange)
139  {
140  int count = states.size();
141  int maxN = count - 1;
142  int range = 1 + (int)(floor(0.5 + (double)count * rangeRatio));
143 
144  int p1 = rng_.uniformInt(0, maxN);
145  int p2 = rng_.uniformInt(std::max(p1 - range, 0), std::min(maxN, p1 + range));
146  if (abs(p1 - p2) < 2)
147  {
148  if (p1 < maxN - 1)
149  p2 = p1 + 2;
150  else
151  if (p1 > 1)
152  p2 = p1 - 2;
153  else
154  continue;
155  }
156 
157  if (p1 > p2)
158  std::swap(p1, p2);
159 
160  if (si->checkMotion(states[p1], states[p2]))
161  {
162  if (freeStates_)
163  for (int j = p1 + 1 ; j < p2 ; ++j)
164  si->freeState(states[j]);
165  states.erase(states.begin() + p1 + 1, states.begin() + p2);
166  nochange = 0;
167  result = true;
168  }
169  }
170  return result;
171 }
172 
173 bool ompl::geometric::PathSimplifier::shortcutPath(PathGeometric &path, unsigned int maxSteps, unsigned int maxEmptySteps, double rangeRatio, double snapToVertex)
174 {
175  if (path.getStateCount() < 3)
176  return false;
177 
178  if (maxSteps == 0)
179  maxSteps = path.getStateCount();
180 
181  if (maxEmptySteps == 0)
182  maxEmptySteps = path.getStateCount();
183 
185  std::vector<base::State*> &states = path.getStates();
186 
187  // dists[i] contains the cumulative length of the path up to and including state i
188  std::vector<double> dists(states.size(), 0.0);
189  for (unsigned int i = 1 ; i < dists.size() ; ++i)
190  dists[i] = dists[i - 1] + si->distance(states[i-1], states[i]);
191  // Sampled states closer than 'threshold' distance to any existing state in the path
192  // are snapped to the close state
193  double threshold = dists.back() * snapToVertex;
194  // The range (distance) of a single connection that will be attempted
195  double rd = rangeRatio * dists.back();
196 
197  base::State *temp0 = si->allocState();
198  base::State *temp1 = si->allocState();
199  bool result = false;
200  unsigned int nochange = 0;
201  // Attempt shortcutting maxSteps times or when no improvement is found after
202  // maxEmptySteps attempts, whichever comes first
203  for (unsigned int i = 0 ; i < maxSteps && nochange < maxEmptySteps ; ++i, ++nochange)
204  {
205  // Sample a random point anywhere along the path
206  base::State *s0 = nullptr;
207  int index0 = -1;
208  double t0 = 0.0;
209  double p0 = rng_.uniformReal(0.0, dists.back()); // sample a random point (p0) along the path
210  std::vector<double>::iterator pit = std::lower_bound(dists.begin(), dists.end(), p0); // find the NEXT waypoint after the random point
211  int pos0 = pit == dists.end() ? dists.size() - 1 : pit - dists.begin(); // get the index of the NEXT waypoint after the point
212 
213  if (pos0 == 0 || dists[pos0] - p0 < threshold) // snap to the NEXT waypoint
214  index0 = pos0;
215  else
216  {
217  while (pos0 > 0 && p0 < dists[pos0])
218  --pos0;
219  if (p0 - dists[pos0] < threshold) // snap to the PREVIOUS waypoint
220  index0 = pos0;
221  }
222 
223  // Sample a random point within rd distance of the previously sampled point
224  base::State *s1 = nullptr;
225  int index1 = -1;
226  double t1 = 0.0;
227  double p1 = rng_.uniformReal(std::max(0.0, p0 - rd), std::min(p0 + rd, dists.back())); // sample a random point (p1) near p0
228  pit = std::lower_bound(dists.begin(), dists.end(), p1); // find the NEXT waypoint after the random point
229  int pos1 = pit == dists.end() ? dists.size() - 1 : pit - dists.begin(); // get the index of the NEXT waypoint after the point
230 
231  if (pos1 == 0 || dists[pos1] - p1 < threshold) // snap to the NEXT waypoint
232  index1 = pos1;
233  else
234  {
235  while (pos1 > 0 && p1 < dists[pos1])
236  --pos1;
237  if (p1 - dists[pos1] < threshold) // snap to the PREVIOUS waypoint
238  index1 = pos1;
239  }
240 
241  // Don't waste time on points that are on the same path segment
242  if (pos0 == pos1 || index0 == pos1 || index1 == pos0 ||
243  pos0 + 1 == index1 || pos1 + 1 == index0 ||
244  (index0 >=0 && index1 >= 0 && abs(index0 - index1) < 2))
245  continue;
246 
247  // Get the state pointer for p0
248  if (index0 >= 0)
249  s0 = states[index0];
250  else
251  {
252  t0 = (p0 - dists[pos0]) / (dists[pos0 + 1] - dists[pos0]);
253  si->getStateSpace()->interpolate(states[pos0], states[pos0 + 1], t0, temp0);
254  s0 = temp0;
255  }
256 
257  // Get the state pointer for p1
258  if (index1 >= 0)
259  s1 = states[index1];
260  else
261  {
262  t1 = (p1 - dists[pos1]) / (dists[pos1 + 1] - dists[pos1]);
263  si->getStateSpace()->interpolate(states[pos1], states[pos1 + 1], t1, temp1);
264  s1 = temp1;
265  }
266 
267  // Check for validity between s0 and s1
268  if (si->checkMotion(s0, s1))
269  {
270  if (pos0 > pos1)
271  {
272  std::swap(pos0, pos1);
273  std::swap(index0, index1);
274  std::swap(s0, s1);
275  std::swap(t0, t1);
276  }
277 
278  // Modify the path with the new, shorter result
279  if (index0 < 0 && index1 < 0)
280  {
281  if (pos0 + 1 == pos1)
282  {
283  si->copyState(states[pos1], s0);
284  states.insert(states.begin() + pos1 + 1, si->cloneState(s1));
285  }
286  else
287  {
288  if (freeStates_)
289  for (int j = pos0 + 2 ; j < pos1 ; ++j)
290  si->freeState(states[j]);
291  si->copyState(states[pos0 + 1], s0);
292  si->copyState(states[pos1], s1);
293  states.erase(states.begin() + pos0 + 2, states.begin() + pos1);
294  }
295  }
296  else
297  if (index0 >= 0 && index1 >= 0)
298  {
299  if (freeStates_)
300  for (int j = index0 + 1 ; j < index1 ; ++j)
301  si->freeState(states[j]);
302  states.erase(states.begin() + index0 + 1, states.begin() + index1);
303  }
304  else
305  if (index0 < 0 && index1 >= 0)
306  {
307  if (freeStates_)
308  for (int j = pos0 + 2 ; j < index1 ; ++j)
309  si->freeState(states[j]);
310  si->copyState(states[pos0 + 1], s0);
311  states.erase(states.begin() + pos0 + 2, states.begin() + index1);
312  }
313  else
314  if (index0 >= 0 && index1 < 0)
315  {
316  if (freeStates_)
317  for (int j = index0 + 1 ; j < pos1 ; ++j)
318  si->freeState(states[j]);
319  si->copyState(states[pos1], s1);
320  states.erase(states.begin() + index0 + 1, states.begin() + pos1);
321  }
322 
323  // fix the helper variables
324  dists.resize(states.size(), 0.0);
325  for (unsigned int j = pos0 + 1 ; j < dists.size() ; ++j)
326  dists[j] = dists[j - 1] + si->distance(states[j-1], states[j]);
327  threshold = dists.back() * snapToVertex;
328  rd = rangeRatio * dists.back();
329  result = true;
330  nochange = 0;
331  }
332  }
333 
334  si->freeState(temp1);
335  si->freeState(temp0);
336  return result;
337 }
338 
339 bool ompl::geometric::PathSimplifier::collapseCloseVertices(PathGeometric &path, unsigned int maxSteps, unsigned int maxEmptySteps)
340 {
341  if (path.getStateCount() < 3)
342  return false;
343 
344  if (maxSteps == 0)
345  maxSteps = path.getStateCount();
346 
347  if (maxEmptySteps == 0)
348  maxEmptySteps = path.getStateCount();
349 
351  std::vector<base::State*> &states = path.getStates();
352 
353  // compute pair-wise distances in path (construct only half the matrix)
354  std::map<std::pair<const base::State*, const base::State*>, double> distances;
355  for (unsigned int i = 0 ; i < states.size() ; ++i)
356  for (unsigned int j = i + 2 ; j < states.size() ; ++j)
357  distances[std::make_pair(states[i], states[j])] = si->distance(states[i], states[j]);
358 
359  bool result = false;
360  unsigned int nochange = 0;
361  for (unsigned int s = 0 ; s < maxSteps && nochange < maxEmptySteps ; ++s, ++nochange)
362  {
363  // find closest pair of points
364  double minDist = std::numeric_limits<double>::infinity();
365  int p1 = -1;
366  int p2 = -1;
367  for (unsigned int i = 0 ; i < states.size() ; ++i)
368  for (unsigned int j = i + 2 ; j < states.size() ; ++j)
369  {
370  double d = distances[std::make_pair(states[i], states[j])];
371  if (d < minDist)
372  {
373  minDist = d;
374  p1 = i;
375  p2 = j;
376  }
377  }
378 
379  if (p1 >= 0 && p2 >= 0)
380  {
381  if (si->checkMotion(states[p1], states[p2]))
382  {
383  if (freeStates_)
384  for (int i = p1 + 1 ; i < p2 ; ++i)
385  si->freeState(states[i]);
386  states.erase(states.begin() + p1 + 1, states.begin() + p2);
387  result = true;
388  nochange = 0;
389  }
390  else
391  distances[std::make_pair(states[p1], states[p2])] = std::numeric_limits<double>::infinity();
392  }
393  else
394  break;
395  }
396  return result;
397 }
398 
400 {
402  simplify(path, neverTerminate);
403 }
404 
406 {
408 }
409 
411 {
412  if (path.getStateCount() < 3)
413  return;
414 
415  // try a randomized step of connecting vertices
416  bool tryMore = false;
417  if (ptc == false)
418  tryMore = reduceVertices(path);
419 
420  // try to collapse close-by vertices
421  if (ptc == false)
422  collapseCloseVertices(path);
423 
424  // try to reduce verices some more, if there is any point in doing so
425  int times = 0;
426  while (tryMore && ptc == false && ++times <= 5)
427  tryMore = reduceVertices(path);
428 
429  // if the space is metric, we can do some additional smoothing
430  if(si_->getStateSpace()->isMetricSpace())
431  {
432  bool tryMore = true;
433  unsigned int times = 0;
434  do
435  {
436  bool shortcut = shortcutPath(path); // split path segments, not just vertices
437  bool better_goal = gsr_ ? findBetterGoal(path, ptc) : false; // Try to connect the path to a closer goal
438 
439  tryMore = shortcut || better_goal;
440  } while(ptc == false && tryMore && ++times <= 5);
441 
442  // smooth the path with BSpline interpolation
443  if(ptc == false)
444  smoothBSpline(path, 3, path.length()/100.0);
445 
446  // we always run this if the metric-space algorithms were run. In non-metric spaces this does not work.
447  const std::pair<bool, bool> &p = path.checkAndRepair(magic::MAX_VALID_SAMPLE_ATTEMPTS);
448  if (!p.second)
449  OMPL_WARN("Solution path may slightly touch on an invalid region of the state space");
450  else
451  if (!p.first)
452  OMPL_DEBUG("The solution path was slightly touching on an invalid region of the state space, but it was successfully fixed.");
453  }
454 }
455 
456 bool ompl::geometric::PathSimplifier::findBetterGoal(PathGeometric &path, double maxTime, unsigned int samplingAttempts,
457  double rangeRatio, double snapToVertex)
458 {
459  return findBetterGoal(path, base::timedPlannerTerminationCondition(maxTime), samplingAttempts, rangeRatio, snapToVertex);
460 }
461 
462 
464  unsigned int samplingAttempts, double rangeRatio, double snapToVertex)
465 {
466  if (path.getStateCount() < 2)
467  return false;
468 
469  if (!gsr_)
470  {
471  OMPL_WARN("%s: No goal sampleable object to sample a better goal from.", "PathSimplifier::findBetterGoal");
472  return false;
473  }
474 
475  unsigned int maxGoals = std::min((unsigned)10, gsr_->maxSampleCount()); // the number of goals we will sample
476  unsigned int failedTries = 0;
477  bool betterGoal = false;
478 
479  const base::StateSpacePtr& ss = si_->getStateSpace();
480  std::vector<base::State*> &states = path.getStates();
481 
482  // dists[i] contains the cumulative length of the path up to and including state i
483  std::vector<double> dists(states.size(), 0.0);
484  for (unsigned int i = 1 ; i < dists.size() ; ++i)
485  dists[i] = dists[i-1] + si_->distance(states[i-1], states[i]);
486 
487  // Sampled states closer than 'threshold' distance to any existing state in the path
488  // are snapped to the close state
489  double threshold = dists.back() * snapToVertex;
490  // The range (distance) of a single connection that will be attempted
491  double rd = rangeRatio * dists.back();
492 
493  base::State* temp = si_->allocState();
494  base::State* tempGoal = si_->allocState();
495 
496  while(!ptc && failedTries++ < maxGoals && !betterGoal)
497  {
498  gsr_->sampleGoal(tempGoal);
499 
500  // Goal state is not compatible with the start state
501  if (!gsr_->isStartGoalPairValid(path.getState(0), tempGoal))
502  continue;
503 
504  unsigned int numSamples = 0;
505  while (!ptc && numSamples++ < samplingAttempts && !betterGoal)
506  {
507  // sample a state within rangeRatio
508  double t = rng_.uniformReal(std::max(dists.back() - rd, 0.0), dists.back()); // Sample a random point within rd of the end of the path
509 
510  std::vector<double>::iterator end = std::lower_bound(dists.begin(), dists.end(), t);
511  std::vector<double>::iterator start = end;
512  while(start != dists.begin() && *start >= t)
513  start -= 1;
514 
515  unsigned int startIndex = start - dists.begin();
516  unsigned int endIndex = end - dists.begin();
517 
518  // Snap the random point to the nearest vertex, if within the threshold
519  if (t - (*start) < threshold) // snap to the starting waypoint
520  endIndex = startIndex;
521  if ((*end) - t < threshold) // snap to the ending waypoint
522  startIndex = endIndex;
523 
524  // Compute the state value and the accumulated cost up to that state
525  double costToCome = dists[startIndex];
526  base::State* state;
527  if (startIndex == endIndex)
528  {
529  state = states[startIndex];
530  }
531  else
532  {
533  double tSeg = (t - (*start)) / (*end - *start);
534  ss->interpolate(states[startIndex], states[endIndex], tSeg, temp);
535  state = temp;
536 
537  costToCome += si_->distance(states[startIndex], state);
538  }
539 
540  double costToGo = si_->distance(state, tempGoal);
541  double candidateCost = costToCome + costToGo;
542 
543  // Make sure we improve before attempting validation
544  if (dists.back() - candidateCost > std::numeric_limits<float>::epsilon() && si_->checkMotion(state, tempGoal))
545  {
546  // insert the new states
547  if (startIndex == endIndex)
548  {
549  // new intermediate state
550  si_->copyState(states[startIndex], state);
551  // new goal state
552  si_->copyState(states[startIndex+1], tempGoal);
553 
554  if (freeStates_)
555  {
556  for(size_t i = startIndex + 2; i < states.size(); ++i)
557  si_->freeState(states[i]);
558  }
559  states.erase(states.begin() + startIndex + 2, states.end());
560  }
561  else
562  {
563  // overwriting the end of the segment with the new state
564  si_->copyState(states[endIndex], state);
565  if (endIndex == states.size()-1)
566  {
567  path.append(tempGoal);
568  }
569  else
570  {
571  // adding goal new goal state
572  si_->copyState(states[endIndex + 1], tempGoal);
573  if (freeStates_)
574  {
575  for(size_t i = endIndex + 2; i < states.size(); ++i)
576  si_->freeState(states[i]);
577  }
578  states.erase(states.begin() + endIndex + 2, states.end());
579  }
580  }
581 
582  // fix the helper variables
583  dists.resize(states.size(), 0.0);
584  for (unsigned int j = std::max(1u, startIndex); j < dists.size() ; ++j)
585  dists[j] = dists[j-1] + si_->distance(states[j-1], states[j]);
586 
587  betterGoal = true;
588  }
589  }
590  }
591 
592  si_->freeState(temp);
593  si_->freeState(tempGoal);
594 
595  return betterGoal;
596 }
bool findBetterGoal(PathGeometric &path, double maxTime, unsigned int samplingAttempts=10, double rangeRatio=0.33, double snapToVertex=0.005)
Attempt to improve the solution path by sampling a new goal state and connecting this state to the so...
PlannerTerminationCondition plannerNonTerminatingCondition()
Simple termination condition that always returns false. The termination condition will never be met...
bool shortcutPath(PathGeometric &path, unsigned int maxSteps=0, unsigned int maxEmptySteps=0, double rangeRatio=0.33, double snapToVertex=0.005)
Given a path, attempt to shorten it while maintaining its validity. This is an iterative process that...
void simplify(PathGeometric &path, double maxTime)
Run simplification algorithms on the path for at most maxTime seconds.
A shared pointer wrapper for ompl::base::StateSpace.
void simplifyMax(PathGeometric &path)
Given a path, attempt to remove vertices from it while keeping the path valid. Then, try to smooth the path. This function applies the same set of default operations to the path, except in non-metric spaces, with the intention of simplifying it. In non-metric spaces, some operations are skipped because they do not work correctly when the triangle inequality may not hold.
RNG rng_
Instance of random number generator.
Encapsulate a termination condition for a motion planner. Planners will call operator() to decide whe...
std::shared_ptr< base::GoalSampleableRegion > gsr_
The goal object for the path simplifier. Used for end-of-path improvements.
void append(const base::State *state)
Append state to the end of this path. The memory for state is copied.
base::State * getState(unsigned int index)
Get the state located at index along the path.
virtual double length() const
Compute the length of a geometric path (sum of lengths of segments that make up the path) ...
std::size_t getStateCount() const
Get the number of states (way-points) that make up this path.
std::pair< bool, bool > checkAndRepair(unsigned int attempts)
Check if the path is valid. If it is not, attempts are made to fix the path by sampling around invali...
PlannerTerminationCondition timedPlannerTerminationCondition(double duration)
Return a termination condition that will become true duration seconds in the future (wall-time) ...
Abstract definition of a goal region that can be sampled.
const SpaceInformationPtr & getSpaceInformation() const
Get the space information associated to this class.
Definition: Path.h:85
PathSimplifier(const base::SpaceInformationPtr &si, const base::GoalPtr &goal=ompl::base::GoalPtr())
Create an instance for a specified space information. Optionally, a GoalSampleableRegion may be passe...
bool reduceVertices(PathGeometric &path, unsigned int maxSteps=0, unsigned int maxEmptySteps=0, double rangeRatio=0.33)
Given a path, attempt to remove vertices from it while keeping the path valid. This is an iterative p...
std::vector< base::State * > & getStates()
Get the states that make up the path (as a reference, so it can be modified, hence the function is no...
base::SpaceInformationPtr si_
The space information this path simplifier uses.
double uniformReal(double lower_bound, double upper_bound)
Generate a random real within given bounds: [lower_bound, upper_bound)
Definition: RandomNumbers.h:75
A shared pointer wrapper for ompl::base::SpaceInformation.
Definition of an abstract state.
Definition: State.h:50
#define OMPL_WARN(fmt,...)
Log a formatted warning string.
Definition: Console.h:66
#define OMPL_DEBUG(fmt,...)
Log a formatted debugging string.
Definition: Console.h:70
bool freeStates() const
Return true if the memory of states is freed when they are removed from a path during simplification...
void subdivide()
Add a state at the middle of each segment.
A shared pointer wrapper for ompl::base::Goal.
Definition of a geometric path.
Definition: PathGeometric.h:60
bool collapseCloseVertices(PathGeometric &path, unsigned int maxSteps=0, unsigned int maxEmptySteps=0)
Given a path, attempt to remove vertices from it while keeping the path valid. This is an iterative p...
bool freeStates_
Flag indicating whether the states removed from a motion should be freed.
int uniformInt(int lower_bound, int upper_bound)
Generate a random integer within given bounds: [lower_bound, upper_bound].
Definition: RandomNumbers.h:82
void smoothBSpline(PathGeometric &path, unsigned int maxSteps=5, double minChange=std::numeric_limits< double >::epsilon())
Given a path, attempt to smooth it (the validity of the path is maintained).
static const unsigned int MAX_VALID_SAMPLE_ATTEMPTS
When multiple attempts are needed to generate valid samples, this value defines the default number of...