Ponca  aa50bfdf187919869239c5b44b748842569114c1
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
10template < class DataPoint, class _WFunctor, typename T>
11void
13{
14 Base::init(_evalPos);
15 m_matA.setZero();
16 m_matQ.setZero();
17 m_sumDotPP = Scalar(0.0);
18}
19
20template<class DataPoint, class _WFunctor, typename T>
21bool
23 const VectorType &localQ,
24 const DataPoint &attributes) {
25 if( Base::addLocalNeighbor(w, localQ, attributes) )
26 {
27 VectorB basis;
28 basis << attributes.normal(), attributes.normal().dot(localQ);
29
30 m_matA += w * basis * basis.transpose();
31 m_sumDotPP += w * localQ.squaredNorm();
32
33 return true;
34 }
35
36 return false;
37}
38
39template < class DataPoint, class _WFunctor, typename T>
42{
43 PONCA_MULTIARCH_STD_MATH(sqrt);
44 constexpr int Dim = DataPoint::Dim;
45
46 // Compute status
47 if(Base::finalize() != STABLE)
48 return Base::m_eCurrentState;
49 if(Base::getNumNeighbors() < DataPoint::Dim)
50 return Base::m_eCurrentState = UNDEFINED;
51 if (Base::algebraicSphere().isValid())
52 Base::m_eCurrentState = CONFLICT_ERROR_FOUND;
53 else
54 Base::m_eCurrentState = Base::getNumNeighbors() < 2*DataPoint::Dim ? UNSTABLE : STABLE;
55
56 // 1. finalize sphere fitting
57 Scalar invSumW = Scalar(1.) / Base::getWeightSum();
58
59 m_matQ.template topLeftCorner<Dim,Dim>().setIdentity();
60 m_matQ.col(Dim).template head<Dim>() = Base::m_sumP * invSumW;
61 m_matQ.row(Dim).template head<Dim>() = Base::m_sumP * invSumW;
62 m_matQ(Dim,Dim) = m_sumDotPP * invSumW;
63
64 MatrixBB M = m_matQ.inverse() * m_matA;
65 m_solver.compute(M);
66 VectorB eivals = m_solver.eigenvalues().real();
67 int maxId = 0;
68 eivals.maxCoeff(&maxId);
69
70 VectorB eivec = m_solver.eigenvectors().col(maxId).real();
71
72 // integrate
73 Base::m_ul = eivec.template head<Dim>();
74 Base::m_uq = Scalar(0.5) * eivec(Dim);
75 Base::m_uc = -invSumW * (Base::m_ul.dot(Base::m_sumP) + m_sumDotPP * Base::m_uq);
76
77 Base::m_isNormalized = false;
78
79 return Base::m_eCurrentState;
80}
81
82
83
84template < class DataPoint, class _WFunctor, int DiffType, typename T>
85void
87{
88 Base::init(_evalPos);
89 for(int dim = 0; dim < Base::NbDerivatives; ++dim)
90 m_dmatA[dim] = MatrixBB::Zero();
91 m_dSumDotPP = ScalarArray::Zero();
92 m_dUc = ScalarArray::Zero();
93 m_dUl = VectorArray::Zero();
94 m_dUq = ScalarArray::Zero();
95}
96
97template < class DataPoint, class _WFunctor, int DiffType, typename T>
98bool
100 Scalar w,
101 const VectorType &localQ,
102 const DataPoint &attributes,
103 ScalarArray& dw)
104{
105 if( Base::addLocalNeighbor(w, localQ, attributes, dw) )
106 {
107 VectorB basis;
108 basis << attributes.normal(), attributes.normal().dot(localQ);
109 const MatrixBB prod = basis * basis.transpose();
110
111 m_dSumDotPP += dw * localQ.squaredNorm();
112
113 for(int dim = 0; dim < Base::NbDerivatives; ++dim)
114 {
115 m_dmatA[dim] += dw[dim] * prod;
116 }
117
118 return true;
119 }
120 return false;
121}
122
123template < class DataPoint, class _WFunctor, int DiffType, typename T>
126{
127 constexpr int Dim = DataPoint::Dim;
128 constexpr Scalar epsilon = Eigen::NumTraits<Scalar>::dummy_precision();
129
130 Base::finalize();
131 if(this->isReady())
132 {
133 int i = 0;
134 Base::m_solver.eigenvalues().real().maxCoeff(&i);
135 const Scalar eigenval_i = Base::m_solver.eigenvalues().real()[i];
136 const VectorB eigenvec_i = Base::m_solver.eigenvectors().real().col(i);
137
138 const Scalar invSumW = Scalar(1) / Base::getWeightSum();
139
140 // the derivative of (A vi = li Q vi), where A and Q are symmetric real, is
141 //
142 // dA vi + A dvi = dli Q vi + li dQ vi + li Q dvi
143 //
144 // left-multiply by vj (i!=j, associated to eigenvalue lj)
145 //
146 // vj . dA vi + vj . A dvi = dli vj . Q vi + li vj . dQ vi + li vj . Q dvi
147 // ^^^^^^ ^^^^^^^^^
148 // = lj vj . Q = 0
149 //
150 // which simplified to
151 //
152 // (Q vj) . dvi = 1/(li - lj) vj . dQ vi
153 //
154 // therefore
155 //
156 // dvi = sum_j (1/(li - lj) vj . dQ vi) Q vj
157 // = Q sum_j (1/(li - lj) vj . ((dA - li dQ) vi)) vj
158 //
159 for(int dim = 0; dim < Base::NbDerivatives; ++dim)
160 {
161 MatrixBB dQ;
162 dQ.template topLeftCorner<Dim,Dim>().setZero();
163 dQ.col(Dim).template head<Dim>() = Base::m_dSumP.col(dim);
164 dQ.row(Dim).template head<Dim>() = Base::m_dSumP.col(dim);
165 dQ(Dim,Dim) = m_dSumDotPP[dim];
166 dQ -= Base::m_dSumW[dim] * Base::m_matQ;
167 dQ *= invSumW;
168
169 const VectorB vec = (m_dmatA[dim] - eigenval_i * dQ) * eigenvec_i;
170
171 VectorB deigvec = VectorB::Zero();
172 for(int j = 0; j < Dim+1; ++j)
173 {
174 if(j != i)
175 {
176 const Scalar eigenval_j = Base::m_solver.eigenvalues().real()[j];
177 const Scalar eigengap = eigenval_i - eigenval_j; // positive since eigenval_i is the maximal eigenvalue
178
179 if(eigengap > epsilon)
180 {
181 const VectorB eigenvec_j = Base::m_solver.eigenvectors().real().col(j);
182 deigvec += Scalar(1)/eigengap * eigenvec_j.dot(vec) * eigenvec_j;
183 }
184 }
185 }
186
187 deigvec = Base::m_matQ * deigvec;
188
189 m_dUq[dim] = Scalar(.5) * deigvec[dim];
190 m_dUl.col(dim) = deigvec.template head<Dim>();
191 }
192
193 // same as in OrientedSphereDerImpl::finalize()
194 m_dUc = -invSumW*( Base::m_sumP.transpose() * m_dUl
195 + Base::m_sumDotPP * m_dUq
196 + Base::m_ul.transpose() * Base::m_dSumP
197 + Base::m_uq * m_dSumDotPP
198 + Base::m_dSumW * Base::m_uc);
199
200 return FIT_RESULT::STABLE;
201 }
202 return Base::m_eCurrentState;
203}
204
205template < class DataPoint, class _WFunctor, int DiffType, typename T>
208{
209 // same as OrientedSphereDerImpl::dPotential()
210 ScalarArray dfield = m_dUc;
211 if(Base::isSpaceDer())
212 dfield.template tail<DataPoint::Dim>() += Base::m_ul;
213 return dfield;
214}
215
216template < class DataPoint, class _WFunctor, int DiffType, typename T>
218UnorientedSphereDerImpl<DataPoint, _WFunctor, DiffType, T>::dNormal() const
219{
220 // same as OrientedSphereDerImpl::dNormal()
221 VectorArray dgrad = m_dUl;
222 if(Base::isSpaceDer())
223 dgrad.template rightCols<DataPoint::Dim>().diagonal().array() += Scalar(2)*Base::m_uq;
224 Scalar norm = Base::m_ul.norm();
225 Scalar norm3 = norm*norm*norm;
226 return dgrad / norm - Base::m_ul * (Base::m_ul.transpose() * dgrad) / norm3;
227}
228
229} //namespace Ponca
typename Base::VectorType VectorType
Alias to vector type.
bool addLocalNeighbor(Scalar w, const VectorType &localQ, const DataPoint &attributes, ScalarArray &dw)
Add a neighbor to perform the fit.
typename DataPoint::Scalar Scalar
Alias to scalar type.
typename Base::ScalarArray ScalarArray
Alias to scalar derivatives array.
void init(const VectorType &_evalPos)
Set the evaluation position and reset the internal states.
typename Base::VectorArray VectorArray
Alias to vector derivatives array.
FIT_RESULT finalize()
Finalize the procedure.
typename Base::VectorType VectorType
Alias to vector type.
bool addLocalNeighbor(Scalar w, const VectorType &localQ, const DataPoint &attributes)
Add a neighbor to perform the fit.
FIT_RESULT finalize()
Finalize the procedure.
typename DataPoint::Scalar Scalar
Alias to scalar type.
void init(const VectorType &_evalPos)
Set the evaluation position and reset the internal states.
This Source Code Form is subject to the terms of the Mozilla Public License, v.
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