Easy3D 2.6.1
Loading...
Searching...
No Matches
principal_axes.h
1/********************************************************************
2 * Copyright (C) 2015-2021 by Liangliang Nan <liangliang.nan@gmail.com>
3 * Copyright (C) 2000-2005 INRIA - Project ALICE
4 *
5 * The code in this file is partly from OGF/Graphite (2.0 alpha-4) with
6 * modifications and enhancement:
7 * https://gforge.inria.fr/forum/forum.php?forum_id=11459
8 * The original code was distributed under the GNU GPL license.
9 ********************************************************************/
10
11#ifndef EASY3D_CORE_PRINCIPAL_AXES_H
12#define EASY3D_CORE_PRINCIPAL_AXES_H
13
14#include <easy3d/core/types.h>
15
16
17namespace easy3d {
18
28 template <int DIM, typename FT = double>
30 public:
38 ~PrincipalAxes() = default;
39
43 void begin();
44
52 template<typename FT2>
53 void add(const Vec<DIM, FT2>& p, FT2 weight = FT2(1));
54
58 void end();
59
66 template <typename InputIterator>
67 void add(InputIterator first, InputIterator last);
68
78 template<typename FT2>
79 Vec<DIM, FT2> center() const;
80
92 template<typename FT2>
93 Vec<DIM, FT2> axis(int i) const;
94
101 FT eigen_value(int i) const;
102
103 private:
104 FT center_[DIM];
105 FT axis_[DIM][DIM];
106 FT eigen_value_[DIM];
107
109 int nb_points_;
110 FT sum_weights_;
111 } ;
112
113} // namespace easy3d
114
115
116#include <cassert>
117#include <easy3d/core/eigen_solver.h>
118
119
120namespace easy3d {
121
122
123 template <int DIM, typename FT>
124 PrincipalAxes<DIM, FT>::PrincipalAxes() : nb_points_(0), sum_weights_(0) {
125 for (int i = 0; i < DIM; ++i) {
126 center_[i] = 0;
127 eigen_value_[i] = 0;
128 for (int j = 0; j < DIM; ++j) {
129 axis_[i][j] = 0;
130 M_(i, j) = 0;
131 }
132 }
133 }
134
135
136 template <int DIM, typename FT>
137 template <typename FT2>
139 return Vec<DIM, FT2>(center_) ;
140 }
141
142
143 template <int DIM, typename FT>
144 template <typename FT2>
146 assert(i >= 0 && i < DIM) ;
147 return Vec<DIM, FT2>(axis_[i]) ;
148 }
149
150
151 template <int DIM, typename FT>
153 assert(i >= 0 && i < DIM) ;
154 return eigen_value_[i] ;
155 }
156
157
158 template <int DIM, typename FT>
160 nb_points_ = 0 ;
161 sum_weights_ = 0 ;
162 for (int i = 0; i < DIM; ++i) {
163 center_[i] = 0;
164 for (int j = 0; j < DIM; ++j)
165 M_(i, j) = 0;
166 }
167 }
168
169
170 template <int DIM, typename FT>
172 for (int i = 0; i < DIM; ++i)
173 center_[i] /= sum_weights_;
174
175 // If the system is under-determined, return the trivial basis.
176 if (nb_points_ < DIM + 1) {
177 for (int i = 0; i < DIM; ++i) {
178 eigen_value_[i] = FT(1);
179 for (int j = 0; j < DIM; ++j)
180 axis_[i][j] = (i == j ? FT(1) : FT(0));
181 }
182 }
183 else {
184 for (int i = 0; i < DIM; ++i) {
185 for (int j = i; j < DIM; ++j) {
186 M_(i, j) = M_(i, j)/sum_weights_ - center_[i]*center_[j];
187 if (i != j)
188 M_(j, i) = M_(i, j);
189 }
190
191 if( M_(i, i) <= FT(0))
192 M_(i, i) = std::numeric_limits<FT>::min();
193 }
194
196 solver.solve(M_, EigenSolver<Mat<DIM, DIM, double> >::DECREASING);
197
198 for (int i=0; i<DIM; ++i) {
199 eigen_value_[i] = solver.eigen_value(i);
200 for (int j=0; j<DIM; ++j)
201 axis_[i][j] = solver.eigen_vector(j, i); // eigenvectors are stored in columns
202 }
203
204 // Normalize the eigen vectors
205 for(int i=0; i<DIM; i++) {
206 FT sqr_len(0);
207 for(int j=0; j<DIM; j++)
208 sqr_len += (axis_[i][j] * axis_[i][j]);
209 FT s = std::sqrt(sqr_len);
210 s = (s > std::numeric_limits<FT>::min()) ? FT(1) / s : FT(0);
211 for (int j = 0; j < DIM; ++j)
212 axis_[i][j] *= s;
213 }
214 }
215 }
216
217
218 // The covariance matrix:
219 // If A and B have components a_i and b_j respectively, then
220 // the covariance matrix C has a_i*b_j as its ij-th entry.
221 template <int DIM, typename FT>
222 template <typename FT2>
223 void PrincipalAxes<DIM, FT>::add(const Vec<DIM, FT2>& p, FT2 weight) {
224 for (int i = 0; i < DIM; ++i) {
225 center_[i] += p[i] * weight ;
226 for (int j = i; j < DIM; ++j)
227 M_(i, j) += weight * p[i] * p[j];
228 }
229 nb_points_++ ;
230 sum_weights_ += weight ;
231 }
232
233
234 // add a set of point (it internally calls add())
235 template <int DIM, typename FT>
236 template <typename InputIterator >
237 void PrincipalAxes<DIM, FT>::add(InputIterator first, InputIterator last) {
238 assert(first != last);
239 for (InputIterator it = first; it != last; ++it) {
240 add(*it);
241 }
242 }
243
244} // namespace easy3d
245
246#endif // EASY3D_CORE_PRINCIPAL_AXES_H
247
An easy-to-use eigen solver.
Definition eigen_solver.h:30
T eigen_value(int i) const
Retrieves the eigenvalue at the specified index.
Definition eigen_solver.h:65
void solve(const MAT &mat, SortingMethod sm=NO_SORTING)
Computes the eigenvalues and eigenvectors of the specified input matrix.
Definition eigen_solver.h:620
T eigen_vector(int comp, int i) const
Retrieves the specified component of the eigenvector at the given index.
Definition eigen_solver.h:72
Base class for matrix types.
Definition mat.h:64
~PrincipalAxes()=default
Destructor.
FT eigen_value(int i) const
The i_th eigenvalue.
Definition principal_axes.h:152
Vec< DIM, FT2 > center() const
The weighted average of the points.
Definition principal_axes.h:138
void add(const Vec< DIM, FT2 > &p, FT2 weight=FT2(1))
Adds a point p with a weight.
Definition principal_axes.h:223
void end()
Ends adding points.
Definition principal_axes.h:171
void begin()
Begins adding points.
Definition principal_axes.h:159
Vec< DIM, FT2 > axis(int i) const
The i_th axis.
Definition principal_axes.h:145
PrincipalAxes()
Default constructor.
Definition principal_axes.h:124
Base class for vector types. It provides generic functionality for N dimensional vectors.
Definition vec.h:30
Definition collider.cpp:182