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