Points&Forces (survey)
Software tools facilitating the task of surveying architecture
a_shape_sphere.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_sphere.h"
17 #include <math.h>
18 #include <time.h>
19 #include <vnl/vnl_least_squares_function.h>
20 #include "a_mat_sq.h"
21 
22 //***************************************************************************
25 {
26  public:
28  const std::vector<a_point> & cloud) :
29  vnl_least_squares_function(4, cloud.size(), no_gradient),
30  shape_(shape),
31  cloud_(cloud) {};
32  void f(const vnl_vector<double>& x, vnl_vector<double>& fx);
33  protected:
35  const std::vector<a_point> & cloud_;
36 };
37 //---------------------------------------------------------------------------
38 void a_shape_sphere_function::f(const vnl_vector<double>& x, vnl_vector<double>& fx)
39 {
40  a_point center(x[0],x[1],x[2]);
41  shape_.radius(x[3]);
42  for (int i = 0; i< fx.size(); i++)
43  fx[i] = shape_.dist_point(cloud_[i]);
44 }
45 //***************************************************************************
46 //---------------------------------------------------------------------------
47 const std::string a_shape_sphere::help()
48 {
49  std::ostringstream o;
50  o << "***************" << std::endl;
51  o << "a_shape_sphere:" << std::endl;
52  o << "***************" << std::endl;
53  o << "This is a 'sphere' fitting class" << std::endl;
54  o << std::endl;
55  o << a_shape::help();
56  return o.str();
57 }
58 //---------------------------------------------------------------------------
59 void a_shape_sphere::p4pts(const a_point p1, const a_point p2, const a_point p3, const a_point p4)
60 {
61  //see http://paulbourke.net/geometry/circlesphere/
62  a_mat_sq m(4);
63  m(0,0)=p1.x(); m(0,1)=p1.y(); m(0,2)=p1.z(); m(0,3)=1.;
64  m(1,0)=p2.x(); m(1,1)=p2.y(); m(1,2)=p2.z(); m(1,3)=1.;
65  m(2,0)=p3.x(); m(2,1)=p3.y(); m(2,2)=p3.z(); m(2,3)=1.;
66  m(3,0)=p4.x(); m(3,1)=p4.y(); m(3,2)=p4.z(); m(3,3)=1.;
67  double M11 = m.determinant();
68  double t1 = p1.x()*p1.x()+p1.y()*p1.y()+p1.z()*p1.z();
69  double t2 = p2.x()*p2.x()+p2.y()*p2.y()+p2.z()*p2.z();
70  double t3 = p3.x()*p3.x()+p3.y()*p3.y()+p3.z()*p3.z();
71  double t4 = p4.x()*p4.x()+p4.y()*p4.y()+p4.z()*p4.z();
72  m(0,0)= t1; m(1,0)= t2; m(2,0)= t3; m(3,0)= t4;
73  double M12 = m.determinant();
74  m(0,1)= p1.x(); m(1,1)= p2.x(); m(2,1)= p3.x(); m(3,1)= p4.x();
75  double M13 = m.determinant();
76  m(0,2)= p1.y(); m(1,2)= p2.y(); m(2,2)= p3.y(); m(3,2)= p4.y();
77  double M14 = m.determinant();
78  m(0,3)= p1.z(); m(1,3)= p2.z(); m(2,3)= p3.z(); m(3,3)= p4.z();
79  double M15 = m.determinant();
80  a_point centre(.5*M12/M11,-.5*M13/M11,.5*M14/M11);
81  this->center(centre);
82  this->radius(sqrt(centre.sumsq()-M15/M11));
83 }
84 //---------------------------------------------------------------------------
85 a_point a_shape_sphere::closest_point(const a_point pt) const
86 {
87  a_point d = (pt-this->center()).normalise();
88  return this->center()+d*this->radius();
89 }
90 //---------------------------------------------------------------------------
91 double a_shape_sphere::dist_point(const a_point pt) const
92 {
93  a_point cp = this->closest_point(pt);
94  return pt.dist(cp);
95 }
96 //---------------------------------------------------------------------------
97 void a_shape_sphere::random_hint(const std::vector<a_point>& pts)
98 {
99  int n = pts.size();
100  int i1 = rand()%n;
101  int i2,i3,i4;
102  do
103  {
104  i2 = rand()%n;
105  } while (i1==i2);
106  do
107  {
108  i3 = rand()%n;
109  } while ((i1==i3)||(i2==i3));
110  do
111  {
112  i4 = rand()%n;
113  } while ((i1==i4)||(i2==i4)||(i3==i4));
114  a_point p1 = pts[i1];
115  a_point p2 = pts[i2];
116  a_point p3 = pts[i3];
117  a_point p4 = pts[i4];
118  // std::cerr << p1 << " * " << p2 << " * " << p3 << " * " << p4 << std::endl;
119  this->p4pts(p1,p2,p3,p4);
120 }
121 //---------------------------------------------------------------------------
122 void a_shape_sphere::fit_cloud(std::vector<a_point>& pts, short nl)
123 {
124  std::vector<a_point> pts2;
125  int cs0 = pts.size();
126  this->best_fitting_cloud(pts,pts2);
127  if (nl==1)
128  {
129  a_shape_sphere_function f(*this,pts2);
130  a_shape::fit_cloud(pts2,f);
131  }
132  pts = pts2;
133 }
134 //---------------------------------------------------------------------------
135 void a_shape_sphere::export_points(const unsigned int nseg, const std::vector<a_point>& pts) const
136 {
137  //see http://www.math.niu.edu/~rusin/known-math/95/sphere.faq
138  const double pi = 3.14159265358979;
139  a_point ce = this->center();
140  double r = this->radius();
141  std::vector<a_point> points;
142  points.push_back(ce+a_point(0.,0.,r));
143  points.push_back(ce+a_point(0.,0.,-r));
144  int K = int((sqrt(pi/4.*nseg))+.5);
145  for (int i=0; i<K; i++)
146  {
147  double ui=pi/2-i*(pi/K);
148  double li = 2*pi*cos(ui);
149  int Ki = int(li/(pi/K)+.5);
150  for (int j=0; j<Ki; j++)
151  {
152  double vi = 2*pi*j/Ki;
153  a_point dir(cos(ui)*cos(vi),cos(ui)*sin(vi),sin(ui));
154  points.push_back(ce+r*dir);
155  }
156  }
157  std::cout << points.size() << std::endl;
158  for (int i=0; i< points.size(); i++)
159  std::cout << points[i] << std::endl;
160  points.clear();
161 }
162 //---------------------------------------------------------------------------
163 int right(int ref, int max)
164 {
165  if (ref==max-1)
166  return 0;
167  else
168  return ref+1;
169 }
170 //---------------------------------------------------------------------------
171 void a_shape_sphere::export_triangles(const unsigned int nseg, const std::vector<a_point>& pts) const
172 {
173  const double pi = 3.14159265358979;
174  a_point ce = this->center();
175  double r = this->radius();
176  std::vector<std::vector<a_point> *> points;
177  auto pt_line = new std::vector<a_point>;
178  pt_line->push_back(ce+a_point(0.,0.,r));
179  points.push_back(pt_line);
180  auto pt_line2 = new std::vector<a_point>;
181  pt_line2->push_back(ce+a_point(0.,0.,-r));
182  points.push_back(pt_line2);
183  int K = int(sqrt(pi/8.*nseg)+.5);
184  K += 1-K%2;
185  std::cerr << "K = " << K << std::endl;
186  int npt_tot = 1;
187  int npt_i;
188  for (int i=1; i<=K/2; i++)
189  {
190  npt_i = 0;
191  pt_line = new std::vector<a_point>;
192  pt_line2 = new std::vector<a_point>;
193  double ui=pi/2-i*(pi/K);
194  double li = 2*pi*cos(ui);
195  int Ki = int(li/(pi/K)+.5);
196  for (int j=0; j<Ki; j++)
197  {
198  double vi = 2*pi*j/Ki;
199  a_point dir(cos(ui)*sin(vi),cos(ui)*cos(vi),sin(ui));
200  pt_line->push_back(ce+r*dir);
201  a_point dir2(cos(ui)*sin(vi),cos(ui)*cos(vi),-sin(ui));
202  pt_line2->push_back(ce+r*dir2);
203  npt_i++;
204  }
205  npt_tot += npt_i;
206  points.push_back(pt_line);
207  points.push_back(pt_line2);
208  }
209  std::cout << npt_tot*2 << std::endl;
210  for (int i=0; i<points.size();i++)
211  {
212  pt_line = points[i];
213  for (int j=0; j<pt_line->size();j++)
214  std::cout << (*pt_line)[j] << std::endl;
215  }
216  int ref1 = npt_tot*2;
217  int ref2 = ref1-npt_i*2;
218  std::vector<int> refs;
219  for (int i=points.size()-1; i>1; i--)
220  {
221  std::vector<a_point> * pt1, * pt2;
222  pt1 = points[i];
223  pt2 = points[i-2];
224  int l1 = pt1->size();
225  int l2 = pt2->size();
226  ref1 -= l1;
227  ref2 -= l2;
228  int j2 = 0;
229  for (int j=0; j<l1; j++)
230  {
231  //iterate along the segments of the long ring
232  double x1a, x1b, x2a, x2b;
233  x1a = j/double(l1);
234  x1b = right(j,l1)/double(l1);
235  x2a = j2/double(l2);
236  x2b = right(j2,l2)/double(l2);
237  double d1 = dist((*pt1)[j],(*pt2)[right(j2,l2)]);
238  double d2 = dist((*pt1)[right(j,l1)],(*pt2)[j2]);
239  int r[3];
240  if (d1<d2)
241  {
242  refs.push_back(ref1+j);
243  if (i%2==0)
244  {
245  refs.push_back(ref1+right(j,l1));
246  refs.push_back(ref2+right(j2,l2));
247  } else
248  {
249  refs.push_back(ref2+right(j2,l2));
250  refs.push_back(ref1+right(j,l1));
251  }
252  refs.push_back(ref1+j);
253  if (i%2==0)
254  {
255  refs.push_back(ref2+right(j2,l2));
256  refs.push_back(ref2+j2);
257  } else
258  {
259  refs.push_back(ref2+j2);
260  refs.push_back(ref2+right(j2,l2));
261  }
262  j2 = right(j2,l2);
263  } else
264  {
265  refs.push_back(ref1+j);
266  if (i%2==0)
267  {
268  refs.push_back(ref1+right(j,l1));
269  refs.push_back(ref2+j2);
270  } else
271  {
272  refs.push_back(ref2+j2);
273  refs.push_back(ref1+right(j,l1));
274  }
275  }
276  }
277  }
278  std::vector<a_point> * pt1 = points[points.size()-1];
279  std::vector<a_point> * pt2 = points[points.size()-2];
280  int l = pt1->size();
281  ref1 = npt_tot*2-l;
282  ref2 = ref1-l;
283  for (int i=0; i<l; i++)
284  {
285  refs.push_back(ref1+i);
286  refs.push_back(ref1+right(i,l));
287  refs.push_back(ref2+i);
288  refs.push_back(ref1+right(i,l));
289  refs.push_back(ref2+right(i,l));
290  refs.push_back(ref2+i);
291  }
292  std::cout << refs.size()/3 <<std::endl;
293  for (int i=0; i< refs.size(); i+=3)
294  std::cout << refs[i] << " " << refs[i+1] << " " << refs[i+2] << std::endl;
295 }
int right(int ref, int max)
sphere shape solver
const std::vector< a_point > & cloud_
void f(const vnl_vector< double > &x, vnl_vector< double > &fx)
a_shape_sphere_function(a_shape_sphere &shape, const std::vector< a_point > &cloud)
a_shape_sphere & shape_
sphere shape
void export_points(const unsigned int nseg, const std::vector< a_point > &pts) const
static const std::string help()
void fit_cloud(std::vector< a_point > &pts, short nl=1)
double dist_point(const a_point p) const
double radius() const
void p4pts(const a_point p1, const a_point p2, const a_point p3, const a_point p4)
a_point center() const
void random_hint(const std::vector< a_point > &pts)
a_point closest_point(const a_point p) const
void export_triangles(const unsigned int nseg, const std::vector< a_point > &pts) const
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
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
double max(double a, double b)
Definition: a_colors.cxx:30
const double pi
Definition: orient.cxx:49
a_point dir(int i, int l)
Definition: rib0.cxx:60
Definition: stlb2stla.cxx:21