Points&Forces (core)
Software tools facilitating the task of surveying architecture
a_segment.cxx
Go to the documentation of this file.
1 /*
2  Copyright 2000-17 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_segment.h"
17 #include <vector>
18 #include <algorithm>
19 #include <math.h>
20 #include <sstream>
21 
22 #include "a_debug.h"
23 
24 //---------------------------------------------------------------------------
25 const std::string a_segment::help()
26 {
27  std::ostringstream o;
28  o << "**********" << std::endl;
29  o << "a_segment:" << std::endl;
30  o << "**********" << std::endl;
31  o << "This is a 'segment' class." << std::endl;
32  o << std::endl;
33  o << "Create a segment:" << std::endl;
34  o << " a_point a 0 0 0" << std::endl;
35  o << " a_point b 1 0 0" << std::endl;
36  o << " a_segment s1 a b" << std::endl;
37  o << " set s2 [a_segment [new_a_point 0 0 0] [new_a_point 0 1 0] ]" << std::endl;
38  o << std::endl;
39  o << "Commands:" << std::endl;
40  o << "p1, p2, p1 _pt, p2 _pt: returns or set apices." << std::endl;
41  o << "c: returns centre."<< std::endl;
42  o << "vec: returns p2-p1."<< std::endl;
43  o << "dir: returns direction (normalised)."<< std::endl;
44  o << "translate _x _y _z: move segment."<< std::endl;
45  o << "rotate _xaxis _yaxis _zaxis: rotate segment; 3 points define new axis."<< std::endl;
46  o << "length: returns length of segment." << std::endl;
47  o << "project _pt: project a point on the segment."<< std::endl;
48  o << "closest _pt: returns pt closest to _pt belonging to segment."<< std::endl;
49  o << "closestl _pt: returns pt closest to _pt on line defined by segment."<< std::endl;
50  o << "dist _pt: closest distance to _pt."<< std::endl;
51  o << "dist _seg: closest distance to _seg."<< std::endl;
52  o << "distl _pt: closest distance between _pt and line defined by segment."<< std::endl;
53  o << "distl _seg: closest distance between lines defined by segments."<< std::endl;
54  o << "intersect _seg _m1* _m2*: intersection between to segments; returns a segment between the closest point between the two lines (l1,l2) defined by the segment; also returns the relative position (0-1 if inside segments) of its apices on l1 and l2." << std::endl;
55  o << "shortest _seg _m1* _m2*: shortest distance between two lines defined by segments; returns a segment between the closest point between the two segments; also returns the relative position of its apices on the input segments."<< std::endl;
56  o << "print: print segment parameters (coordinates of apices)."<< std::endl;
57  o << std::endl;
58  o << a_geom_base::help();
59  return o.str();
60 }
61 //---------------------------------------------------------------------------
62 a_segment& a_segment::rotate(const a_point& x_axis, const a_point& y_axis, const a_point& z_axis)
63 {
64  p1_.rotate(x_axis,y_axis,z_axis);
65  p2_.rotate(x_axis,y_axis,z_axis);
66  return *this;
67 }
68 //---------------------------------------------------------------------------
70 {
71  return ((p1_ == s.p1())&&(p2_ == s.p2()));
72 }
73 //---------------------------------------------------------------------------
75 {
76  p1_ = s.p1();
77  p2_ = s.p2();
78  return *this;
79 }
80 //---------------------------------------------------------------------------
82 {
83  a_mat_sq a(3);
84  a_point d = this->vec();
85  a_point c = this->c();
86  double l = this->length();
87  for (short i=0; i<3; i++)
88  {
89  double li = d[i];
90  double ci = c[i];
91  for (short j=0; j<=i; j++)
92  {
93  double lj = d[j];
94  double cj = c[j];
95  double v = l*(li*lj/12.+ci*cj);
96  a(i,j) = v;
97  a(j,i) = v;
98  }
99  }
100  return a;
101 }
102 //---------------------------------------------------------------------------
103 double a_segment::project(const a_point v) const
104 {
105  a_point dir = p2_-p1_;
106  a_point u = v-p1_;
107  return (u*dir)/(dir*dir);
108 }
109 //---------------------------------------------------------------------------
111 {
112  a_point dir = p2_-p1_;
113  double t = (p-p1_)*dir/dir.sumsq();
114  return p1_+t*dir;
115 }
116 //---------------------------------------------------------------------------
118 {
119  a_point dir = p2_-p1_;
120  double t = (p-p1_)*dir/dir.sumsq();
121  if (t<0)
122  return p1_;
123  else if (t>1)
124  return p2_;
125  else
126  return p1_+t*dir;
127 }
128 //---------------------------------------------------------------------------
129 double a_segment::distl(const a_point& p) const
130 {
131  return p.dist(this->closestl(p));
132 }
133 //---------------------------------------------------------------------------
134 double a_segment::dist(const a_point& p) const
135 {
136  return p.dist(this->closest(p));
137 }
138 //---------------------------------------------------------------------------
139 a_segment a_segment::intersect(const a_segment& s, double& m1, double& m2) const
140 {
141  const double eps = 1e-10;
142  a_point dor = p1_-s.p1();
143  a_point d1 = this->vec();
144  if (d1.sumsq() < eps) throw a_segment::null_segment_error();
145  a_point d2 = s.vec();
146  if (d2.sumsq() < eps) throw a_segment::null_segment_error();
147  double a = d1*d1;
148  double b = d2*d1;
149  double c = d2*d2;
150  double d = dor*d1;
151  double e = dor*d2;
152  double D = a*c-b*b;
153  if (fabs(D) < eps) //lines are parallel
154  {
155  m1 = 0;
156  m2 = (b>c ? d/b : e/c);
157  }
158  else
159  {
160  m1 = (b*e-c*d)/D;
161  m2 = (a*e-b*d)/D;
162  }
163  a_point r1 = p1_+m1*d1;
164  a_point r2 = s.p1()+m2*d2;
165  return a_segment(r1,r2);
166 }
167 //---------------------------------------------------------------------------
168 class pack
169 {
170  public:
171  pack(int ref, double dist) : ref_(ref), dist_(dist) {}
172  int ref_;
173  double dist_;
174 };
175 bool operator<(const pack& p1, const pack& p2) {return p1.dist_<p2.dist_;};
176 //---------------------------------------------------------------------------
177 a_segment a_segment::shortest(const a_segment& s, double& m1, double& m2) const
178 {
179  const double eps = 1e-10;
180  a_point dor = p1_-s.p1();
181  a_point d1 = p2_-p1_;
182  if (d1.sumsq() < eps) throw a_segment::null_segment_error();
183  a_point d2 = s.p2()-s.p1();
184  if (d2.sumsq() < eps) throw a_segment::null_segment_error();
185  double sd1 = d1*d1;
186  double sd1d2 = d2*d1;
187  double sd2 = d2*d2;
188  double sd1dor = dor*d1;
189  double sd2dor = dor*d2;
190  double D = (sd1*sd2-sd1d2*sd1d2);//surface of the triangle of the 2 directions
191  if (D < eps) // the lines are almost parallel
192  {
193  m1 = 0;
194  m2 = sd2dor/sd2;
195  }
196  else // get the closest points on the infinite lines
197  {
198  m1 = (sd1d2*sd2dor-sd2*sd1dor) / D;
199  m2 = (sd1*sd2dor-sd1d2*sd1dor) / D;
200  }
201  if ((m1<0)||(m1>1)||(m2<0)||(m2>1))
202  {
203  std::vector<pack> li;
204  pack p1(1,this->dist(s.p1()));
205  li.push_back(p1);
206  pack p2(2,this->dist(s.p2()));
207  li.push_back(p2);
208  pack p3(3,s.dist(p1_));
209  li.push_back(p3);
210  pack p4(4,s.dist(p2_));
211  li.push_back(p4);
212 
213  std::sort(li.begin(),li.end());
214  int ref = li[0].ref_;
215  a_point pn;
216  switch (ref)
217  {
218  case 1 :
219  pn = this->closest(s.p1());
220  m1 = ((pn-p1_)*d1)/sd1;
221  m2 = 0;
222  return a_segment(pn,s.p1());
223  case 2 :
224  pn = this->closest(s.p2());
225  m1 = ((pn-p1_)*d1)/sd1;
226  m2 = 1;
227  return a_segment(pn,s.p2());
228  case 3 :
229  pn = s.closest(p1_);
230  m1 = 0;
231  m2 = ((pn-s.p1())*d2)/sd2;
232  return a_segment(p1_,pn);
233  case 4 :
234  pn = s.closest(p2_);
235  m1 = 1;
236  m2 = ((pn-s.p1())*d2)/sd2;
237  return a_segment(p2_,pn);
238  }
239  }
240  a_point r1 = p1_+m1*d1;
241  a_point r2 = s.p1()+m2*d2;
242  return a_segment(r1,r2);
243 }
244 /*
245  a_segment a_segment::shortest(const a_segment& s, double& m1, double& m2) const
246  {
247  const double eps = 1e-10;
248  a_point dor = p1_-s.p1();
249  a_point d1 = p2_-p1_;
250  if (d1.sumsq() < eps) throw a_segment::null_segment_error();
251  a_point d2 = s.p2()-s.p1();
252  if (d2.sumsq() < eps) throw a_segment::null_segment_error();
253  bool inv = false;
254  if (d1.sumsq() < d2.sumsq())
255  {
256  a_point di = d1;
257  d1 = d2;
258  d2 = di;
259  dor = -dor;
260  inv = true;
261  }
262  std::cerr << "d1 " << d1 << std::endl;
263  std::cerr << "d2 " << d2 << std::endl;
264  std::cerr << "dor " << dor << std::endl;
265 
266  double a = d1*d1;
267  double b = d2*d1;
268  double c = d2*d2;
269  double d = dor*d1;
270  double e = dor*d2;
271  double D = a*c-b*b;
272  double sN, sD = D; // sc = sN / sD, default sD = D >= 0
273  double tN, tD = D; // tc = tN / tD, default tD = D >= 0
274 // compute the line parameters of the two closest points
275 if (D < eps) // the lines are almost parallel
276 {
277 sN = 0.0;
278 tN = e;
279 tD = c;
280 std::cerr << "13 tN " << tN << " tD " << tD << std::endl;
281 std::cerr << "sD " << sD << std::endl;
282 }
283 else // get the closest points on the infinite lines
284 {
285 std::cerr << "14" << std::endl;
286 sN = (b*e - c*d);
287 tN = (a*e - b*d);
288 if (sN < 0) // sc < 0 => the s=0 edge is visible
289 {
290 sN = 0.0;
291 tN = e;
292 tD = c;
293 }
294 else if (sN > sD) // sc > 1 => the s=1 edge is visible
295 {
296 sN = sD;
297 tN = e + b;
298 tD = c;
299 }
300 }
301 if (tN < 0) // tc < 0 => the t=0 edge is visible
302 {
303 std::cerr << "15" << std::endl;
304 tN = 0.0;
305 // recompute sc for this edge
306 if (-d < 0)
307 sN = 0.0;
308 else if (-d > a)
309 sN = sD;
310 else
311 {
312 sN = -d;
313 sD = a;
314 }
315 }
316 else if (tN > tD) // tc > 1 => the t=1 edge is visible
317 {
318  std::cerr << "16" << std::endl;
319  tN = tD;
320  // recompute sc for this edge
321  if ((-d + b) < 0)
322  sN = 0;
323  else if ((-d + b) > a)
324  sN = sD;
325  else
326  {
327  sN = (-d + b);
328  sD = a;
329  std::cerr << "a " << a << std::endl;
330  }
331 }
332 std::cerr << "sD " << sD << " tD " << tD << std::endl;
333 std::cerr << "sN " << sN << " tN " << tN << std::endl;
334 std::cerr << "*this " << *this << std::endl;
335 std::cerr << "s " << s << std::endl;
336 if ((sD==0)||(tD==0))
337 {
338  std::cerr << "error" << std::endl;
339  std::exit(-1);
340 }
341 // finally do the division to get sc and tc
342 m1 = sN / sD;
343 m2 = tN / tD;
344 
345 std::cerr << "18" << std::endl;
346 if (inv)
347 {
348  a_point r1 = s.p1()+m1*d1;
349  a_point r2 = p1_+m2*d2;
350  double m = m1;
351  m1 = m2;
352  m2 = m;
353  return a_segment(r2,r1);
354 }
355 else
356 {
357  a_point r1 = p1_+m1*d1;
358  a_point r2 = s.p1()+m2*d2;
359  return a_segment(r1,r2);
360 }
361 }*/
362 //---------------------------------------------------------------------------
363 double a_segment::distl(const a_segment& s) const
364 {
365  double m1,m2;
366  a_segment i = this->intersect(s,m1,m2);
367  return i.length();
368 }
369 //---------------------------------------------------------------------------
370 double a_segment::dist(const a_segment& s) const
371 {
372  double m1,m2;
373  a_segment i = this->shortest(s,m1,m2);
374  return i.length();
375 }
376 //***************************************************************************
377 //---------------------------------------------------------------------------
378 void a_segment::read(std::istream &in)
379 {
380  in >> p1_;
381  in >> p2_;
382 }
383 //---------------------------------------------------------------------------
384 void a_segment::write(std::ostream &o) const
385 {
386  o << this->p1() << " ";
387  o << this->p2() << " ";
388 }
double dist(const a_point &a, const a_point &b)
Definition: a_point.h:111
bool operator<(const pack &p1, const pack &p2)
Definition: a_segment.cxx:175
static const std::string help()
Definition: a_geom_base.cxx:21
a square matrix unit
Definition: a_mat_sq.h:29
a_point & rotate(const a_point &x_axis, const a_point &y_axis, const a_point &z_axis)
Definition: a_point.cxx:225
double sumsq() const
Definition: a_point.cxx:163
double dist(const a_point &p) const
Definition: a_point.h:96
a segment
Definition: a_segment.h:29
bool operator==(const a_segment &p)
Definition: a_segment.cxx:69
double dist(const a_point &p) const
distance betweeen p and segment
Definition: a_segment.cxx:134
static const std::string help()
Definition: a_segment.cxx:25
a_point dir() const
get direction defined by segment
Definition: a_segment.h:44
a_segment()
Definition: a_segment.h:31
a_point vec() const
get vector between the two apices
Definition: a_segment.h:42
a_segment shortest(const a_segment &s, double &m1, double &m2) const
intersection between two segments, returns a segment between the closest point between the two segmen...
Definition: a_segment.cxx:177
a_segment & rotate(const a_point &x_axis, const a_point &y_axis, const a_point &z_axis)
Definition: a_segment.cxx:62
double project(const a_point v) const
Definition: a_segment.cxx:103
a_point p2_
Definition: a_segment.h:94
a_point c() const
center of segment
Definition: a_segment.h:46
double length() const
Definition: a_segment.h:57
virtual void read(std::istream &i)
Definition: a_segment.cxx:378
a_mat_sq inertia() const
inertia of the segment
Definition: a_segment.cxx:81
a_segment intersect(const a_segment &s, double &m1, double &m2) const
intersection between two segments, returns a segment between the closest point between the two lines ...
Definition: a_segment.cxx:139
a_point closestl(const a_point &p) const
point closest to p on line defined by segment
Definition: a_segment.cxx:110
a_point p2() const
get second apex of segment
Definition: a_segment.h:40
a_point closest(const a_point &p) const
point closest to p inside segment
Definition: a_segment.cxx:117
double distl(const a_point &p) const
distance between p and line defined by segment
Definition: a_segment.cxx:129
a_point p1_
Definition: a_segment.h:93
a_segment & operator=(const a_segment &v)
Definition: a_segment.cxx:74
virtual void write(std::ostream &o) const
Definition: a_segment.cxx:384
a_point p1() const
get first apex of segment
Definition: a_segment.h:38
pack(int ref, double dist)
Definition: a_segment.cxx:171
int ref_
Definition: a_segment.cxx:172
double dist_
Definition: a_segment.cxx:173