Points&Forces (survey)
Software tools facilitating the task of surveying architecture
a_shape_quadric.cxx
Go to the documentation of this file.
1 /*
2  Copyright 2009-2020 Pierre SMARS (smars@yuntech.edu.tw)
3  This program is free software: you can redistribute it and/or modify
4  it under the terms of the GNU General Public License as published by
5  the Free Software Foundation, either version 2 of the License, or
6  (at your option) any later version.
7 
8  This program is distributed in the hope that it will be useful,
9  but WITHOUT ANY WARRANTY; without even the implied warranty of
10  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  GNU General Public License for more details.
12 
13  You should have received a copy of the GNU General Public License
14  along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16 #include "a_shape_quadric.h"
17 #include <math.h>
18 #include <cstdlib>
19 #include <vnl/vnl_least_squares_function.h>
20 #include <vnl/algo/vnl_svd.h>
21 #include <vnl/algo/vnl_rpoly_roots.h>
22 #include <vnl/algo/vnl_matrix_inverse.h>
23 #include <vnl/algo/vnl_matrix_inverse.h>
24 #include <vnl/algo/vnl_matrix_inverse.h>
25 #include <vnl/algo/vnl_matrix_inverse.h>
26 #include <vnl/algo/vnl_matrix_inverse.h>
27 #include <vnl/algo/vnl_matrix_inverse.h>
28 #include <vnl/algo/vnl_matrix_inverse.h>
29 #include <vnl/algo/vnl_matrix_inverse.h>
30 #include <vnl/algo/vnl_matrix_inverse.h>
31 #include <vnl/algo/vnl_matrix_inverse.h>
32 
33 //***************************************************************************
36 {
37  public:
39  const std::vector<a_point> & cloud) :
40  vnl_least_squares_function(9, cloud.size(), no_gradient),
41  shape_(shape),
42  cloud_(cloud) {};
43  void f(const vnl_vector<double>& x, vnl_vector<double>& fx);
44  protected:
46  const std::vector<a_point> & cloud_;
47 };
48 //---------------------------------------------------------------------------
49 void a_shape_quadric_function::f(const vnl_vector<double>& x, vnl_vector<double>& fx)
50 {
51  for (int i = 0; i<9; i++)
52  shape_.para(i,x[i]);
53  shape_.init_dist();
54  for (int i = 0; i< fx.size(); i++)
55  fx[i] = shape_.dist_point(cloud_[i]);
56 }
57 //***************************************************************************
58 //---------------------------------------------------------------------------
59 const std::string a_shape_quadric::help()
60 {
61  std::ostringstream o;
62  o << "****************" << std::endl;
63  o << "a_shape_quadric:" << std::endl;
64  o << "****************" << std::endl;
65  o << "This is a 'quadric' fitting class" << std::endl;
66  o << std::endl;
67  o << a_shape::help();
68  return o.str();
69 }
70 //---------------------------------------------------------------------------
72 {
73  for (short i=0;i<3;i++) para_[i] = 1.;
74  for (short i=3;i<9;i++) para_[i] = 0.;
75  this->init_dist();
76 }
77 //---------------------------------------------------------------------------
78 vnl_double_3x3 a_shape_quadric::A() const
79 {
80  vnl_double_3x3 a;
81  a(0,0) = para_[0];
82  a(1,1) = para_[1];
83  a(2,2) = para_[2];
84  a(0,1) = para_[3];
85  a(0,2) = para_[5];
86  a(1,0) = para_[3];
87  a(1,2) = para_[4];
88  a(2,0) = para_[5];
89  a(2,1) = para_[4];
90  return a;
91 }
92 //---------------------------------------------------------------------------
94 {
95  a_point c = a_shape_quadric::center();
96  vnl_double_3 k(c.x(),c.y(),c.z());
97  double cp = dot_product(b_,k)+dot_product(A_*k,k)-1.;
98  Ap_ = -A_/cp;
99 }
100 //---------------------------------------------------------------------------
101 vnl_double_3 a_shape_quadric::b() const
102 {
103  vnl_double_3 b;
104  b(0) = para_[6];
105  b(1) = para_[7];
106  b(2) = para_[8];
107  return b;
108 }
109 //---------------------------------------------------------------------------
110 void a_shape_quadric::p9pts(const a_point & p1, const a_point & p2, const a_point & p3,
111  const a_point & p4, const a_point & p5, const a_point & p6,
112  const a_point & p7, const a_point & p8, const a_point & p9)
113 {
114  a_point p[9];
115  p[0] = p1; p[1] = p2; p[2] = p3;
116  p[3] = p4; p[4] = p5; p[5] = p6;
117  p[6] = p7; p[7] = p8; p[8] = p9;
118  this->p9pts(p);
119 }
120 //---------------------------------------------------------------------------
121 void a_shape_quadric::p9pts(const a_point * pt)
122 {
123  vnl_matrix<double> mat(9,9);
124  vnl_vector<double> b(9);
125  for (int i=0;i<9;i++)
126  {
127  double x = pt[i].x();
128  double y = pt[i].y();
129  double z = pt[i].z();
130  mat(i,0) = x*x;
131  mat(i,1) = y*y;
132  mat(i,2) = z*z;
133  mat(i,3) = 2*x*y;
134  mat(i,4) = 2*y*z;
135  mat(i,5) = 2*x*z;
136  mat(i,6) = x;
137  mat(i,7) = y;
138  mat(i,8) = z;
139  b(i) = 1.;
140  }
141  vnl_svd<double> svd(mat);
142  vnl_vector<double> x = svd.solve(b);
143  for (int i=0;i<9;i++)
144  para_[i] = x(i);
145  this->init_dist();
146 }
147 //---------------------------------------------------------------------------
148 vnl_vector<double> clean_poly(vnl_vector<double>& k)
149 {
150  int n = k.size();
151  if (n==1)
152  return k;
153  vnl_vector<double> kn(n-1);
154  double kr = k[0];
155  //if first factor is null, it can be eliminated directly
156  //cannot be threshold at this stage because all factors may be very small
157  if (kr==0.)
158  {
159  for (int i=1; i<n; i++)
160  kn[i-1] = k[i];
161  return clean_poly(kn);
162  }
163  //divide all factors so that first one = 1.
164  for (int i=0; i<n; i++)
165  {
166  k[i] /= kr;
167  //eliminate very small factors
168  if (k[i] < 1.e-6) k[i] = 0.;
169  }
170  //if 2d factor is very big, first one can be eliminated
171  if (fabs(k[1])>1.e6)
172  {
173  for (int i=1; i<n; i++)
174  kn[i-1] = k[i];
175  return clean_poly(kn);
176  }
177  return k;
178 }
179 //---------------------------------------------------------------------------
181 {
182  A_ = this->A();
183  b_ = this->b();
184  vnl_symmetric_eigensystem<double> eig(A_.as_matrix());
185  R_ = eig.V;
186  d0_ = eig.get_eigenvalue(0);
187  d1_ = eig.get_eigenvalue(1);
188  d2_ = eig.get_eigenvalue(2);
189  this->Ap();
190 }
191 //---------------------------------------------------------------------------
192 a_point a_shape_quadric::closest_point(const a_point pt) const
193 {
194  // get parameters of the equation: xT.A.x + bT.x + c = 0
197  double c = -1.;
198  //check whether point is on quadric
199  vnl_double_3 pt0(pt.x(),pt.y(),pt.z());
200  // double on = fabs(dot_product(A*pt0,pt0) + dot_product(b,pt0)-1.);
201  // if (on<1.e-6)
202  // return pt;
203  // decompose matrix A: A = RT.D.R
206  //
207  // 1. compute coefficients first term
208  double a00 = 1.;
209  double a01 = 4*(d1_+d2_);
210  double a02 = 4*(d1_*d1_+d2_*d2_+4*d1_*d2_);
211  double a03 = 16*d1_*d2_*(d1_+d2_);
212  double a04 = 16*d1_*d1_*d2_*d2_;
213  double a10 = 1.;
214  double a11 = 4*(d0_+d2_);
215  double a12 = 4*(d0_*d0_+d2_*d2_+4*d0_*d2_);
216  double a13 = 16*d0_*d2_*(d0_+d2_);
217  double a14 = 16*d0_*d0_*d2_*d2_;
218  double a20 = 1.;
219  double a21 = 4*(d0_+d1_);
220  double a22 = 4*(d0_*d0_+d1_*d1_+4*d0_*d1_);
221  double a23 = 16*d0_*d1_*(d0_+d1_);
222  double a24 = 16*d0_*d0_*d1_*d1_;
223  //
224  vnl_double_3 alpha = R_.transpose()*pt0;
225  vnl_double_3 beta = R_.transpose()*b_;
226  //
227  double a0 = alpha[0];
228  double a1 = alpha[1];
229  double a2 = alpha[2];
230  double b0 = beta[0];
231  double b1 = beta[1];
232  double b2 = beta[2];
233  //
234  double c00 = a0*a0*d0_;
235  double c01 = -2*a0*b0*d0_;
236  double c02 = b0*b0*d0_;
237  double c10 = a1*a1*d1_;
238  double c11 = -2*a1*b1*d1_;
239  double c12 = b1*b1*d1_;
240  double c20 = a2*a2*d2_;
241  double c21 = -2*a2*b2*d2_;
242  double c22 = b2*b2*d2_;
243  //
244  double d00 = c00*a00;
245  double d01 = c00*a01+c01*a00;
246  double d02 = c00*a02+c01*a01+c02*a00;
247  double d03 = c00*a03+c01*a02+c02*a01;
248  double d04 = c00*a04+c01*a03+c02*a02;
249  double d05 = c01*a04+c02*a03;
250  double d06 = c02*a04;
251  //
252  double d10 = c10*a10;
253  double d11 = c10*a11+c11*a10;
254  double d12 = c10*a12+c11*a11+c12*a10;
255  double d13 = c10*a13+c11*a12+c12*a11;
256  double d14 = c10*a14+c11*a13+c12*a12;
257  double d15 = c11*a14+c12*a13;
258  double d16 = c12*a14;
259  //
260  double d20 = c20*a20;
261  double d21 = c20*a21+c21*a20;
262  double d22 = c20*a22+c21*a21+c22*a20;
263  double d23 = c20*a23+c21*a22+c22*a21;
264  double d24 = c20*a24+c21*a23+c22*a22;
265  double d25 = c21*a24+c22*a23;
266  double d26 = c22*a24;
267  // 1.n results
268  double dd0 = d00+d10+d20;
269  double dd1 = d01+d11+d21;
270  double dd2 = d02+d12+d22;
271  double dd3 = d03+d13+d23;
272  double dd4 = d04+d14+d24;
273  double dd5 = d05+d15+d25;
274  double dd6 = d06+d16+d26;
275  // 2. compute coefficients 2d term
276  double e00 = a0*b0;
277  double e01 = 2*a0*b0*d0_-b0*b0;
278  double e02 = -2*b0*b0*d0_;
279  //
280  double e10 = a1*b1;
281  double e11 = 2*a1*b1*d1_-b1*b1;
282  double e12 = -2*b1*b1*d1_;
283  //
284  double e20 = a2*b2;
285  double e21 = 2*a2*b2*d2_-b2*b2;
286  double e22 = -2*b2*b2*d2_;
287  //
288  double f00 = e00*a00;
289  double f01 = e00*a01+e01*a00;
290  double f02 = e00*a02+e01*a01+e02*a00;
291  double f03 = e00*a03+e01*a02+e02*a01;
292  double f04 = e00*a04+e01*a03+e02*a02;
293  double f05 = e01*a04+e02*a03;
294  double f06 = e02*a04;
295  //
296  double f10 = e10*a10;
297  double f11 = e10*a11+e11*a10;
298  double f12 = e10*a12+e11*a11+e12*a10;
299  double f13 = e10*a13+e11*a12+e12*a11;
300  double f14 = e10*a14+e11*a13+e12*a12;
301  double f15 = e11*a14+e12*a13;
302  double f16 = e12*a14;
303  //
304  double f20 = e20*a20;
305  double f21 = e20*a21+e21*a20;
306  double f22 = e20*a22+e21*a21+e22*a20;
307  double f23 = e20*a23+e21*a22+e22*a21;
308  double f24 = e20*a24+e21*a23+e22*a22;
309  double f25 = e21*a24+e22*a23;
310  double f26 = e22*a24;
311  // 2.n results
312  double f0 = f00+f10+f20;
313  double f1 = f01+f11+f21;
314  double f2 = f02+f12+f22;
315  double f3 = f03+f13+f23;
316  double f4 = f04+f14+f24;
317  double f5 = f05+f15+f25;
318  double f6 = f06+f16+f26;
319  // 3. compute coefficients 3d term
320  double g0 = c;
321  double g1 = 4*d0_*c;
322  double g2 = g1*d0_;
323  // 3.n results
324  double h0 = g0*a00;
325  double h1 = g0*a01+g1*a00;
326  double h2 = g0*a02+g1*a01+g2*a00;
327  double h3 = g0*a03+g1*a02+g2*a01;
328  double h4 = g0*a04+g1*a03+g2*a02;
329  double h5 = g1*a04+g2*a03;
330  double h6 = g2*a04;
331  // total of the 3 terms : coefficients of the polynomial
332  vnl_vector<double> k(7);
333  k[6] = dd0+f0+h0;
334  k[5] = dd1+f1+h1;
335  k[4] = dd2+f2+h2;
336  k[3] = dd3+f3+h3;
337  k[2] = dd4+f4+h4;
338  k[1] = dd5+f5+h5;
339  k[0] = dd6+f6+h6;
340  vnl_vector<double> roots;
341  vnl_vector<double> k2 = clean_poly(k);
342  vnl_rpoly_roots poly(k2);
343  roots = poly.realroots();
344  vnl_double_3x3 I(0.);
345  I(0,0) = 1.;
346  I(1,1) = 1.;
347  I(2,2) = 1.;
348  vnl_double_3 x0;
349  double li0 = 1.e30;
350  for (int i=0; i<roots.size(); i++)
351  {
352  vnl_svd<double> svd(I+2*roots(i)*A_.as_matrix());
353  svd.zero_out_relative(1.e-6);
354  vnl_double_3 x = svd.solve(pt0-roots(i)*b_.as_vector());
355  double li = (x-pt0).magnitude();
356  if (li<li0)
357  {
358  li0 = li;
359  x0 = x;
360  }
361  }
362  return a_point(x0(0),x0(1),x0(2));
363 }
364 //---------------------------------------------------------------------------
365 a_point a_shape_quadric::center() const
366 {
367  vnl_svd<double> svd(A_.as_matrix());
368  svd.zero_out_relative(1.e-6);
369  vnl_double_3 x = svd.solve(b_.as_vector())/(-2.);
370  return a_point(x(0),x(1),x(2));
371 }
372 //---------------------------------------------------------------------------
374 {
375  vnl_symmetric_eigensystem<double> eig(Ap_.as_matrix());
376  double d0 = eig.get_eigenvalue(0);
377  double d1 = eig.get_eigenvalue(1);
378  double d2 = eig.get_eigenvalue(2);
379  return a_point(d2,d1,d0);
380 }
381 //---------------------------------------------------------------------------
382 a_point a_shape_quadric::n1() const
383 {
384  vnl_symmetric_eigensystem<double> eig(Ap_.as_matrix());
385  vnl_double_3 n = eig.get_eigenvector(2);
386  return a_point(n(0),n(1),n(2));
387 }
388 //---------------------------------------------------------------------------
389 a_point a_shape_quadric::n2() const
390 {
391  vnl_symmetric_eigensystem<double> eig(Ap_.as_matrix());
392  vnl_double_3 n = eig.get_eigenvector(1);
393  return a_point(n(0),n(1),n(2));
394 }
395 //---------------------------------------------------------------------------
396 a_point a_shape_quadric::n3() const
397 {
398  vnl_symmetric_eigensystem<double> eig(Ap_.as_matrix());
399  vnl_double_3 n = eig.get_eigenvector(0);
400  return a_point(n(0),n(1),n(2));
401 }
402 //---------------------------------------------------------------------------
403 double a_shape_quadric::dist_point(const a_point pt) const
404 {
405  a_point proj = this->closest_point(pt);
406  return (pt-proj).norm();
407 }
408 //---------------------------------------------------------------------------
409 void a_shape_quadric::random_hint(const std::vector<a_point>& pts)
410 {
411  int n = pts.size();
412  int i[9];
413  a_point pt[9];
414  std::cerr << "hint: ";
415  for (int j=0; j<9; j++)
416  {
417  bool passed;
418  int it;
419  do {
420  passed = true;
421  it = rand()%n;
422  int k=0;
423  while ((k<j)&&(passed))
424  {
425  if (it==i[k])
426  passed = false;
427  k++;
428  }
429  } while (!passed);
430  i[j] = it;
431  pt[j] = pts[it];
432  std::cerr << it << " ";
433  }
434  std::cerr << std::endl;
435  this->p9pts(pt);
436 }
437 //---------------------------------------------------------------------------
438 void a_shape_quadric::fit_cloud(std::vector<a_point>& pts, short nl)
439 {
440  std::vector<a_point> pts2;
441  int cs0 = pts.size();
442  this->best_fitting_cloud(pts,pts2);
443  if (nl==1)
444  {
445  a_shape_quadric_function f(*this,pts2);
446  a_shape::fit_cloud(pts2,f);
447  }
448  pts = pts2;
449 }
450 //---------------------------------------------------------------------------
452 {
453  std::cout << "A:" << std::endl;
454  std::cout << A_;
455  std::cout << "b:" << std::endl;
456  std::cout << b_ << std::endl;
457  std::cout << "center:" << std::endl;
458  std::cout << this->center() << std::endl;
459  std::cout << "Ap:" << std::endl;
460  std::cout << Ap_;
461  std::cout << "eigen values:" << std::endl;
462  std::cout << this->principals() << std::endl;
463  std::cout << "eigen vectors:" << std::endl;
464  std::cout << "n1: " << this->n1() << std::endl;
465  std::cout << "n2: " << this->n2() << std::endl;
466  std::cout << "n3: " << this->n3() << std::endl;
467 }
468 //---------------------------------------------------------------------------
469 void a_shape_quadric::export_points(const unsigned int nseg, const std::vector<a_point>& pts) const
470 {
471 }
472 //---------------------------------------------------------------------------
473 void a_shape_quadric::export_triangles(const unsigned int nseg, const std::vector<a_point>& pts) const
474 {
475 }
vnl_vector< double > clean_poly(vnl_vector< double > &k)
quadric shape solver
const std::vector< a_point > & cloud_
a_shape_quadric_function(a_shape_quadric &shape, const std::vector< a_point > &cloud)
a_shape_quadric & shape_
void f(const vnl_vector< double > &x, vnl_vector< double > &fx)
a_point n2() const
a_point center() const
a_point n1() const
vnl_double_3 b() const
a_point n3() const
vnl_double_3x3 A_
vnl_double_3x3 Ap_
a_point principals() const
vnl_matrix< double > R_
void export_triangles(const unsigned int nseg, const std::vector< a_point > &pts) const
void fit_cloud(std::vector< a_point > &pts, short nl=1)
vnl_double_3 b_
void random_hint(const std::vector< a_point > &pts)
vnl_double_3x3 A() const
static const std::string help()
virtual double dist_point(a_point p) const
virtual a_point closest_point(const a_point p) const
virtual void export_matrices() const
void export_points(const unsigned int nseg, const std::vector< a_point > &pts) const
virtual void p9pts(const a_point *pt)
shape
Definition: a_shape.h:32
vnl_vector< double > para_
Definition: a_shape.h:68
void fit_cloud(const std::vector< a_point > &pts, vnl_least_squares_function &fn)
Definition: a_shape.cxx:126
static const std::string help()
Definition: a_shape.cxx:21
void para(const int i, const double val)
Definition: a_shape.h:57
int best_fitting_cloud(const std::vector< a_point > &pts, std::vector< a_point > &pts2)
Definition: a_shape.cxx:82
uint32_t n[]
Definition: generate.cxx:34
Definition: stlb2stla.cxx:21
float y
Definition: stlb2stla.cxx:23
float z
Definition: stlb2stla.cxx:24
float x
Definition: stlb2stla.cxx:22