Ponca  4d2a58fa5c6375adef5c4b208f4d47e016cecd6d
Point Cloud Analysis library
Loading...
Searching...
No Matches
unorientedSphereFit.hpp
1/*
2 This Source Code Form is subject to the terms of the Mozilla Public
3 License, v. 2.0. If a copy of the MPL was not distributed with this
4 file, You can obtain one at http://mozilla.org/MPL/2.0/.
5*/
6
7namespace Ponca
8{
9
10 template <class DataPoint, class _NFilter, typename T>
11 requires UNORIENTED_SPHERE_FIT_REQUIREMENTS
13 {
14 Base::init();
15 m_matA.setZero();
16 m_matQ.setZero();
17 m_sumDotPP = Scalar(0.0);
18 }
19
20 template <class DataPoint, class _NFilter, typename T>
21 requires UNORIENTED_SPHERE_FIT_REQUIREMENTS
23 const DataPoint& attributes)
24 {
25 Base::addLocalNeighbor(w, localQ, attributes);
26 VectorB basis;
27 basis << attributes.normal(), attributes.normal().dot(localQ);
28
29 m_matA += w * basis * basis.transpose();
30 m_sumDotPP += w * localQ.squaredNorm();
31 }
32
33 template <class DataPoint, class _NFilter, typename T>
34 requires UNORIENTED_SPHERE_FIT_REQUIREMENTS
36 {
37 PONCA_MULTIARCH_STD_MATH(sqrt);
38 constexpr int Dim = DataPoint::Dim;
39
40 // Compute status
41 if (Base::finalize() != STABLE)
42 return Base::m_eCurrentState;
43 if (Base::getNumNeighbors() < DataPoint::Dim)
44 return Base::m_eCurrentState = UNDEFINED;
45 if (Base::algebraicSphere().isValid())
46 Base::m_eCurrentState = CONFLICT_ERROR_FOUND;
47 else
48 Base::m_eCurrentState = Base::getNumNeighbors() < 2 * DataPoint::Dim ? UNSTABLE : STABLE;
49
50 // 1. finalize sphere fitting
51 Scalar invSumW = Scalar(1.) / Base::getWeightSum();
52
53 m_matQ.template topLeftCorner<Dim, Dim>().setIdentity();
54 m_matQ.col(Dim).template head<Dim>() = Base::m_sumP * invSumW;
55 m_matQ.row(Dim).template head<Dim>() = Base::m_sumP * invSumW;
56 m_matQ(Dim, Dim) = m_sumDotPP * invSumW;
57
58 MatrixBB M = m_matQ.inverse() * m_matA;
59 m_solver.compute(M);
60 VectorB eivals = m_solver.eigenvalues().real();
61 int maxId = 0;
62 eivals.maxCoeff(&maxId);
63
64 VectorB eivec = m_solver.eigenvectors().col(maxId).real();
65
66 // integrate
67 Base::m_ul = eivec.template head<Dim>();
68 Base::m_uq = Scalar(0.5) * eivec(Dim);
69 Base::m_uc = -invSumW * (Base::m_ul.dot(Base::m_sumP) + m_sumDotPP * Base::m_uq);
70
71 Base::m_isNormalized = false;
72
73 return Base::m_eCurrentState;
74 }
75
76 template <class DataPoint, class _NFilter, int DiffType, typename T>
77 requires UNORIENTED_SPHERE_DER_REQUIREMENTS
79 {
80 Base::init();
81 for (int dim = 0; dim < Base::NbDerivatives; ++dim)
82 m_dmatA[dim] = MatrixBB::Zero();
83 m_dSumDotPP = ScalarArray::Zero();
84 m_dUc = ScalarArray::Zero();
85 m_dUl = VectorArray::Zero();
86 m_dUq = ScalarArray::Zero();
87 }
88
89 template <class DataPoint, class _NFilter, int DiffType, typename T>
90 requires UNORIENTED_SPHERE_DER_REQUIREMENTS
92 const DataPoint& attributes,
94 {
95 Base::addLocalNeighbor(w, localQ, attributes, dw);
96 VectorB basis;
97 basis << attributes.normal(), attributes.normal().dot(localQ);
98 const MatrixBB prod = basis * basis.transpose();
99
100 m_dSumDotPP += dw * localQ.squaredNorm();
101
102 for (int dim = 0; dim < Base::NbDerivatives; ++dim)
103 {
104 m_dmatA[dim] += dw[dim] * prod;
105 }
106 }
107
108 template <class DataPoint, class _NFilter, int DiffType, typename T>
109 requires UNORIENTED_SPHERE_DER_REQUIREMENTS
111 {
112 constexpr int Dim = DataPoint::Dim;
113 constexpr Scalar epsilon = Eigen::NumTraits<Scalar>::dummy_precision();
114
115 Base::finalize();
116 if (this->isReady())
117 {
118 int i = 0;
119 Base::m_solver.eigenvalues().real().maxCoeff(&i);
120 const Scalar eigenval_i = Base::m_solver.eigenvalues().real()[i];
121 const VectorB eigenvec_i = Base::m_solver.eigenvectors().real().col(i);
122
123 const Scalar invSumW = Scalar(1) / Base::getWeightSum();
124
125 // the derivative of (A vi = li Q vi), where A and Q are symmetric real, is
126 //
127 // dA vi + A dvi = dli Q vi + li dQ vi + li Q dvi
128 //
129 // left-multiply by vj (i!=j, associated to eigenvalue lj)
130 //
131 // vj . dA vi + vj . A dvi = dli vj . Q vi + li vj . dQ vi + li vj . Q dvi
132 // ^^^^^^ ^^^^^^^^^
133 // = lj vj . Q = 0
134 //
135 // which simplified to
136 //
137 // (Q vj) . dvi = 1/(li - lj) vj . dQ vi
138 //
139 // therefore
140 //
141 // dvi = sum_j (1/(li - lj) vj . dQ vi) Q vj
142 // = Q sum_j (1/(li - lj) vj . ((dA - li dQ) vi)) vj
143 //
144 for (int dim = 0; dim < Base::NbDerivatives; ++dim)
145 {
146 MatrixBB dQ;
147 dQ.template topLeftCorner<Dim, Dim>().setZero();
148 dQ.col(Dim).template head<Dim>() = Base::m_dSumP.col(dim);
149 dQ.row(Dim).template head<Dim>() = Base::m_dSumP.col(dim);
150 dQ(Dim, Dim) = m_dSumDotPP[dim];
151 dQ -= Base::m_dSumW[dim] * Base::m_matQ;
152 dQ *= invSumW;
153
154 const VectorB vec = (m_dmatA[dim] - eigenval_i * dQ) * eigenvec_i;
155
156 VectorB deigvec = VectorB::Zero();
157 for (int j = 0; j < Dim + 1; ++j)
158 {
159 if (j != i)
160 {
161 const Scalar eigenval_j = Base::m_solver.eigenvalues().real()[j];
162 const Scalar eigengap =
163 eigenval_i - eigenval_j; // positive since eigenval_i is the maximal eigenvalue
164
165 if (eigengap > epsilon)
166 {
167 const VectorB eigenvec_j = Base::m_solver.eigenvectors().real().col(j);
169 }
170 }
171 }
172
173 deigvec = Base::m_matQ * deigvec;
174
175 m_dUq[dim] = Scalar(.5) * deigvec[dim];
176 m_dUl.col(dim) = deigvec.template head<Dim>();
177 }
178
179 // same as in OrientedSphereDerImpl::finalize()
180 m_dUc = -invSumW *
181 (Base::m_sumP.transpose() * m_dUl + Base::m_sumDotPP * m_dUq +
182 Base::m_ul.transpose() * Base::m_dSumP + Base::m_uq * m_dSumDotPP + Base::m_dSumW * Base::m_uc);
183
184 return FIT_RESULT::STABLE;
185 }
186 return Base::m_eCurrentState;
187 }
188
189 template <class DataPoint, class _NFilter, int DiffType, typename T>
190 requires UNORIENTED_SPHERE_DER_REQUIREMENTS
192 DataPoint, _NFilter, DiffType, T>::dPotential() const
193 {
194 // same as OrientedSphereDerImpl::dPotential()
195 ScalarArray dfield = m_dUc;
196 if (Base::isSpaceDer())
197 dfield.template tail<DataPoint::Dim>() += Base::m_ul;
198 return dfield;
199 }
200
201 template <class DataPoint, class _NFilter, int DiffType, typename T>
202 requires UNORIENTED_SPHERE_DER_REQUIREMENTS
204 DataPoint, _NFilter, DiffType, T>::dNormal() const
205 {
206 // same as OrientedSphereDerImpl::dNormal()
207 VectorArray dgrad = m_dUl;
208 if (Base::isSpaceDer())
209 dgrad.template rightCols<DataPoint::Dim>().diagonal().array() += Scalar(2) * Base::m_uq;
210 Scalar norm = Base::m_ul.norm();
211 Scalar norm3 = norm * norm * norm;
212 return dgrad / norm - Base::m_ul * (Base::m_ul.transpose() * dgrad) / norm3;
213 }
214
215} // namespace Ponca
Aggregator class used to declare specialized structures using CRTP.
Definition basket.h:260
typename P::Scalar Scalar
Scalar type used for computation, as defined from template parameter P
Definition basket.h:268
void addLocalNeighbor(Scalar w, const VectorType &localQ, const DataPoint &attributes, ScalarArray &dw)
Add a neighbor to perform the fit.
typename Base::ScalarArray ScalarArray
Alias to scalar derivatives array.
typename Base::VectorType VectorType
Alias to vector type.
typename DataPoint::Scalar Scalar
Alias to scalar type.
void init()
Set the evaluation position and reset the internal states.
FIT_RESULT finalize()
Finalize the procedure.
typename Base::VectorArray VectorArray
Alias to vector derivatives array.
void addLocalNeighbor(Scalar w, const VectorType &localQ, const DataPoint &attributes)
Add a neighbor to perform the fit.
FIT_RESULT finalize()
Finalize the procedure.
void init()
Set the evaluation position and reset the internal states.
typename Base::VectorType VectorType
Alias to vector type.
typename DataPoint::Scalar Scalar
Alias to scalar type.
This Source Code Form is subject to the terms of the Mozilla Public License, v.
Definition concepts.h:11
DiffType
Flags defining which derivatives need to be computed.
Definition enums.h:34
FIT_RESULT
Enum corresponding to the state of a fitting method (and what the finalize function returns)
Definition enums.h:15
@ UNDEFINED
The fitting is undefined, you can't use it for valid results.
Definition enums.h:22
@ CONFLICT_ERROR_FOUND
Multiple classes of the fitting procedure initialize the primitive.
Definition enums.h:27
@ STABLE
The fitting is stable and ready to use.
Definition enums.h:17
@ UNSTABLE
The fitting is ready to use but it is considered as unstable (if the number of neighbors is low for e...
Definition enums.h:20
FIT_RESULT compute(const IteratorBegin &begin, const IteratorEnd &end)
Convenience function for STL-like iterators Add neighbors stored in a container using STL-like iterat...
Definition basket.h:155