37 #include "ompl/geometric/PathSimplifier.h"
38 #include "ompl/tools/config/MagicConstants.h"
39 #include "ompl/base/objectives/PathLengthOptimizationObjective.h"
40 #include "ompl/base/StateSampler.h"
49 const base::OptimizationObjectivePtr& obj)
50 : si_(std::move(si)), freeStates_(true)
54 gsr_ = std::dynamic_pointer_cast<base::GoalSampleableRegion>(goal);
56 OMPL_WARN(
"%s: Goal could not be cast to GoalSampleableRegion. Goal simplification will not be performed.",
65 obj_ = std::make_shared<base::PathLengthOptimizationObjective>(
si_);
82 if (path.getStateCount() < 3)
85 const base::SpaceInformationPtr &si = path.getSpaceInformation();
86 std::vector<base::State *> &states = path.getStates();
91 for (
unsigned int s = 0; s < maxSteps; ++s)
95 unsigned int i = 2, u = 0, n1 = states.size() - 1;
98 if (si->isValid(states[i - 1]))
100 si->getStateSpace()->interpolate(states[i - 1], states[i], 0.5, temp1);
101 si->getStateSpace()->interpolate(states[i], states[i + 1], 0.5, temp2);
102 si->getStateSpace()->interpolate(temp1, temp2, 0.5, temp1);
103 if (si->checkMotion(states[i - 1], temp1) && si->checkMotion(temp1, states[i + 1]))
105 if (si->distance(states[i], temp1) > minChange)
107 si->copyState(states[i], temp1);
120 si->freeState(temp1);
121 si->freeState(temp2);
125 unsigned int maxEmptySteps,
double rangeRatio)
127 if (path.getStateCount() < 3)
131 maxSteps = path.getStateCount();
133 if (maxEmptySteps == 0)
134 maxEmptySteps = path.getStateCount();
137 unsigned int nochange = 0;
138 const base::SpaceInformationPtr &si = path.getSpaceInformation();
139 std::vector<base::State *> &states = path.getStates();
141 if (si->checkMotion(states.front(), states.back()))
144 for (std::size_t i = 2; i < states.size(); ++i)
145 si->freeState(states[i - 1]);
146 std::vector<base::State *> newStates(2);
147 newStates[0] = states.front();
148 newStates[1] = states.back();
149 states.swap(newStates);
153 for (
unsigned int i = 0; i < maxSteps && nochange < maxEmptySteps; ++i, ++nochange)
155 int count = states.size();
156 int maxN = count - 1;
157 int range = 1 + (int)(floor(0.5 + (
double)count * rangeRatio));
159 int p1 = rng_.uniformInt(0, maxN);
160 int p2 = rng_.uniformInt(std::max(p1 - range, 0), std::min(maxN, p1 + range));
161 if (abs(p1 - p2) < 2)
174 if (si->checkMotion(states[p1], states[p2]))
177 for (
int j = p1 + 1; j < p2; ++j)
178 si->freeState(states[j]);
179 states.erase(states.begin() + p1 + 1, states.begin() + p2);
188 unsigned int maxEmptySteps,
double rangeRatio,
double snapToVertex)
190 if (path.getStateCount() < 3)
194 maxSteps = path.getStateCount();
196 if (maxEmptySteps == 0)
197 maxEmptySteps = path.getStateCount();
199 const base::SpaceInformationPtr &si = path.getSpaceInformation();
200 std::vector<base::State *> &states = path.getStates();
203 std::vector<base::Cost> costs(states.size(), obj_->identityCost());
204 std::vector<double> dists(states.size(), 0.0);
205 for (
unsigned int i = 1; i < costs.size(); ++i)
207 costs[i] = obj_->combineCosts(costs[i - 1], obj_->motionCost(states[i - 1], states[i]));
208 dists[i] = dists[i - 1] + si->distance(states[i - 1], states[i]);
212 double threshold = dists.back() * snapToVertex;
214 double rd = rangeRatio * dists.back();
219 unsigned int nochange = 0;
222 for (
unsigned int i = 0; i < maxSteps && nochange < maxEmptySteps; ++i, ++nochange)
228 double distTo0 = rng_.uniformReal(0.0, dists.back());
230 std::lower_bound(dists.begin(), dists.end(), distTo0);
231 int pos0 = pit == dists.end() ? dists.size() - 1 :
234 if (pos0 == 0 || dists[pos0] - distTo0 < threshold)
238 while (pos0 > 0 && distTo0 < dists[pos0])
240 if (distTo0 - dists[pos0] < threshold)
249 rng_.uniformReal(std::max(0.0, distTo0 - rd),
250 std::min(distTo0 + rd, dists.back()));
251 pit = std::lower_bound(dists.begin(), dists.end(), distTo1);
252 int pos1 = pit == dists.end() ? dists.size() - 1 :
255 if (pos1 == 0 || dists[pos1] - distTo1 < threshold)
259 while (pos1 > 0 && distTo1 < dists[pos1])
261 if (distTo1 - dists[pos1] < threshold)
266 if (pos0 == pos1 || index0 == pos1 || index1 == pos0 || pos0 + 1 == index1 || pos1 + 1 == index0 ||
267 (index0 >= 0 && index1 >= 0 && abs(index0 - index1) < 2))
277 t0 = (distTo0 - dists[pos0]) / (dists[pos0 + 1] - dists[pos0]);
278 si->getStateSpace()->interpolate(states[pos0], states[pos0 + 1], t0, temp0);
289 t1 = (distTo1 - dists[pos1]) / (dists[pos1 + 1] - dists[pos1]);
290 si->getStateSpace()->interpolate(states[pos1], states[pos1 + 1], t1, temp1);
295 if (si->checkMotion(s0, s1))
299 std::swap(pos0, pos1);
300 std::swap(index0, index1);
306 base::Cost s0PartialCost = (index0 >= 0) ? obj_->identityCost() : obj_->motionCost(s0, states[pos0 + 1]);
307 base::Cost s1PartialCost = (index1 >= 0) ? obj_->identityCost() : obj_->motionCost(states[pos1], s1);
309 int posTemp = pos0 + 1;
310 while (posTemp < pos1)
312 alongPath = obj_->combineCosts(alongPath, obj_->motionCost(states[posTemp], states[posTemp + 1]));
315 alongPath = obj_->combineCosts(alongPath, s1PartialCost);
316 if (obj_->isCostBetterThan(alongPath, obj_->motionCost(s0, s1)))
325 if (index0 < 0 && index1 < 0)
327 if (pos0 + 1 == pos1)
329 si->copyState(states[pos1], s0);
330 states.insert(states.begin() + pos1 + 1, si->cloneState(s1));
335 for (
int j = pos0 + 2; j < pos1; ++j)
336 si->freeState(states[j]);
337 si->copyState(states[pos0 + 1], s0);
338 si->copyState(states[pos1], s1);
339 states.erase(states.begin() + pos0 + 2, states.begin() + pos1);
342 else if (index0 >= 0 && index1 >= 0)
345 for (
int j = index0 + 1; j < index1; ++j)
346 si->freeState(states[j]);
347 states.erase(states.begin() + index0 + 1, states.begin() + index1);
349 else if (index0 < 0 && index1 >= 0)
352 for (
int j = pos0 + 2; j < index1; ++j)
353 si->freeState(states[j]);
354 si->copyState(states[pos0 + 1], s0);
355 states.erase(states.begin() + pos0 + 2, states.begin() + index1);
357 else if (index0 >= 0 && index1 < 0)
360 for (
int j = index0 + 1; j < pos1; ++j)
361 si->freeState(states[j]);
362 si->copyState(states[pos1], s1);
363 states.erase(states.begin() + index0 + 1, states.begin() + pos1);
367 dists.resize(states.size(), 0.0);
368 costs.resize(states.size(), obj_->identityCost());
369 for (
unsigned int j = pos0 + 1; j < costs.size(); ++j)
371 costs[j] = obj_->combineCosts(costs[j - 1], obj_->motionCost(states[j - 1], states[j]));
372 dists[j] = dists[j - 1] + si->distance(states[j - 1], states[j]);
374 threshold = dists.back() * snapToVertex;
375 rd = rangeRatio * dists.back();
381 si->freeState(temp1);
382 si->freeState(temp0);
387 unsigned int maxEmptySteps,
double snapToVertex)
390 maxSteps = path.getStateCount();
392 if (maxEmptySteps == 0)
393 maxEmptySteps = path.getStateCount();
395 const base::SpaceInformationPtr &si = path.getSpaceInformation();
396 std::vector<base::State *> &states = path.getStates();
398 std::vector<double> dists(states.size(), 0.0);
399 for (
unsigned int i = 1; i < dists.size(); i++)
400 dists[i] = dists[i - 1] + si->distance(states[i - 1], states[i]);
402 std::vector<std::tuple<double, base::Cost, unsigned int>> distCostIndices;
403 for (
unsigned int i = 0; i < states.size() - 1; i++)
404 distCostIndices.emplace_back(si->distance(states[i], states[i + 1]), obj_->motionCost(states[i], states[i + 1]), i);
407 std::sort(distCostIndices.begin(), distCostIndices.end(),
408 [
this](std::tuple<double, base::Cost, unsigned int> a, std::tuple<double, base::Cost, unsigned int> b) {
409 return obj_->isCostBetterThan(std::get<1>(b), std::get<1>(a));
412 double threshold = dists.back() * snapToVertex;
415 unsigned int nochange = 0;
417 base::StateSamplerPtr sampler = si->allocStateSampler();
426 for (
unsigned int i = 0; i < maxSteps && nochange < maxEmptySteps; i++, nochange++)
430 double costBias = -1 * rng_.halfNormalReal(-dists.back(), 0.0, 20.0);
432 if (costBias >= dists.back())
434 z = distCostIndices.size() - 1;
435 costBias = std::get<0>(distCostIndices[z]);
440 while (costBias - std::get<0>(distCostIndices[z]) > std::numeric_limits<double>::epsilon())
442 costBias -= std::get<0>(distCostIndices[z]);
447 int pos, pos_before, pos_after;
448 double distTo = dists[std::get<2>(distCostIndices[z])] + costBias;
449 selectAlongPath(dists, states, distTo, threshold, perturb_state, pos);
452 int index_before = selectAlongPath(dists, states, distTo - stepSize / 2.0, threshold, before_state, pos_before);
453 int index_after = selectAlongPath(dists, states, distTo + stepSize / 2.0, threshold, after_state, pos_after);
455 if (index_before >= 0 && index_after >= 0 && index_before == index_after)
461 sampler->sampleUniform(new_state);
462 double dist = si->distance(perturb_state, new_state);
463 si->getStateSpace()->interpolate(perturb_state, new_state, stepSize / dist, new_state);
466 if (si->checkMotion(before_state, new_state) && si->checkMotion(new_state, after_state))
470 if (pos_before == pos_after)
472 alongPath = obj_->motionCost(before_state, after_state);
478 (index_before >= 0) ? obj_->identityCost() : obj_->motionCost(before_state, states[pos_before + 1]);
479 int posTemp = (index_before >= 0) ? index_before : pos_before + 1;
480 while (posTemp < pos_after)
482 alongPath = obj_->combineCosts(alongPath, obj_->motionCost(states[posTemp], states[posTemp + 1]));
486 (index_after >= 0) ? obj_->identityCost() : obj_->motionCost(states[pos_after], after_state);
487 alongPath = obj_->combineCosts(alongPath, afterPartialCost);
491 obj_->combineCosts(obj_->motionCost(before_state, new_state), obj_->motionCost(new_state, after_state));
492 if (obj_->isCostBetterThan(alongPath, newCost) || obj_->isCostEquivalentTo(alongPath, newCost))
499 if (index_before < 0 && index_after < 0)
501 if (pos_before == pos_after)
505 states.insert(states.begin() + pos_before + 1, si->cloneState(after_state));
506 states.insert(states.begin() + pos_before + 1, si->cloneState(new_state));
507 states.insert(states.begin() + pos_before + 1, si->cloneState(before_state));
509 else if (pos_before + 1 == pos_after)
511 si->copyState(states[pos_after], before_state);
512 states.insert(states.begin() + pos_after + 1, si->cloneState(after_state));
513 states.insert(states.begin() + pos_after + 1, si->cloneState(new_state));
515 else if (pos_before + 2 == pos_after)
517 si->copyState(states[pos_before + 1], before_state);
518 si->copyState(states[pos_after], new_state);
519 states.insert(states.begin() + pos_after + 1, si->cloneState(after_state));
523 si->copyState(states[pos_before + 1], before_state);
524 si->copyState(states[pos_before + 2], new_state);
525 si->copyState(states[pos_before + 3], after_state);
527 for (
int j = pos_before + 4; j < pos_after + 1; ++j)
528 si->freeState(states[j]);
529 states.erase(states.begin() + pos_before + 4, states.begin() + pos_after + 1);
532 else if (index_before >= 0 && index_after >= 0)
534 states.insert(states.begin() + index_before + 1, si->cloneState(new_state));
536 for (
int j = index_before + 2; j < index_after + 1; ++j)
537 si->freeState(states[j]);
538 states.erase(states.begin() + index_before + 2, states.begin() + index_after + 1);
540 else if (index_before < 0 && index_after >= 0)
542 if (index_after > pos_before + 1)
544 si->copyState(states[pos_before + 1], before_state);
545 states.insert(states.begin() + pos_before + 2, si->cloneState(new_state));
547 for (
int j = pos_before + 3; j < index_after + 1; ++j)
548 si->freeState(states[j]);
549 states.erase(states.begin() + pos_before + 3, states.begin() + index_after + 1);
553 states.insert(states.begin() + pos_before + 1, si->cloneState(new_state));
554 states.insert(states.begin() + pos_before + 1, si->cloneState(before_state));
557 else if (index_before >= 0 && index_after < 0)
559 if (pos_after > index_before)
561 si->copyState(states[pos_after], new_state);
562 states.insert(states.begin() + pos_after + 1, si->cloneState(after_state));
564 for (
int j = index_before + 1; j < pos_after; ++j)
565 si->freeState(states[j]);
566 states.erase(states.begin() + index_before + 1, states.begin() + pos_after);
570 states.insert(states.begin() + index_before + 1, si->cloneState(after_state));
571 states.insert(states.begin() + index_before + 1, si->cloneState(new_state));
576 dists.resize(states.size(), 0.0);
577 for (
unsigned int j = pos_before + 1; j < dists.size(); ++j)
579 dists[j] = dists[j - 1] + si->distance(states[j - 1], states[j]);
581 distCostIndices.clear();
582 for (
unsigned int i = 0; i < states.size() - 1; i++)
583 distCostIndices.emplace_back(si->distance(states[i], states[i + 1]),
584 obj_->motionCost(states[i], states[i + 1]), i);
588 distCostIndices.begin(), distCostIndices.end(),
589 [
this](std::tuple<double, base::Cost, unsigned int> a, std::tuple<double, base::Cost, unsigned int> b) {
590 return obj_->isCostBetterThan(std::get<1>(b), std::get<1>(a));
592 threshold = dists.back() * snapToVertex;
597 si->freeState(perturb_state);
598 si->freeState(before_state);
599 si->freeState(after_state);
600 si->freeState(new_state);
606 unsigned int maxEmptySteps)
608 if (path.getStateCount() < 3)
612 maxSteps = path.getStateCount();
614 if (maxEmptySteps == 0)
615 maxEmptySteps = path.getStateCount();
617 const base::SpaceInformationPtr &si = path.getSpaceInformation();
618 std::vector<base::State *> &states = path.getStates();
621 std::map<std::pair<const base::State *, const base::State *>,
double> distances;
622 for (
unsigned int i = 0; i < states.size(); ++i)
623 for (
unsigned int j = i + 2; j < states.size(); ++j)
624 distances[std::make_pair(states[i], states[j])] = si->distance(states[i], states[j]);
627 unsigned int nochange = 0;
628 for (
unsigned int s = 0; s < maxSteps && nochange < maxEmptySteps; ++s, ++nochange)
631 double minDist = std::numeric_limits<double>::infinity();
634 for (
unsigned int i = 0; i < states.size(); ++i)
635 for (
unsigned int j = i + 2; j < states.size(); ++j)
637 double d = distances[std::make_pair(states[i], states[j])];
646 if (p1 >= 0 && p2 >= 0)
648 if (si->checkMotion(states[p1], states[p2]))
651 for (
int i = p1 + 1; i < p2; ++i)
652 si->freeState(states[i]);
653 states.erase(states.begin() + p1 + 1, states.begin() + p2);
658 distances[std::make_pair(states[p1], states[p2])] = std::numeric_limits<double>::infinity();
669 return simplify(path, neverTerminate);
680 if (path.getStateCount() < 3)
683 bool tryMore =
true, valid =
true;
684 while ((ptc ==
false || atLeastOnce) && tryMore)
687 if ((ptc ==
false || atLeastOnce) && si_->getStateSpace()->isMetricSpace())
689 bool metricTryMore =
true;
690 unsigned int times = 0;
693 bool shortcut = shortcutPath(path);
695 gsr_ ? findBetterGoal(path, ptc) :
false;
697 metricTryMore = shortcut || better_goal;
698 }
while ((ptc ==
false || atLeastOnce) && ++times <= 5 && metricTryMore);
701 if (ptc ==
false || atLeastOnce)
702 smoothBSpline(path, 3, path.length() / 100.0);
704 if (ptc ==
false || atLeastOnce)
711 OMPL_WARN(
"Solution path may slightly touch on an invalid region of the state space");
714 OMPL_DEBUG(
"The solution path was slightly touching on an invalid region of the state space, but "
716 "successfully fixed.");
721 if (ptc ==
false || atLeastOnce)
722 tryMore = reduceVertices(path);
725 if (ptc ==
false || atLeastOnce)
726 collapseCloseVertices(path);
729 unsigned int times = 0;
730 while ((ptc ==
false || atLeastOnce) && tryMore && ++times <= 5)
731 tryMore = reduceVertices(path);
733 if ((ptc ==
false || atLeastOnce) && si_->getStateSpace()->isMetricSpace())
740 OMPL_WARN(
"Solution path may slightly touch on an invalid region of the state space");
743 OMPL_DEBUG(
"The solution path was slightly touching on an invalid region of the state space, but it "
745 "successfully fixed.");
750 return valid || path.check();
754 double rangeRatio,
double snapToVertex)
761 unsigned int samplingAttempts,
double rangeRatio,
764 if (path.getStateCount() < 2)
769 OMPL_WARN(
"%s: No goal sampleable object to sample a better goal from.",
"PathSimplifier::findBetterGoal");
773 unsigned int maxGoals = std::min((
unsigned)10, gsr_->maxSampleCount());
774 unsigned int failedTries = 0;
775 bool betterGoal =
false;
777 const base::StateSpacePtr &ss = si_->getStateSpace();
778 std::vector<base::State *> &states = path.getStates();
781 std::vector<base::Cost> costs(states.size(), obj_->identityCost());
782 std::vector<double> dists(states.size(), 0.0);
783 for (
unsigned int i = 1; i < dists.size(); ++i)
785 costs[i] = obj_->combineCosts(costs[i - 1], obj_->motionCost(states[i - 1], states[i]));
786 dists[i] = dists[i - 1] + si_->distance(states[i - 1], states[i]);
789 OMPL_WARN(
"%s: Somehow computed negative distance!.",
"PathSimplifier::findBetterGoal");
796 double threshold = dists.back() * snapToVertex;
798 double rd = rangeRatio * dists.back();
803 while (!ptc && failedTries++ < maxGoals && !betterGoal)
805 gsr_->sampleGoal(tempGoal);
808 if (!gsr_->isStartGoalPairValid(path.getState(0), tempGoal))
811 unsigned int numSamples = 0;
812 while (!ptc && numSamples++ < samplingAttempts && !betterGoal)
815 double t = rng_.uniformReal(std::max(dists.back() - rd, 0.0),
818 auto end = std::lower_bound(dists.begin(), dists.end(), t);
820 while (start != dists.begin() && *start >= t)
823 unsigned int startIndex = start - dists.begin();
824 unsigned int endIndex = end - dists.begin();
827 if (t - (*start) < threshold)
828 endIndex = startIndex;
829 if ((*end) - t < threshold)
830 startIndex = endIndex;
835 if (startIndex == endIndex)
837 state = states[startIndex];
841 double tSeg = (t - (*start)) / (*end - *start);
842 ss->interpolate(states[startIndex], states[endIndex], tSeg, temp);
845 costToCome = obj_->combineCosts(costToCome, obj_->motionCost(states[startIndex], state));
848 base::Cost costToGo = obj_->motionCost(state, tempGoal);
849 base::Cost candidateCost = obj_->combineCosts(costToCome, costToGo);
852 if (obj_->isCostBetterThan(candidateCost, costs.back()) && si_->checkMotion(state, tempGoal))
855 if (startIndex == endIndex)
858 si_->copyState(states[startIndex], state);
860 si_->copyState(states[startIndex + 1], tempGoal);
864 for (
size_t i = startIndex + 2; i < states.size(); ++i)
865 si_->freeState(states[i]);
867 states.erase(states.begin() + startIndex + 2, states.end());
872 si_->copyState(states[endIndex], state);
873 if (endIndex == states.size() - 1)
875 path.append(tempGoal);
880 si_->copyState(states[endIndex + 1], tempGoal);
883 for (
size_t i = endIndex + 2; i < states.size(); ++i)
884 si_->freeState(states[i]);
886 states.erase(states.begin() + endIndex + 2, states.end());
891 costs.resize(states.size(), obj_->identityCost());
892 dists.resize(states.size(), 0.0);
893 for (
unsigned int j = std::max(1u, startIndex); j < dists.size(); ++j)
895 costs[j] = obj_->combineCosts(costs[j - 1], obj_->motionCost(states[j - 1], states[j]));
896 dists[j] = dists[j - 1] + si_->distance(states[j - 1], states[j]);
904 si_->freeState(temp);
905 si_->freeState(tempGoal);
910 int ompl::geometric::PathSimplifier::selectAlongPath(std::vector<double> dists, std::vector<base::State *> states,
911 double distTo,
double threshold,
base::State *select_state,
916 else if (distTo > dists.back())
917 distTo = dists.back();
920 auto pit = std::lower_bound(dists.begin(), dists.end(), distTo);
921 pos = pit == dists.end() ? dists.size() - 1 : pit - dists.begin();
923 if (pos == 0 || dists[pos] - distTo < threshold)
927 while (pos > 0 && distTo < dists[pos])
929 if (distTo - dists[pos] < threshold)
935 si_->copyState(select_state, states[index]);
940 double t = (distTo - dists[pos]) / (dists[pos + 1] - dists[pos]);
941 si_->getStateSpace()->interpolate(states[pos], states[pos + 1], t, select_state);