EnclosingEllipsoid.cpp
Go to the documentation of this file.
1 #include "EnclosingEllipsoid.h"
2 
3 #include <algorithm>
4 #include <cmath>
5 #include <cstddef>
6 #include <iterator>
7 #include <vector>
8 
9 #include <Eigen/Core>
10 #include <Eigen/Geometry>
11 
12 #include <SimoxUtility/math/periodic/periodic_clamp.h>
13 #include <VirtualRobot/math/Helpers.h>
14 
16 
18 {
19 
20  // Eigen::Affine2f Ellipsoid::pose() const noexcept
21  // {
22  // Eigen::Affine2f pose;
23  // pose.translation() = center;
24  // pose.linear() = Eigen::Rotation2Df(angle).toRotationMatrix();
25 
26  // return pose;
27  // }
28 
29  // TODO(fabian.reister): use Eigen built-in stuff.
30  size_t
31  argmin(const Eigen::VectorXf& v)
32  {
33  const std::vector<float> vec(v.data(), v.data() + v.rows() * v.cols());
34  return std::distance(std::begin(vec), std::max_element(vec.begin(), vec.end()));
35  }
36 
37  // https://github.com/minillinim/ellipsoid/blob/master/ellipsoid.py
38 
40  {
41  ARMARX_CHECK(compute(points));
42  }
43 
44  bool
45  EnclosingEllipsoid::compute(const Points& points)
46  {
47  const float tolerance = 0.01;
48 
49  const int N = static_cast<int>(points.size());
50  const int d = 2;
51 
52  Eigen::MatrixXf P(N, d);
53 
54  for (int i = 0; i < N; i++)
55  {
56  P.row(i) = points.at(i);
57  }
58 
59  Eigen::MatrixXf Q(d + 1, N);
60  Q.topRows(d) = P.transpose();
61  Q.bottomRows(1).setOnes(); // last row
62 
63  Eigen::MatrixXf Qt = Q.transpose();
64 
65  float err = 1.F + tolerance;
66  Eigen::VectorXf u = (1.F / N) * Eigen::VectorXf::Ones(N);
67 
68  // Khachiyan Algorithm
69  while (err > tolerance)
70  {
71  const Eigen::MatrixXf V = Q * (u.asDiagonal() * Qt);
72  const Eigen::VectorXf M = (Qt * (V.inverse() * Q)).diagonal();
73 
74  const int j = static_cast<int>(argmin(M));
75  const float maximum = M(j);
76 
77  const float stepSize = (maximum - d - 1.0) / ((d + 1.0) * (maximum - 1.0));
78 
79  Eigen::VectorXf uNew = (1.0 - stepSize) * u;
80  uNew(j) += stepSize;
81 
82  err = (uNew - u).norm();
83  u = uNew;
84  }
85 
86  const Eigen::VectorXf center = P.transpose() * u;
87 
88  Eigen::MatrixXf K(d, d);
89  for (int i = 0; i < d; i++)
90  {
91  for (int j = 0; j < d; j++)
92  {
93  K(i, j) = center(i) * center(j);
94  }
95  }
96 
97  const Eigen::MatrixXf H = (P.transpose() * (u.asDiagonal() * P)) - K;
98  const Eigen::MatrixXf A = H.inverse() / d;
99 
100  const Eigen::JacobiSVD svd(A, Eigen::ComputeThinV);
101 
102  // angle
103  const Eigen::VectorXf v0 = svd.matrixV().col(0);
104  const float angle = math::Helpers::Angle(v0);
105 
106  // radii
107  const Eigen::Vector2f radii = svd.singularValues().cwiseSqrt().cwiseInverse();
108 
109  // As the singular values are sorted descending, the radii are sorted ascending.
110  // To fix this, the vector is reversed.
111  this->radii = radii.reverse();
112 
113  // Thus, the angle does no longer match the radii. It has to be altered by 90°.
114  const float angle1 = simox::math::periodic_clamp(angle + M_PI_2, -M_PI, M_PI);
115 
116  this->pose.setIdentity();
117  this->pose.translation().head<2>() = center;
118  this->pose.linear() =
119  Eigen::AngleAxisf(angle1, Eigen::Vector3f::UnitZ()).toRotationMatrix();
120 
121  return true;
122  }
123 
124 } // namespace armarx::navigation::components::laser_scanner_feature_extraction
visionx::Points
std::vector< Point > Points
Definition: ObjectShapeClassification.h:71
armarx::navigation::memory::Ellipsoid::pose
Eigen::Isometry3f pose
Definition: types.h:35
armarx::navigation::memory::Ellipsoid::radii
Eigen::Vector2f radii
Definition: types.h:37
ARMARX_CHECK
#define ARMARX_CHECK(expression)
Shortcut for ARMARX_CHECK_EXPRESSION.
Definition: ExpressionException.h:82
EnclosingEllipsoid.h
M_PI
#define M_PI
Definition: MathTools.h:17
armarx::navigation::components::laser_scanner_feature_extraction::EnclosingEllipsoid::Points
std::vector< Point > Points
Definition: EnclosingEllipsoid.h:56
ExpressionException.h
A
class A(deque< T, A >)) ARMARX_OVERLOAD_STD_HASH_FOR_ITERABLE((class T
Enables hashing of std::list.
armarx::ctrlutil::v
double v(double t, double v0, double a0, double j)
Definition: CtrlUtil.h:39
angle
double angle(const Point &a, const Point &b, const Point &c)
Definition: point.hpp:109
distance
double distance(const Point &a, const Point &b)
Definition: point.hpp:95
armarx::navigation::components::laser_scanner_feature_extraction::EnclosingEllipsoid::EnclosingEllipsoid
EnclosingEllipsoid(const Points &points)
Definition: EnclosingEllipsoid.cpp:39
armarx::navigation::components::laser_scanner_feature_extraction::argmin
size_t argmin(const Eigen::VectorXf &v)
Definition: EnclosingEllipsoid.cpp:31
armarx::navigation::components::laser_scanner_feature_extraction
Definition: ArVizDrawer.cpp:28
norm
double norm(const Point &a)
Definition: point.hpp:102