FeatureMerger.cpp
Go to the documentation of this file.
1 #include "FeatureMerger.h"
2 
3 #include <cstddef>
4 #include <optional>
5 #include <utility>
6 #include <vector>
7 
9 
13 
14 #include <range/v3/view/enumerate.hpp>
15 #include <range/v3/view/sliding.hpp>
16 
18 {
19 
20 
21  FeatureMerger::FeatureMerger(std::vector<Features>&& features,
22  const ChainApproximation::Params& chainApproximationParams) :
23  inputFeatures(std::move(features)), chainApproximationParams(chainApproximationParams)
24  {
25  }
26 
27  FeatureMerger::FeatureMerger(const std::vector<Features>& features,
28  const ChainApproximation::Params& chainApproximationParams) :
29  inputFeatures(features), chainApproximationParams(chainApproximationParams)
30  {
31  }
32 
33  std::vector<Features>
35  {
36  ARMARX_DEBUG << "Starting merge of " << inputFeatures.size() << " features";
37  UnionFind uf{inputFeatures.size()};
38 
39  for (const auto [i, f] : ranges::views::enumerate(inputFeatures))
40  {
41  std::optional<std::size_t> lastFeature = std::nullopt;
42  for (const auto& p : f.points)
43  {
44  if (auto res = checkPoint(p, i, lastFeature); res)
45  {
46  uf.unite(i, res.value());
47  lastFeature = res.value();
48  }
49  }
50  }
51 
52  for (const auto [i, f] : ranges::views::enumerate(inputFeatures))
53  {
54  std::size_t representative = uf.find(i);
55  if (i != representative)
56  {
57  ARMARX_DEBUG << "add feature " << i << " to feature " << representative;
58  addToFeature(inputFeatures[representative], f);
59  }
60  }
61 
62  std::vector<Features> merged;
63  for (const auto [i, f] : ranges::views::enumerate(inputFeatures))
64  {
65  if (i == uf.find(i))
66  {
67  ARMARX_DEBUG << "feature " << i << " is representative";
68  merged.push_back(f);
69  }
70  }
71  // recalculate convex hull etc. for all merged features
72  recalculateFeatures(merged);
73 
74  ARMARX_DEBUG << "Merged " << inputFeatures.size() << " features into " << merged.size();
75  return merged;
76  }
77 
78  bool
79  FeatureMerger::insideConvexPoly(const Eigen::Vector2f& p,
80  const std::vector<Eigen::Vector2f>& vertices)
81  {
82  // algorithm to check whether a point is inside a convex polygon
83  // see https://stackoverflow.com/questions/1119627/how-to-test-if-a-point-is-inside-of-a-convex-polygon-in-2d-integer-coordinates
84 
85  const auto signum = [](float x)
86  {
87  if (x == 0)
88  return 0;
89  return x > 0 ? 1 : -1;
90  };
91 
92  const auto checkSide = [&](const Eigen::Vector2f& a, const Eigen::Vector2f& b)
93  { return signum((p.x() - a.x()) * (b.y() - a.y()) - (p.y() - a.y()) * (b.x() - a.x())); };
94 
95  float previousSide = 0;
96  for (const auto edge : vertices | ranges::views::sliding(2))
97  {
98  int d = checkSide(edge[0], edge[1]);
99  if (d == 0)
100  return true;
101 
102  if (previousSide != 0 && d != previousSide)
103  {
104  return false;
105  }
106  previousSide = d;
107  }
108  int d = checkSide(vertices.back(), vertices.front());
109  if (d == 0)
110  return true;
111  return d == previousSide;
112  }
113 
114  std::optional<std::size_t>
115  FeatureMerger::checkPoint(const Eigen::Vector2f p,
116  std::size_t ignore,
117  const std::optional<std::size_t> checkFirst)
118  {
119  // when try first is given check this feature before all others
120  if (checkFirst)
121  {
122  if (insideConvexPoly(p, inputFeatures[checkFirst.value()].convexHull->vertices))
123  {
124  return checkFirst.value();
125  }
126  }
127 
128  for (const auto [i, f] : ranges::views::enumerate(inputFeatures))
129  {
130  if (i == ignore || (checkFirst && i == checkFirst.value()))
131  continue;
132 
133  if (insideConvexPoly(p, f.convexHull->vertices))
134  {
135  return i;
136  }
137  }
138  return std::nullopt;
139  }
140 
141  void
142  FeatureMerger::addToFeature(Features& f, const Features& toAdd)
143  {
144  f.points.insert(f.points.end(), toAdd.points.begin(), toAdd.points.end());
145 
146  f.convexHull = std::nullopt;
147  f.circle = std::nullopt;
148  f.ellipsoid = std::nullopt;
149  f.chain = std::nullopt;
150  }
151 
152  void
153  FeatureMerger::recalculateFeatures(std::vector<Features>& features)
154  {
155  for (auto& f : features)
156  {
157  if (!f.convexHull)
158  {
159  f.convexHull = FeatureExtractor::convexHull(f.points);
160  }
161 
162  if (!f.circle)
163  {
164  f.circle = FeatureExtractor::circle(f.points);
165  }
166 
167  // if (!f.ellipsoid)
168  // {
169  // f.ellipsoid = FeatureExtractor::ellipsoid(f.convexHull);
170  // }
171 
172  if (!f.chain)
173  {
175  f.points, f.convexHull, chainApproximationParams);
176  }
177  }
178  }
179 
180 
181 } // namespace armarx::navigation::components::laser_scanner_feature_extraction
UnionFind.h
armarx::navigation::components::laser_scanner_feature_extraction::FeatureExtractor::convexHull
static std::optional< VirtualRobot::MathTools::ConvexHull2D > convexHull(const Points &points)
Definition: FeatureExtractor.cpp:123
armarx::detail::ChainApproximationParams
Definition: ChainApproximation.h:34
armarx::navigation::components::laser_scanner_feature_extraction::FeatureExtractor::chainApproximation
static std::optional< Points > chainApproximation(const Points &points, const std::optional< VirtualRobot::MathTools::ConvexHull2D > &convexHull, const ChainApproximation::Params &params)
Definition: FeatureExtractor.cpp:209
FeatureMerger.h
FeatureExtractor.h
armarx::ctrlutil::a
double a(double t, double a0, double j)
Definition: CtrlUtil.h:45
armarx::navigation::components::laser_scanner_feature_extraction::FeatureMerger::merge
std::vector< Features > merge()
Definition: FeatureMerger.cpp:34
ARMARX_DEBUG
#define ARMARX_DEBUG
Definition: Logging.h:184
armarx::conversions::Features
armarx::navigation::components::laser_scanner_feature_extraction::Features Features
Definition: features.cpp:12
ChainApproximation.h
armarx::navigation::components::laser_scanner_feature_extraction::FeatureExtractor::circle
static std::optional< Circle > circle(const Points &circle)
Definition: FeatureExtractor.cpp:190
armarx::navigation::components::laser_scanner_feature_extraction::FeatureMerger::insideConvexPoly
static bool insideConvexPoly(const Eigen::Vector2f &p, const std::vector< Eigen::Vector2f > &vertices)
Definition: FeatureMerger.cpp:79
std
Definition: Application.h:66
armarx::navigation::components::laser_scanner_feature_extraction::FeatureMerger::FeatureMerger
FeatureMerger(std::vector< Features > &&features, const ChainApproximation::Params &chainApproximationParams)
Definition: FeatureMerger.cpp:21
Logging.h
armarx::navigation::components::laser_scanner_feature_extraction
Definition: ArVizDrawer.cpp:28
armarx::navigation::components::laser_scanner_feature_extraction::UnionFind
A simple union find data structure.
Definition: UnionFind.h:40