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);
189 if (path.getStateCount() < 3)
192 const base::SpaceInformationPtr &si = path.getSpaceInformation();
193 std::vector<base::State *> &states = path.getStates();
197 for (std::size_t i = 0; i < states.size() - 1; ++i)
199 double dist = si->distance(states[i], states[i + 1]);
202 std::size_t numIntermediateStates =
static_cast<std::size_t
>(floor(dist / delta));
203 double t = 1.0 / (numIntermediateStates + 1);
204 for (std::size_t j = 0; j < numIntermediateStates; ++j)
207 si->getStateSpace()->interpolate(states[i], states[i + 1 + j], t * (j + 1), newState);
208 states.insert(states.begin() + i + 1 + j, newState);
210 i = i + numIntermediateStates;
216 std::vector<base::Cost> costs(states.size(), obj_->identityCost());
217 for (std::size_t i = 1; i < costs.size(); ++i)
219 costs[i] = obj_->combineCosts(costs[i - 1], obj_->motionCost(states[i - 1], states[i]));
226 for (std::size_t i = 0; i < states.size() - 2; ++i)
229 for (std::size_t j = states.size() - 1; j > i + 1; --j)
232 if (si->checkMotion(states[i], states[j]))
234 base::Cost shortcutCost = obj_->motionCost(states[i], states[j]);
235 base::Cost alongPath = obj_->subtractCosts(costs[j], costs[i]);
238 if (obj_->isCostBetterThan(obj_->subtractCosts(alongPath, shortcutCost), equivalenceCost))
240 if (j == states.size() - 1)
247 if (obj_->isCostBetterThan(shortcutCost, alongPath))
251 for (std::size_t k = i + 1; k < j; ++k)
252 si->freeState(states[k]);
253 states.erase(states.begin() + i + 1, states.begin() + j);
256 double dist = si->distance(states[i], states[j]);
259 std::size_t numIntermediateStates = (int)(floor(dist / delta));
260 double t = 1.0 / (numIntermediateStates + 1);
261 for (std::size_t k = 0; k < numIntermediateStates; ++k)
264 si->getStateSpace()->interpolate(states[i], states[i + 1 + k], t * (k + 1), newState);
265 states.insert(states.begin() + i + 1 + k, newState);
270 costs.resize(states.size(), obj_->identityCost());
271 for (std::size_t k = i + 1; k < costs.size(); ++k)
273 costs[k] = obj_->combineCosts(costs[k - 1], obj_->motionCost(states[k - 1], states[k]));
277 if (j == states.size() - 1)
294 unsigned int maxEmptySteps,
double rangeRatio,
297 if (path.getStateCount() < 3)
301 maxSteps = path.getStateCount();
303 if (maxEmptySteps == 0)
304 maxEmptySteps = path.getStateCount();
306 const base::SpaceInformationPtr &si = path.getSpaceInformation();
307 std::vector<base::State *> &states = path.getStates();
310 std::vector<base::Cost> costs(states.size(), obj_->identityCost());
311 std::vector<double> dists(states.size(), 0.0);
312 for (
unsigned int i = 1; i < costs.size(); ++i)
314 costs[i] = obj_->combineCosts(costs[i - 1], obj_->motionCost(states[i - 1], states[i]));
315 dists[i] = dists[i - 1] + si->distance(states[i - 1], states[i]);
319 double threshold = dists.back() * snapToVertex;
321 double rd = rangeRatio * dists.back();
326 unsigned int nochange = 0;
329 for (
unsigned int i = 0; i < maxSteps && nochange < maxEmptySteps; ++i, ++nochange)
335 double distTo0 = rng_.uniformReal(0.0, dists.back());
337 std::lower_bound(dists.begin(), dists.end(), distTo0);
338 int pos0 = pit == dists.end() ? dists.size() - 1 :
341 if (pos0 == 0 || dists[pos0] - distTo0 < threshold)
345 while (pos0 > 0 && distTo0 < dists[pos0])
347 if (distTo0 - dists[pos0] < threshold)
356 rng_.uniformReal(std::max(0.0, distTo0 - rd),
357 std::min(distTo0 + rd, dists.back()));
358 pit = std::lower_bound(dists.begin(), dists.end(), distTo1);
359 int pos1 = pit == dists.end() ? dists.size() - 1 :
362 if (pos1 == 0 || dists[pos1] - distTo1 < threshold)
366 while (pos1 > 0 && distTo1 < dists[pos1])
368 if (distTo1 - dists[pos1] < threshold)
373 if (pos0 == pos1 || index0 == pos1 || index1 == pos0 || pos0 + 1 == index1 || pos1 + 1 == index0 ||
374 (index0 >= 0 && index1 >= 0 && abs(index0 - index1) < 2))
384 t0 = (distTo0 - dists[pos0]) / (dists[pos0 + 1] - dists[pos0]);
385 si->getStateSpace()->interpolate(states[pos0], states[pos0 + 1], t0, temp0);
396 t1 = (distTo1 - dists[pos1]) / (dists[pos1 + 1] - dists[pos1]);
397 si->getStateSpace()->interpolate(states[pos1], states[pos1 + 1], t1, temp1);
402 if (si->checkMotion(s0, s1))
406 std::swap(pos0, pos1);
407 std::swap(index0, index1);
413 base::Cost s0PartialCost = (index0 >= 0) ? obj_->identityCost() : obj_->motionCost(s0, states[pos0 + 1]);
414 base::Cost s1PartialCost = (index1 >= 0) ? obj_->identityCost() : obj_->motionCost(states[pos1], s1);
416 int posTemp = pos0 + 1;
417 while (posTemp < pos1)
419 alongPath = obj_->combineCosts(alongPath, obj_->motionCost(states[posTemp], states[posTemp + 1]));
422 alongPath = obj_->combineCosts(alongPath, s1PartialCost);
423 if (obj_->isCostBetterThan(alongPath, obj_->motionCost(s0, s1)))
432 if (index0 < 0 && index1 < 0)
434 if (pos0 + 1 == pos1)
436 si->copyState(states[pos1], s0);
437 states.insert(states.begin() + pos1 + 1, si->cloneState(s1));
442 for (
int j = pos0 + 2; j < pos1; ++j)
443 si->freeState(states[j]);
444 si->copyState(states[pos0 + 1], s0);
445 si->copyState(states[pos1], s1);
446 states.erase(states.begin() + pos0 + 2, states.begin() + pos1);
449 else if (index0 >= 0 && index1 >= 0)
452 for (
int j = index0 + 1; j < index1; ++j)
453 si->freeState(states[j]);
454 states.erase(states.begin() + index0 + 1, states.begin() + index1);
456 else if (index0 < 0 && index1 >= 0)
459 for (
int j = pos0 + 2; j < index1; ++j)
460 si->freeState(states[j]);
461 si->copyState(states[pos0 + 1], s0);
462 states.erase(states.begin() + pos0 + 2, states.begin() + index1);
464 else if (index0 >= 0 && index1 < 0)
467 for (
int j = index0 + 1; j < pos1; ++j)
468 si->freeState(states[j]);
469 si->copyState(states[pos1], s1);
470 states.erase(states.begin() + index0 + 1, states.begin() + pos1);
474 dists.resize(states.size(), 0.0);
475 costs.resize(states.size(), obj_->identityCost());
476 for (
unsigned int j = pos0 + 1; j < costs.size(); ++j)
478 costs[j] = obj_->combineCosts(costs[j - 1], obj_->motionCost(states[j - 1], states[j]));
479 dists[j] = dists[j - 1] + si->distance(states[j - 1], states[j]);
481 threshold = dists.back() * snapToVertex;
482 rd = rangeRatio * dists.back();
488 si->freeState(temp1);
489 si->freeState(temp0);
494 unsigned int maxEmptySteps,
double snapToVertex)
497 maxSteps = path.getStateCount();
499 if (maxEmptySteps == 0)
500 maxEmptySteps = path.getStateCount();
502 const base::SpaceInformationPtr &si = path.getSpaceInformation();
503 std::vector<base::State *> &states = path.getStates();
505 std::vector<double> dists(states.size(), 0.0);
506 for (
unsigned int i = 1; i < dists.size(); i++)
507 dists[i] = dists[i - 1] + si->distance(states[i - 1], states[i]);
509 std::vector<std::tuple<double, base::Cost, unsigned int>> distCostIndices;
510 for (
unsigned int i = 0; i < states.size() - 1; i++)
511 distCostIndices.emplace_back(si->distance(states[i], states[i + 1]), obj_->motionCost(states[i], states[i + 1]),
515 std::sort(distCostIndices.begin(), distCostIndices.end(),
516 [
this](std::tuple<double, base::Cost, unsigned int> a, std::tuple<double, base::Cost, unsigned int> b) {
517 return obj_->isCostBetterThan(std::get<1>(b), std::get<1>(a));
520 double threshold = dists.back() * snapToVertex;
523 unsigned int nochange = 0;
525 base::StateSamplerPtr sampler = si->allocStateSampler();
534 for (
unsigned int i = 0; i < maxSteps && nochange < maxEmptySteps; i++, nochange++)
538 double costBias = -1 * rng_.halfNormalReal(-dists.back(), 0.0, 20.0);
540 if (costBias >= dists.back())
542 z = distCostIndices.size() - 1;
543 costBias = std::get<0>(distCostIndices[z]);
548 while (costBias - std::get<0>(distCostIndices[z]) > std::numeric_limits<double>::epsilon())
550 costBias -= std::get<0>(distCostIndices[z]);
555 int pos, pos_before, pos_after;
556 double distTo = dists[std::get<2>(distCostIndices[z])] + costBias;
557 selectAlongPath(dists, states, distTo, threshold, perturb_state, pos);
560 int index_before = selectAlongPath(dists, states, distTo - stepSize / 2.0, threshold, before_state, pos_before);
561 int index_after = selectAlongPath(dists, states, distTo + stepSize / 2.0, threshold, after_state, pos_after);
563 if (index_before >= 0 && index_after >= 0 && index_before == index_after)
569 sampler->sampleUniform(new_state);
570 double dist = si->distance(perturb_state, new_state);
571 si->getStateSpace()->interpolate(perturb_state, new_state, stepSize / dist, new_state);
574 if (si->checkMotion(before_state, new_state) && si->checkMotion(new_state, after_state))
578 if (pos_before == pos_after)
580 alongPath = obj_->motionCost(before_state, after_state);
586 (index_before >= 0) ? obj_->identityCost() : obj_->motionCost(before_state, states[pos_before + 1]);
587 int posTemp = (index_before >= 0) ? index_before : pos_before + 1;
588 while (posTemp < pos_after)
590 alongPath = obj_->combineCosts(alongPath, obj_->motionCost(states[posTemp], states[posTemp + 1]));
594 (index_after >= 0) ? obj_->identityCost() : obj_->motionCost(states[pos_after], after_state);
595 alongPath = obj_->combineCosts(alongPath, afterPartialCost);
599 obj_->combineCosts(obj_->motionCost(before_state, new_state), obj_->motionCost(new_state, after_state));
600 if (obj_->isCostBetterThan(alongPath, newCost) || obj_->isCostEquivalentTo(alongPath, newCost))
607 if (index_before < 0 && index_after < 0)
609 if (pos_before == pos_after)
613 states.insert(states.begin() + pos_before + 1, si->cloneState(after_state));
614 states.insert(states.begin() + pos_before + 1, si->cloneState(new_state));
615 states.insert(states.begin() + pos_before + 1, si->cloneState(before_state));
617 else if (pos_before + 1 == pos_after)
619 si->copyState(states[pos_after], before_state);
620 states.insert(states.begin() + pos_after + 1, si->cloneState(after_state));
621 states.insert(states.begin() + pos_after + 1, si->cloneState(new_state));
623 else if (pos_before + 2 == pos_after)
625 si->copyState(states[pos_before + 1], before_state);
626 si->copyState(states[pos_after], new_state);
627 states.insert(states.begin() + pos_after + 1, si->cloneState(after_state));
631 si->copyState(states[pos_before + 1], before_state);
632 si->copyState(states[pos_before + 2], new_state);
633 si->copyState(states[pos_before + 3], after_state);
635 for (
int j = pos_before + 4; j < pos_after + 1; ++j)
636 si->freeState(states[j]);
637 states.erase(states.begin() + pos_before + 4, states.begin() + pos_after + 1);
640 else if (index_before >= 0 && index_after >= 0)
642 states.insert(states.begin() + index_before + 1, si->cloneState(new_state));
644 for (
int j = index_before + 2; j < index_after + 1; ++j)
645 si->freeState(states[j]);
646 states.erase(states.begin() + index_before + 2, states.begin() + index_after + 1);
648 else if (index_before < 0 && index_after >= 0)
650 if (index_after > pos_before + 1)
652 si->copyState(states[pos_before + 1], before_state);
653 states.insert(states.begin() + pos_before + 2, si->cloneState(new_state));
655 for (
int j = pos_before + 3; j < index_after + 1; ++j)
656 si->freeState(states[j]);
657 states.erase(states.begin() + pos_before + 3, states.begin() + index_after + 1);
661 states.insert(states.begin() + pos_before + 1, si->cloneState(new_state));
662 states.insert(states.begin() + pos_before + 1, si->cloneState(before_state));
665 else if (index_before >= 0 && index_after < 0)
667 if (pos_after > index_before)
669 si->copyState(states[pos_after], new_state);
670 states.insert(states.begin() + pos_after + 1, si->cloneState(after_state));
672 for (
int j = index_before + 1; j < pos_after; ++j)
673 si->freeState(states[j]);
674 states.erase(states.begin() + index_before + 1, states.begin() + pos_after);
678 states.insert(states.begin() + index_before + 1, si->cloneState(after_state));
679 states.insert(states.begin() + index_before + 1, si->cloneState(new_state));
684 dists.resize(states.size(), 0.0);
685 for (
unsigned int j = pos_before + 1; j < dists.size(); ++j)
687 dists[j] = dists[j - 1] + si->distance(states[j - 1], states[j]);
689 distCostIndices.clear();
690 for (
unsigned int i = 0; i < states.size() - 1; i++)
691 distCostIndices.emplace_back(si->distance(states[i], states[i + 1]),
692 obj_->motionCost(states[i], states[i + 1]), i);
696 distCostIndices.begin(), distCostIndices.end(),
697 [
this](std::tuple<double, base::Cost, unsigned int> a, std::tuple<double, base::Cost, unsigned int> b) {
698 return obj_->isCostBetterThan(std::get<1>(b), std::get<1>(a));
700 threshold = dists.back() * snapToVertex;
705 si->freeState(perturb_state);
706 si->freeState(before_state);
707 si->freeState(after_state);
708 si->freeState(new_state);
714 unsigned int maxEmptySteps)
716 if (path.getStateCount() < 3)
720 maxSteps = path.getStateCount();
722 if (maxEmptySteps == 0)
723 maxEmptySteps = path.getStateCount();
725 const base::SpaceInformationPtr &si = path.getSpaceInformation();
726 std::vector<base::State *> &states = path.getStates();
729 std::map<std::pair<const base::State *, const base::State *>,
double> distances;
730 for (
unsigned int i = 0; i < states.size(); ++i)
731 for (
unsigned int j = i + 2; j < states.size(); ++j)
732 distances[std::make_pair(states[i], states[j])] = si->distance(states[i], states[j]);
735 unsigned int nochange = 0;
736 for (
unsigned int s = 0; s < maxSteps && nochange < maxEmptySteps; ++s, ++nochange)
739 double minDist = std::numeric_limits<double>::infinity();
742 for (
unsigned int i = 0; i < states.size(); ++i)
743 for (
unsigned int j = i + 2; j < states.size(); ++j)
745 double d = distances[std::make_pair(states[i], states[j])];
754 if (p1 >= 0 && p2 >= 0)
756 if (si->checkMotion(states[p1], states[p2]))
759 for (
int i = p1 + 1; i < p2; ++i)
760 si->freeState(states[i]);
761 states.erase(states.begin() + p1 + 1, states.begin() + p2);
766 distances[std::make_pair(states[p1], states[p2])] = std::numeric_limits<double>::infinity();
777 return simplify(path, neverTerminate);
788 if (path.getStateCount() < 3)
791 bool tryMore =
true, valid =
true;
792 while ((ptc ==
false || atLeastOnce) && tryMore)
795 if ((ptc ==
false || atLeastOnce) && si_->getStateSpace()->isMetricSpace())
797 bool metricTryMore =
true;
798 unsigned int times = 0;
801 bool shortcut = partialShortcutPath(path);
803 gsr_ ? findBetterGoal(path, ptc) :
false;
805 metricTryMore = shortcut || better_goal;
806 }
while ((ptc ==
false || atLeastOnce) && ++times <= 5 && metricTryMore);
809 if (ptc ==
false || atLeastOnce)
810 smoothBSpline(path, 3, path.length() / 100.0);
812 if (ptc ==
false || atLeastOnce)
819 OMPL_WARN(
"Solution path may slightly touch on an invalid region of the state space");
822 OMPL_DEBUG(
"The solution path was slightly touching on an invalid region of the state space, but "
824 "successfully fixed.");
829 if (ptc ==
false || atLeastOnce)
830 tryMore = reduceVertices(path);
833 if (ptc ==
false || atLeastOnce)
834 collapseCloseVertices(path);
837 unsigned int times = 0;
838 while ((ptc ==
false || atLeastOnce) && tryMore && ++times <= 5)
839 tryMore = reduceVertices(path);
841 if ((ptc ==
false || atLeastOnce) && si_->getStateSpace()->isMetricSpace())
848 OMPL_WARN(
"Solution path may slightly touch on an invalid region of the state space");
851 OMPL_DEBUG(
"The solution path was slightly touching on an invalid region of the state space, but it "
853 "successfully fixed.");
858 return valid || path.check();
862 double rangeRatio,
double snapToVertex)
869 unsigned int samplingAttempts,
double rangeRatio,
872 if (path.getStateCount() < 2)
877 OMPL_WARN(
"%s: No goal sampleable object to sample a better goal from.",
"PathSimplifier::findBetterGoal");
881 unsigned int maxGoals = std::min((
unsigned)10, gsr_->maxSampleCount());
882 unsigned int failedTries = 0;
883 bool betterGoal =
false;
885 const base::StateSpacePtr &ss = si_->getStateSpace();
886 std::vector<base::State *> &states = path.getStates();
889 std::vector<base::Cost> costs(states.size(), obj_->identityCost());
890 std::vector<double> dists(states.size(), 0.0);
891 for (
unsigned int i = 1; i < dists.size(); ++i)
893 costs[i] = obj_->combineCosts(costs[i - 1], obj_->motionCost(states[i - 1], states[i]));
894 dists[i] = dists[i - 1] + si_->distance(states[i - 1], states[i]);
897 OMPL_WARN(
"%s: Somehow computed negative distance!.",
"PathSimplifier::findBetterGoal");
904 double threshold = dists.back() * snapToVertex;
906 double rd = rangeRatio * dists.back();
911 while (!ptc && failedTries++ < maxGoals && !betterGoal)
913 gsr_->sampleGoal(tempGoal);
916 if (!gsr_->isStartGoalPairValid(path.getState(0), tempGoal))
919 unsigned int numSamples = 0;
920 while (!ptc && numSamples++ < samplingAttempts && !betterGoal)
923 double t = rng_.uniformReal(std::max(dists.back() - rd, 0.0),
926 auto end = std::lower_bound(dists.begin(), dists.end(), t);
928 while (start != dists.begin() && *start >= t)
931 unsigned int startIndex = start - dists.begin();
932 unsigned int endIndex = end - dists.begin();
935 if (t - (*start) < threshold)
936 endIndex = startIndex;
937 if ((*end) - t < threshold)
938 startIndex = endIndex;
943 if (startIndex == endIndex)
945 state = states[startIndex];
949 double tSeg = (t - (*start)) / (*end - *start);
950 ss->interpolate(states[startIndex], states[endIndex], tSeg, temp);
953 costToCome = obj_->combineCosts(costToCome, obj_->motionCost(states[startIndex], state));
956 base::Cost costToGo = obj_->motionCost(state, tempGoal);
957 base::Cost candidateCost = obj_->combineCosts(costToCome, costToGo);
960 if (obj_->isCostBetterThan(candidateCost, costs.back()) && si_->checkMotion(state, tempGoal))
963 if (startIndex == endIndex)
966 si_->copyState(states[startIndex], state);
968 si_->copyState(states[startIndex + 1], tempGoal);
972 for (
size_t i = startIndex + 2; i < states.size(); ++i)
973 si_->freeState(states[i]);
975 states.erase(states.begin() + startIndex + 2, states.end());
980 si_->copyState(states[endIndex], state);
981 if (endIndex == states.size() - 1)
983 path.append(tempGoal);
988 si_->copyState(states[endIndex + 1], tempGoal);
991 for (
size_t i = endIndex + 2; i < states.size(); ++i)
992 si_->freeState(states[i]);
994 states.erase(states.begin() + endIndex + 2, states.end());
999 costs.resize(states.size(), obj_->identityCost());
1000 dists.resize(states.size(), 0.0);
1001 for (
unsigned int j = std::max(1u, startIndex); j < dists.size(); ++j)
1003 costs[j] = obj_->combineCosts(costs[j - 1], obj_->motionCost(states[j - 1], states[j]));
1004 dists[j] = dists[j - 1] + si_->distance(states[j - 1], states[j]);
1012 si_->freeState(temp);
1013 si_->freeState(tempGoal);
1018 int ompl::geometric::PathSimplifier::selectAlongPath(std::vector<double> dists, std::vector<base::State *> states,
1019 double distTo,
double threshold,
base::State *select_state,
1024 else if (distTo > dists.back())
1025 distTo = dists.back();
1028 auto pit = std::lower_bound(dists.begin(), dists.end(), distTo);
1029 pos = pit == dists.end() ? dists.size() - 1 : pit - dists.begin();
1031 if (pos == 0 || dists[pos] - distTo < threshold)
1035 while (pos > 0 && distTo < dists[pos])
1037 if (distTo - dists[pos] < threshold)
1043 si_->copyState(select_state, states[index]);
1048 double t = (distTo - dists[pos]) / (dists[pos + 1] - dists[pos]);
1049 si_->getStateSpace()->interpolate(states[pos], states[pos + 1], t, select_state);