Points&Forces (survey)
Software tools facilitating the task of surveying architecture
a_shape_cylinder.cxx
Go to the documentation of this file.
1 /*
2  Copyright 2015-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_cylinder.h"
17 #include <math.h>
18 #include <cstdlib>
19 #include <vnl/algo/vnl_svd.h>
20 #include <vnl/algo/vnl_matrix_inverse.h>
21 #include <vnl/algo/vnl_symmetric_eigensystem.h>
22 #include <vnl/algo/vnl_rpoly_roots.h>
23 #include <vnl/algo/vnl_levenberg_marquardt.h>
24 //***************************************************************************
27 {
28  public:
29  a_shape_cylinder_function(const std::vector<a_point> & cloud):
30  vnl_least_squares_function(7, cloud.size(), no_gradient),
31  cloud_(cloud) {};
32  //void radius(const double& r) {x[0]=r;};
33  // void center(const a_point& c) {x[1]=c.x();x[2]=c.y();x[3]=c.z();};
34  // void dir(const a_point& dir) {x[4]=dir.x();x[5]=dir.y();x[6]=dir.z();};
35  void f(const vnl_vector<double>& x, vnl_vector<double>& fx);
36  protected:
37  const std::vector<a_point> & cloud_;
38 };
39 //---------------------------------------------------------------------------
40 void a_shape_cylinder_function::f(const vnl_vector<double>& x, vnl_vector<double>& fx)
41 {
42  double r = x[0];
43  a_point c(x[1],x[2],x[3]);
44  a_point d(x[4],x[5],x[6]);
45  for (int i = 0; i< fx.size(); i++)
46  {
47  a_point v=cloud_[i]-c;
48  a_point v0=c+(v*d)*d;
49  fx[i]=(cloud_[i]-v0).norm()-r;
50  }
51 }
52 //***************************************************************************
53 //---------------------------------------------------------------------------
54 const std::string a_shape_cylinder::help()
55 {
56  std::ostringstream o;
57  o << "****************" << std::endl;
58  o << "a_shape_cylinder:" << std::endl;
59  o << "****************" << std::endl;
60  o << "This is a 'cylinder' fitting class" << std::endl;
61  o << std::endl;
62  o << a_shape::help();
63  return o.str();
64 }
65 //---------------------------------------------------------------------------
66 void a_shape_cylinder::center(a_point c)
67 {
68  if (c.norm() != 0)
69  c.normalise();
70 }
71 //---------------------------------------------------------------------------
72 a_point a_shape_cylinder::center() const
73 {
74  return center_;
75 }
76 //---------------------------------------------------------------------------
77 void a_shape_cylinder::dir(a_point d)
78 {
79  if (d.norm() != 0)
80  {
81  d.normalise();
82  }
83 }
84 //---------------------------------------------------------------------------
85 void a_shape_cylinder::radius(const double r)
86 {
87 }
88 //---------------------------------------------------------------------------
90 {
91  return radius_;
92 }
93 //---------------------------------------------------------------------------
94 a_point a_shape_cylinder::dir() const
95 {
96  return dir_;
97 }
98 //---------------------------------------------------------------------------
99 void a_shape_cylinder::p9pts(const a_point * pt)
100 {
101  vnl_matrix<double> mat(9,9);
102  vnl_matrix<double> b(9,1);
103  for (int i=0;i<9;i++)
104  {
105  double x = pt[i].x();
106  double y = pt[i].y();
107  double z = pt[i].z();
108  mat(i,0) = x*x;
109  mat(i,1) = y*y;
110  mat(i,2) = z*z;
111  mat(i,3) = 2*x*y;
112  mat(i,4) = 2*y*z;
113  mat(i,5) = 2*x*z;
114  mat(i,6) = x;
115  mat(i,7) = y;
116  mat(i,8) = z;
117  b(i,0) = 1.;
118  }
119  vnl_matrix<double> inv_mat = vnl_matrix_inverse<double>(mat).as_matrix();
120  vnl_matrix<double> x = inv_mat*b;
121  for (int i=0;i<9;i++)
122  para_[i] = x(i,0);
123  vnl_double_3x3 A = this->A();
124  //std::cerr << "*****************" << std::endl << A;
125  vnl_double_3 b2 = this->b();
126  //compute center: c
127  vnl_double_3 b3 = -b2/2.;
128  vnl_svd<double> svd(A.as_matrix());
129  svd.zero_out_relative(1.e-6);
130  vnl_double_3 c = svd.solve(b3.as_vector());
131  double d = 1.-dot_product(b2,c)-dot_product(c*A,c);
132  A /= d;
133  //check whether it is a good candidate, close to cylinder
134  double n1 = svd.W(0);
135  double n2 = svd.W(1);
136  double n3 = svd.W(2);
137  if (n1!=0)
138  {
139  n2=fabs(1-n2/n1);
140  n3=fabs(n3/n1);
141  n1=1.;
142  std::cerr << "svd " << n1 << " " << n2 << " " << n3 << std::endl;
143  if ((n2>0.1)&&(n3>0.01))
144  {
145  std::cerr << "failed! not a cylinder!" << std::endl;
146  for (short i=0;i<9;i++) para_[i]=0.;
147  radius_=0;
148  dir_.set(1.,0.,0.);
149  center_.set(0.,0.,0.);
150  return;
151  }
152  else
153  std::cerr << "passed! this is a cylinder" << std::endl;
154  }
155  //compute radius
156  double r = (svd.W(0)+svd.W(1))/2.;
157  svd.W(0) = r;
158  svd.W(1) = r;
159  svd.W(2) = 0;
160  r = sqrt(fabs(1./r));
161  radius_ = sqrt(fabs(1./r));
162  vnl_double_3x3 A2 = svd.recompose();
163  // A2 *= d;
164  para_[0] = A2(0,0);
165  para_[1] = A2(1,1);
166  para_[2] = A2(2,2);
167  para_[3] = A2(0,1);
168  para_[4] = A2(1,2);
169  para_[5] = A2(0,2);
170  center_ = a_shape_quadric::center();
171  dir_ = a_shape_quadric::n3();
172  std::cerr << "dddir " << dir_ << std::endl;
173  //std::cerr << A2 << "--------------------" << std::endl;
174 }
175 //---------------------------------------------------------------------------
176 a_point a_shape_cylinder::closest_point(const a_point pt) const
177 {
178  double r = this->radius();
179  a_point c = this->center();
180  a_point n = this->dir();
181  a_point v = pt-c;
182  a_point c1 = c+(n*v)*n;
183  a_point v2 = (pt-c1).normalise();
184  return c1+v2*r;
185 }
186 //---------------------------------------------------------------------------
187 int a_shape_cylinder::threshold_cloud(const std::vector<a_point>& pts, std::vector<a_point>& pts2)
188 {
189  int iter = 0;
190  pts2.clear();
191  this->init_dist();
192  std::cerr << "rr " << radius_ << " " << center_ << " " << dir_ << std::endl;
193  for (auto pt:pts)
194  {
195  a_point pt0 = this->closest_point(pt);
196  //a_point pt0 = a_shape_quadric::closest_point(*pt);
197  double d = (pt-pt0).norm();
198  if (d<verysmall_)
199  {
200  pts2.push_back(pt);
201  iter += 1;
202  }
203  }
204  std::cerr << "thres: " << iter << std::endl;
205  return iter;
206 }
207 //---------------------------------------------------------------------------
208 void a_shape_cylinder::fit_cloud(std::vector<a_point>& pts, short nl)
209 {
210  std::vector<a_point> pts2;
211  int cs0 = pts.size();
212  this->best_fitting_cloud(pts,pts2);
213  if (nl==1)
214  {
216  vnl_svd<double> svd(Ap_.as_matrix());
217  double r = (svd.W(0)+svd.W(1))/2.;
218  r = sqrt(fabs(1./r));
219  a_point c = a_shape_quadric::center();
220  a_point d = a_shape_quadric::n3();
221  vnl_vector<double> x(7);
222  x[0] = r;
223  x[1] = c.x();
224  x[2] = c.y();
225  x[3] = c.z();
226  x[4] = d.x();
227  x[5] = d.y();
228  x[6] = d.z();
229  vnl_levenberg_marquardt levmarq(f);
230  levmarq.minimize(x);
231  radius_ = x[0];
232  center_ = a_point(x[1],x[2],x[3]);
233  dir_ = a_point(x[4],x[5],x[6]);
234  if (verbose_)
235  {
236  std::cerr << "Least Squares Fitting (Levenberg Marquardt)" << std::endl
237  << "min: " << levmarq.get_end_error() << " at " << x << std::endl;
238  levmarq.diagnose_outcome();
239  }
240  }
241  pts = pts2;
242 }
243 //---------------------------------------------------------------------------
245 {
246  std::cout << "radius: " << radius_ << std::endl;
247  std::cout << "center: " << center_ << std::endl;
248  a_point dir=dir_;
249  if (dir[2]<0.)
250  {
251  for (short i=0;i<3;i++) dir[i]=-dir[i];
252  }
253  std::cout << "direction: " << dir << std::endl;
254  std::cout << "azimuth: " << atan2(dir[1],dir[0])*180./3.1415926535 << "°" << std::endl;
255  double b = sqrt(dir[0]*dir[0]+dir[1]*dir[1]);
256  std::cout << "elevation: " << atan2(dir[2],b)*180./3.1415926535 << "°" << std::endl;
257 }
258 //---------------------------------------------------------------------------
259 void a_shape_cylinder::export_points(const unsigned int nseg, const std::vector<a_point>& pts) const
260 {
261 }
262 //---------------------------------------------------------------------------
263 void a_shape_cylinder::export_triangles(const unsigned int nseg, const std::vector<a_point>& pts) const
264 {
265 }
quadric shape solver
const std::vector< a_point > & cloud_
void f(const vnl_vector< double > &x, vnl_vector< double > &fx)
a_shape_cylinder_function(const std::vector< a_point > &cloud)
double radius() const
void export_triangles(const unsigned int nseg, const std::vector< a_point > &pts) const
a_point center() const
void p9pts(const a_point *pt)
int threshold_cloud(const std::vector< a_point > &pts, std::vector< a_point > &pts2)
a_point dir() const
static const std::string help()
void export_points(const unsigned int nseg, const std::vector< a_point > &pts) const
void export_matrices() const
void fit_cloud(std::vector< a_point > &pts, short nl=1)
a_point closest_point(const a_point pt) const
a_point n2() const
a_point center() const
a_point n1() const
vnl_double_3 b() const
a_point n3() const
vnl_double_3x3 Ap_
vnl_double_3x3 A() const
vnl_vector< double > para_
Definition: a_shape.h:68
bool verbose_
Definition: a_shape.h:69
static const std::string help()
Definition: a_shape.cxx:21
int best_fitting_cloud(const std::vector< a_point > &pts, std::vector< a_point > &pts2)
Definition: a_shape.cxx:82
double v(const uint32_t step, const uint32_t n)
Definition: generate.cxx:42
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