Ponca  aa50bfdf187919869239c5b44b748842569114c1
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(_evalPos);
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 //plane
66 Scalar s = Scalar(1.) / Base::m_ul.norm();
67 Base::m_ul = s*Base::m_ul;
68 Base::m_uc = s*Base::m_uc;
69 Base::m_uq = Scalar(0.);
70 }
71 else
72 {
73 //Generic case
74 Base::m_uq = Scalar(.5) * m_nume / m_deno;
75 Base::m_ul = (Base::m_sumN - Base::m_sumP * (Scalar(2.) * Base::m_uq)) * invSumW;
76 Base::m_uc = -invSumW * (Base::m_ul.dot(Base::m_sumP) + m_sumDotPP * Base::m_uq);
77 }
78
79 Base::m_isNormalized = false;
80
81 return Base::m_eCurrentState;
82}
83
84template < class DataPoint, class _WFunctor, int DiffType, typename T>
85void
87{
88 Base::init(_evalPos);
89
90 m_dSumN.setZero();
91
92 m_dSumDotPN.setZero();
93 m_dSumDotPP.setZero();
94 m_dNume.setZero();
95 m_dDeno.setZero();
96
97 m_dUc.setZero();
98 m_dUq.setZero();
99 m_dUl.setZero();
100}
101
102
103template < class DataPoint, class _WFunctor, int DiffType, typename T>
104bool
106 const VectorType &localQ,
107 const DataPoint &attributes,
108 ScalarArray &dw) {
109 if( Base::addLocalNeighbor(w, localQ, attributes, dw) ) {
110
111 m_dSumN += attributes.normal() * dw;
112 m_dSumDotPN += dw * attributes.normal().dot(localQ);
113 m_dSumDotPP += dw * localQ.squaredNorm();
114
115 return true;
116 }
117 return false;
118}
119
120
121template < class DataPoint, class _WFunctor, int DiffType, typename T>
124{
125 PONCA_MULTIARCH_STD_MATH(sqrt);
126
127 Base::finalize();
128 // Test if base finalize end on a viable case (stable / unstable)
129 if (this->isReady())
130 {
131 Scalar invSumW = Scalar(1.)/Base::getWeightSum();
132
133 Scalar nume = Base::m_sumDotPN - invSumW*Base::m_sumP.dot(Base::m_sumN);
134 Scalar deno = Base::m_sumDotPP - invSumW*Base::m_sumP.dot(Base::m_sumP);
135
136 // FIXME, the following product "Base::m_sumN.transpose() * m_dSumP" is prone to numerical cancellation
137 // issues for spacial derivatives because, (d sum w_i P_i)/(d x) is supposed to be tangent to the surface whereas
138 // "sum w_i N_i" is normal to the surface...
139 m_dNume = m_dSumDotPN
140 - invSumW*invSumW * ( Base::getWeightSum() * ( Base::m_sumN.transpose() * Base::m_dSumP + Base::m_sumP.transpose() * m_dSumN )
141 - Base::m_dSumW*Base::m_sumP.dot(Base::m_sumN) );
142
143 m_dDeno = m_dSumDotPP
144 - invSumW*invSumW*( Scalar(2.) * Base::getWeightSum() * Base::m_sumP.transpose() * Base::m_dSumP
145 - Base::m_dSumW*Base::m_sumP.dot(Base::m_sumP) );
146
147 m_dUq = Scalar(.5) * (deno * m_dNume - m_dDeno * nume)/(deno*deno);
148
149 // FIXME: this line is prone to numerical cancellation issues because dSumN and u_l*dSumW are close to each other.
150 // If using two passes, one could directly compute sum( dw_i + (n_i - ul) ) to avoid this issue.
151 m_dUl = invSumW * ( m_dSumN - Base::m_ul*Base::m_dSumW - Scalar(2.)*(Base::m_dSumP * Base::m_uq + Base::m_sumP * m_dUq) );
152 m_dUc = -invSumW*( Base::m_sumP.transpose() * m_dUl
153 + Base::m_sumDotPP * m_dUq
154 + Base::m_ul.transpose() * Base::m_dSumP
155 + Base::m_uq * m_dSumDotPP
156 + Base::m_dSumW * Base::m_uc);
157 }
158
159 return Base::m_eCurrentState;
160}
161
162template < class DataPoint, class _WFunctor, int DiffType, typename T>
163typename OrientedSphereDerImpl <DataPoint, _WFunctor, DiffType, T>::VectorArray
165{
166 // Computes the derivatives of the normal of the sphere at the evaluation point.
167 // Therefore, we must take into account the variation of the evaluation point when differentiating wrt space
168 // i.e., normal(x) = grad / |grad|, with grad(x) = ul + 2 uq * x, and diff_x(grad) = dul + 2 uq I
169 VectorArray dgrad = m_dUl;
170 if(Base::isSpaceDer())
171 dgrad.template rightCols<DataPoint::Dim>().diagonal().array() += Scalar(2)*Base::m_uq;
172 Scalar norm = Base::m_ul.norm();
173 Scalar norm3 = norm*norm*norm;
174 return dgrad / norm - Base::m_ul * (Base::m_ul.transpose() * dgrad) / norm3;
175}
176
177template < class DataPoint, class _WFunctor, int DiffType, typename T>
178typename OrientedSphereDerImpl <DataPoint, _WFunctor, DiffType, T>::ScalarArray
180{
181 ScalarArray dfield = m_dUc;
182 if(Base::isSpaceDer())
183 dfield.template tail<DataPoint::Dim>() += Base::m_ul;
184 return dfield;
185}
186
187template < class DataPoint, class _WFunctor, int DiffType, typename T>
188bool
190{
191 if(Base::isNormalized())
192 return false; //need original parameters without Pratt Normalization
193
194 PONCA_MULTIARCH_STD_MATH(sqrt);
195 Scalar pn2 = Base::prattNorm2();
196 Scalar pn = sqrt(pn2);
197
198 ScalarArray dpn2 = dprattNorm2();
199 ScalarArray factor = Scalar(0.5) * dpn2 / pn;
200
201 m_dUc = ( m_dUc * pn - Base::m_uc * factor ) / pn2;
202 m_dUl = ( m_dUl * pn - Base::m_ul * factor ) / pn2;
203 m_dUq = ( m_dUq * pn - Base::m_uq * factor ) / pn2;
204
205 Base::applyPrattNorm();
206 return true;
207}
[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