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