Easy3D 2.5.3
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
29 template <int DIM, typename FT = double>
31 public:
34
36 void begin();
39 template<typename FT2>
40 void add(const Vec<DIM, FT2>& p, FT2 weight = FT2(1));
42 void end();
43
45 template <typename InputIterator>
46 void add(InputIterator first, InputIterator last);
47
53 template<typename FT2>
54 Vec<DIM, FT2> center() const;
55
62 template<typename FT2>
63 Vec<DIM, FT2> axis(int i) const;
64
67 FT eigen_value(int i) const ;
68
69 private:
70 FT center_[DIM];
71 FT axis_[DIM][DIM];
72 FT eigen_value_[DIM];
73
74 FT** M_;
75 int nb_points_;
76 FT sum_weights_;
77 } ;
78
79} // namespace easy3d
80
81
82#include <cassert>
83#include <easy3d/core/eigen_solver.h>
84
85
86namespace easy3d {
87
88
89 template <int DIM, typename FT>
90 PrincipalAxes<DIM, FT>::PrincipalAxes() {
91 M_ = new FT *[DIM];
92 for (int i = 0; i < DIM; ++i)
93 M_[i] = new FT [DIM];
94 }
95
96
97 template <int DIM, typename FT>
98 PrincipalAxes<DIM, FT>::~PrincipalAxes() {
99 for (int i = 0; i < DIM; ++i)
100 delete[] M_[i];
101 delete[] M_;
102 }
103
104
105 template <int DIM, typename FT>
106 template <typename FT2>
108 return Vec<DIM, FT2>(center_) ;
109 }
110
111
112 template <int DIM, typename FT>
113 template <typename FT2>
115 assert(i >= 0 && i < DIM) ;
116 return Vec<DIM, FT2>(axis_[i]) ;
117 }
118
119
120 template <int DIM, typename FT>
121 inline FT PrincipalAxes<DIM, FT>::eigen_value(int i) const {
122 assert(i >= 0 && i < DIM) ;
123 return eigen_value_[i] ;
124 }
125
126
127 template <int DIM, typename FT>
129 nb_points_ = 0 ;
130 sum_weights_ = 0 ;
131 for (int i = 0; i < DIM; ++i) {
132 center_[i] = 0;
133 for (int j = 0; j < DIM; ++j)
134 M_[i][j] = 0;
135 }
136 }
137
138
139 template <int DIM, typename FT>
141 for (int i = 0; i < DIM; ++i)
142 center_[i] /= sum_weights_;
143
144 // If the system is under-determined, return the trivial basis.
145 if (nb_points_ < DIM + 1) {
146 for (int i = 0; i < DIM; ++i) {
147 eigen_value_[i] = FT(1);
148 for (int j = 0; j < DIM; ++j)
149 axis_[i][j] = (i == j ? FT(1) : FT(0));
150 }
151 }
152 else {
153 for (int i = 0; i < DIM; ++i) {
154 for (int j = i; j < DIM; ++j) {
155 M_[i][j] = M_[i][j]/sum_weights_ - center_[i]*center_[j];
156 if (i != j)
157 M_[j][i] = M_[i][j];
158 }
159
160 if( M_[i][i] <= FT(0))
161 M_[i][i] = std::numeric_limits<FT>::min();
162 }
163
164 EigenSolver<FT> solver(DIM);
166
167 for (int i=0; i<DIM; ++i) {
168 eigen_value_[i] = solver.eigen_value(i);
169 for (int j=0; j<DIM; ++j)
170 axis_[i][j] = solver.eigen_vector(j, i); // eigenvectors are stored in columns
171 }
172
173 // Normalize the eigen vectors
174 for(int i=0; i<DIM; i++) {
175 FT sqr_len(0);
176 for(int j=0; j<DIM; j++)
177 sqr_len += (axis_[i][j] * axis_[i][j]);
178 FT s = std::sqrt(sqr_len);
179 s = (s > std::numeric_limits<FT>::min()) ? FT(1) / s : FT(0);
180 for (int j = 0; j < DIM; ++j)
181 axis_[i][j] *= s;
182 }
183 }
184 }
185
186
187 // The covariance matrix:
188 // If A and B have components a_i and b_j respectively, then
189 // the covariance matrix C has a_i*b_j as its ij-th entry.
190 template <int DIM, typename FT>
191 template <typename FT2>
192 inline void PrincipalAxes<DIM, FT>::add(const Vec<DIM, FT2>& p, FT2 weight) {
193 for (int i = 0; i < DIM; ++i) {
194 center_[i] += p[i] * weight ;
195 for (int j = i; j < DIM; ++j)
196 M_[i][j] += weight * p[i] * p[j];
197 }
198 nb_points_++ ;
199 sum_weights_ += weight ;
200 }
201
202
203 // add a set of point (it internally calls add())
204 template <int DIM, typename FT>
205 template <typename InputIterator >
206 inline void PrincipalAxes<DIM, FT>::add(InputIterator first, InputIterator last) {
207 assert(first != last);
208 for (InputIterator it = first; it != last; ++it) {
209 add(*it);
210 }
211 }
212
213} // namespace easy3d
214
215#endif // EASY3D_CORE_PRINCIPAL_AXES_H
216
An easy-to-use eigen solver.
Definition: eigen_solver.h:25
FT eigen_value(int i) const
Returns the i_th eigenvalue.
Definition: eigen_solver.h:41
void solve(FT **mat, SortingMethod sm=NO_SORTING)
Computes the eigenvalues and eigenvectors of the input matrix mat.
Definition: eigen_solver.h:566
FT eigen_vector(int comp, int i) const
Returns the comp_th component of the i_th eigenvector.
Definition: eigen_solver.h:43
Computes the center and inertia axes of a set of 2D or 3D points.
Definition: principal_axes.h:30
FT eigen_value(int i) const
The i_th eigenvalue.
Definition: principal_axes.h:121
Vec< DIM, FT2 > center() const
The weighted average of the points. This function supports different types of vectors,...
Definition: principal_axes.h:107
void add(const Vec< DIM, FT2 > &p, FT2 weight=FT2(1))
Adds a point p with a weight. This function supports different types of vectors, e....
Definition: principal_axes.h:192
void end()
Ends adding points.
Definition: principal_axes.h:140
void begin()
Begins adding points.
Definition: principal_axes.h:128
Vec< DIM, FT2 > axis(int i) const
The i_th axis This function supports different types of vectors, e.g. vec3, dvec3,...
Definition: principal_axes.h:114
Base class for vector types. It provides generic functionality for N dimensional vectors.
Definition: vec.h:34
Definition: collider.cpp:182