Ponca  40f245e28b920cbb763a1c6282156c87c626f24c
Point Cloud Analysis library
Loading...
Searching...
No Matches
orientedSphereFit.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
7
8template < class DataPoint, class _WFunctor, typename T>
9void
11{
12 Base::init();
13
14 // Setup fitting internal values
15 m_sumDotPN = Scalar(0.0);
16 m_sumDotPP = Scalar(0.0);
17 m_nume = Scalar(0.0);
18 m_deno = Scalar(0.0);
19}
20
21template<class DataPoint, class _WFunctor, typename T>
22bool
24 const VectorType &localQ,
25 const DataPoint &attributes) {
26 if( Base::addLocalNeighbor(w, localQ, attributes) ) {
27 m_sumDotPN += w * attributes.normal().dot(localQ);
28 m_sumDotPP += w * localQ.squaredNorm();
29 return true;
30 }
31 return false;
32}
33
34
35template < class DataPoint, class _WFunctor, typename T>
38{
39 PONCA_MULTIARCH_STD_MATH(sqrt);
40 PONCA_MULTIARCH_STD_MATH(max);
41 PONCA_MULTIARCH_STD_MATH(abs);
42
43 // Compute status
44 if(Base::finalize() != STABLE)
45 return Base::m_eCurrentState;
46 if(Base::getNumNeighbors() < DataPoint::Dim)
47 return Base::m_eCurrentState = UNDEFINED;
48 if (Base::algebraicSphere().isValid())
49 Base::m_eCurrentState = CONFLICT_ERROR_FOUND;
50 else
51 Base::m_eCurrentState = Base::getNumNeighbors() < 2*DataPoint::Dim ? UNSTABLE : STABLE;
52
53 // 1. finalize sphere fitting
54 Scalar epsilon = Eigen::NumTraits<Scalar>::dummy_precision();
55
56 Scalar invSumW = Scalar(1.)/Base::getWeightSum();
57
58 m_nume = (m_sumDotPN - invSumW * Base::m_sumP.dot(Base::m_sumN));
59 Scalar den1 = invSumW * Base::m_sumP.dot(Base::m_sumP);
60 m_deno = m_sumDotPP - den1;
61
62 // Deal with degenerate cases
63 if(abs(m_deno) < epsilon * max(m_sumDotPP, den1))
64 {
65 if (Base::m_ul.isZero(0))
66 return Base::m_eCurrentState = UNDEFINED;
67 //plane
68 Scalar s = Scalar(1.) / Base::m_ul.norm();
69 Base::m_ul = s*Base::m_ul;
70 Base::m_uc = s*Base::m_uc;
71 Base::m_uq = Scalar(0.);
72 }
73 else
74 {
75 //Generic case
76 Base::m_uq = Scalar(.5) * m_nume / m_deno;
77 Base::m_ul = (Base::m_sumN - Base::m_sumP * (Scalar(2.) * Base::m_uq)) * invSumW;
78 Base::m_uc = -invSumW * (Base::m_ul.dot(Base::m_sumP) + m_sumDotPP * Base::m_uq);
79 }
80
81 Base::m_isNormalized = false;
82
83 return Base::m_eCurrentState;
84}
85
86template < class DataPoint, class _WFunctor, int DiffType, typename T>
87void
89{
90 Base::init();
91
92 m_dSumN.setZero();
93
94 m_dSumDotPN.setZero();
95 m_dSumDotPP.setZero();
96 m_dNume.setZero();
97 m_dDeno.setZero();
98
99 m_dUc.setZero();
100 m_dUq.setZero();
101 m_dUl.setZero();
102}
103
104
105template < class DataPoint, class _WFunctor, int DiffType, typename T>
106bool
108 const VectorType &localQ,
109 const DataPoint &attributes,
110 ScalarArray &dw) {
111 if( Base::addLocalNeighbor(w, localQ, attributes, dw) ) {
112
113 m_dSumN += attributes.normal() * dw;
114 m_dSumDotPN += dw * attributes.normal().dot(localQ);
115 m_dSumDotPP += dw * localQ.squaredNorm();
116
117 return true;
118 }
119 return false;
120}
121
122
123template < class DataPoint, class _WFunctor, int DiffType, typename T>
126{
127 PONCA_MULTIARCH_STD_MATH(sqrt);
128
129 Base::finalize();
130 // Test if base finalize end on a viable case (stable / unstable)
131 if (this->isReady())
132 {
133 Scalar invSumW = Scalar(1.)/Base::getWeightSum();
134
135 Scalar nume = Base::m_sumDotPN - invSumW*Base::m_sumP.dot(Base::m_sumN);
136 Scalar deno = Base::m_sumDotPP - invSumW*Base::m_sumP.dot(Base::m_sumP);
137
138 // FIXME, the following product "Base::m_sumN.transpose() * m_dSumP" is prone to numerical cancellation
139 // issues for spacial derivatives because, (d sum w_i P_i)/(d x) is supposed to be tangent to the surface whereas
140 // "sum w_i N_i" is normal to the surface...
141 m_dNume = m_dSumDotPN
142 - invSumW*invSumW * ( Base::getWeightSum() * ( Base::m_sumN.transpose() * Base::m_dSumP + Base::m_sumP.transpose() * m_dSumN )
143 - Base::m_dSumW*Base::m_sumP.dot(Base::m_sumN) );
144
145 m_dDeno = m_dSumDotPP
146 - invSumW*invSumW*( Scalar(2.) * Base::getWeightSum() * Base::m_sumP.transpose() * Base::m_dSumP
147 - Base::m_dSumW*Base::m_sumP.dot(Base::m_sumP) );
148
149 m_dUq = Scalar(.5) * (deno * m_dNume - m_dDeno * nume)/(deno*deno);
150
151 // FIXME: this line is prone to numerical cancellation issues because dSumN and u_l*dSumW are close to each other.
152 // If using two passes, one could directly compute sum( dw_i + (n_i - ul) ) to avoid this issue.
153 m_dUl = invSumW * ( m_dSumN - Base::m_ul*Base::m_dSumW - Scalar(2.)*(Base::m_dSumP * Base::m_uq + Base::m_sumP * m_dUq) );
154 m_dUc = -invSumW*( Base::m_sumP.transpose() * m_dUl
155 + Base::m_sumDotPP * m_dUq
156 + Base::m_ul.transpose() * Base::m_dSumP
157 + Base::m_uq * m_dSumDotPP
158 + Base::m_dSumW * Base::m_uc);
159 }
160
161 return Base::m_eCurrentState;
162}
163
164template < class DataPoint, class _WFunctor, int DiffType, typename T>
165typename OrientedSphereDerImpl <DataPoint, _WFunctor, DiffType, T>::VectorArray
167{
168 // Computes the derivatives of the normal of the sphere at the evaluation point.
169 // Therefore, we must take into account the variation of the evaluation point when differentiating wrt space
170 // i.e., normal(x) = grad / |grad|, with grad(x) = ul + 2 uq * x, and diff_x(grad) = dul + 2 uq I
171 VectorArray dgrad = m_dUl;
172 if(Base::isSpaceDer())
173 dgrad.template rightCols<DataPoint::Dim>().diagonal().array() += Scalar(2)*Base::m_uq;
174 Scalar norm = Base::m_ul.norm();
175 Scalar norm3 = norm*norm*norm;
176 return dgrad / norm - Base::m_ul * (Base::m_ul.transpose() * dgrad) / norm3;
177}
178
179template < class DataPoint, class _WFunctor, int DiffType, typename T>
180typename OrientedSphereDerImpl <DataPoint, _WFunctor, DiffType, T>::ScalarArray
182{
183 ScalarArray dfield = m_dUc;
184 if(Base::isSpaceDer())
185 dfield.template tail<DataPoint::Dim>() += Base::m_ul;
186 return dfield;
187}
188
189template < class DataPoint, class _WFunctor, int DiffType, typename T>
190bool
192{
193 if(Base::isNormalized())
194 return false; //need original parameters without Pratt Normalization
195
196 PONCA_MULTIARCH_STD_MATH(sqrt);
197 Scalar pn2 = Base::prattNorm2();
198 Scalar pn = sqrt(pn2);
199
200 ScalarArray dpn2 = dprattNorm2();
201 ScalarArray factor = Scalar(0.5) * dpn2 / pn;
202
203 m_dUc = ( m_dUc * pn - Base::m_uc * factor ) / pn2;
204 m_dUl = ( m_dUl * pn - Base::m_ul * factor ) / pn2;
205 m_dUq = ( m_dUq * pn - Base::m_uq * factor ) / pn2;
206
207 Base::applyPrattNorm();
208 return true;
209}
[OrientedSphereFit Definition]
typename DataPoint::Scalar Scalar
Alias to scalar type.
typename Base::ScalarArray ScalarArray
Alias to scalar derivatives array.
typename Base::VectorType VectorType
Alias to vector type.
typename Base::VectorArray VectorArray
Alias to vector derivatives array.
Algebraic Sphere fitting procedure on oriented point sets.
typename DataPoint::Scalar Scalar
Alias to scalar type.
typename Base::VectorType VectorType
Alias to vector type.
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