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