10 #include <Eigen/Geometry>
12 #include <SimoxUtility/algorithm/apply.hpp>
16 #include "range/v3/algorithm/find.hpp"
17 #include "range/v3/numeric/iota.hpp"
23 points(points), params(params)
26 indices.resize(points.size());
27 ranges::iota(indices, 0);
36 const auto maxIterConditionReached = [&]()
49 if (maxIterConditionReached())
53 .iterations = iterations};
56 if (not approximateStep())
60 .iterations = iterations,
61 .reductionFactor = 1.F -
static_cast<float>(indices.size()) /
62 static_cast<float>(points.size())};
69 ChainApproximation::Triplets
70 ChainApproximation::getTriplets()
const
72 const int nIndices =
static_cast<int>(indices.size());
80 triplets.reserve(indices.size());
87 triplets.emplace_back(indices.back(), indices.front(), indices.at(1));
90 for (
int i = 1; i < (nIndices - 1); i++)
92 triplets.emplace_back(indices.at(i - 1), indices.at(i), indices.at(i + 1));
96 triplets.emplace_back(indices.back(), indices.front(), indices.at(1));
102 ChainApproximation::computeDistances(
const ChainApproximation::Triplets& triplets)
104 std::vector<float> distances;
105 distances.reserve(triplets.size());
109 std::back_inserter(distances),
110 [&](
const auto& triplet) { return computeDistance(triplet); });
116 ChainApproximation::computeDistance(
const ChainApproximation::Triplet& triplet)
const
118 using Line = Eigen::ParametrizedLine<float, 2>;
120 const Eigen::Vector2f& ptBefore = points.at(triplet.a);
121 const Eigen::Vector2f& ptPivot = points.at(triplet.b);
122 const Eigen::Vector2f& ptAfter = points.at(triplet.c);
124 const auto line = Line::Through(ptBefore, ptAfter);
125 return line.distance(ptPivot);
129 ChainApproximation::approximateStep()
131 const size_t nIndices = indices.size();
137 const Triplets triplets = getTriplets();
138 const std::vector<float> distances = computeDistances(triplets);
141 const int n =
static_cast<int>(triplets.size());
143 std::vector<int> indicesToBeRemoved;
146 for (
int i = 1; i < n - 1; i++)
148 const auto&
distance = distances.at(i);
159 indicesToBeRemoved.emplace_back(triplets.at(i).b);
164 if (indicesToBeRemoved.empty())
169 const auto isMatch = [&](
const int& idx) ->
bool
170 {
return ranges::find(indicesToBeRemoved, idx) != indicesToBeRemoved.end(); };
172 indices.erase(std::remove_if(indices.begin(), indices.end(), isMatch), indices.end());
180 return simox::alg::apply(indices, [&](
const auto& idx) {
return points.at(idx); });
188 const std::string condStr = [&res]() -> std::string
194 case TerminationCondition::Converged:
197 case TerminationCondition::IterationLimit:
198 repr =
"IterationLimit";
204 str <<
"ApproximationResult: ["
205 <<
"condition: " << condStr <<
" | "