MRPT  1.9.9
geometry.cpp
Go to the documentation of this file.
1 /* +------------------------------------------------------------------------+
2  | Mobile Robot Programming Toolkit (MRPT) |
3  | https://www.mrpt.org/ |
4  | |
5  | Copyright (c) 2005-2020, Individual contributors, see AUTHORS file |
6  | See: https://www.mrpt.org/Authors - All rights reserved. |
7  | Released under BSD License. See: https://www.mrpt.org/License |
8  +------------------------------------------------------------------------+ */
9 
10 #include "math-precomp.h" // Precompiled headers
11 
13 #include <mrpt/math/CMatrixFixed.h>
14 #include <mrpt/math/CPolygon.h>
16 #include <mrpt/math/CVectorFixed.h>
17 #include <mrpt/math/TLine2D.h>
18 #include <mrpt/math/TLine3D.h>
19 #include <mrpt/math/TObject2D.h>
20 #include <mrpt/math/TObject3D.h>
21 #include <mrpt/math/TPose2D.h>
22 #include <mrpt/math/TPose3D.h>
23 #include <mrpt/math/data_utils.h>
24 #include <mrpt/math/geometry.h>
26 #include <Eigen/Dense>
27 
28 using namespace mrpt;
29 using namespace std;
30 using namespace mrpt::math;
31 
32 static double geometryEpsilon = 1e-5;
33 
36 /*---------------------------------------------------------------
37  Returns the closest point to a segment
38  ---------------------------------------------------------------*/
40  double Px, double Py, double x1, double y1, double x2, double y2,
41  double& out_x, double& out_y)
42 {
43  if (x1 == x2 && y1 == y2)
44  {
45  out_x = x1;
46  out_y = y1;
47  }
48  else
49  {
50  double Dx = x2 - x1;
51  double Dy = y2 - y1;
52  double Ratio = ((Px - x1) * Dx + (Py - y1) * Dy) / (Dx * Dx + Dy * Dy);
53  if (Ratio < 0)
54  {
55  out_x = x1;
56  out_y = y1;
57  }
58  else
59  {
60  if (Ratio > 1)
61  {
62  out_x = x2;
63  out_y = y2;
64  }
65  else
66  {
67  out_x = x1 + (Ratio * Dx);
68  out_y = y1 + (Ratio * Dy);
69  }
70  }
71  }
72 }
73 
74 /*---------------------------------------------------------------
75  Returns the closest point to a line
76  ---------------------------------------------------------------*/
78  double Px, double Py, double x1, double y1, double x2, double y2,
79  double& out_x, double& out_y)
80 {
81  if (x1 == x2 && y1 == y2)
82  {
83  out_x = x1;
84  out_y = y1;
85  }
86  else
87  {
88  double Dx = x2 - x1;
89  double Dy = y2 - y1;
90  double Ratio = ((Px - x1) * Dx + (Py - y1) * Dy) / (Dx * Dx + Dy * Dy);
91 
92  out_x = x1 + (Ratio * Dx);
93  out_y = y1 + (Ratio * Dy);
94  }
95 }
96 
97 /*---------------------------------------------------------------
98  Returns the sq. distance to closest point to a line
99  ---------------------------------------------------------------*/
101  double Px, double Py, double x1, double y1, double x2, double y2)
102 {
103  if (x1 == x2 && y1 == y2)
104  {
105  return square(Px - x1) + square(Py - y1);
106  }
107  else
108  {
109  double Dx = x2 - x1;
110  double Dy = y2 - y1;
111  double Ratio = ((Px - x1) * Dx + (Py - y1) * Dy) / (Dx * Dx + Dy * Dy);
112 
113  return square(x1 + (Ratio * Dx) - Px) + square(y1 + (Ratio * Dy) - Py);
114  }
115 }
116 
117 /*---------------------------------------------------------------
118  Intersect
119  ---------------------------------------------------------------*/
121  const double x1, const double y1, const double x2, const double y2,
122  const double x3, const double y3, const double x4, const double y4,
123  double& ix, double& iy)
124 {
125  double UpperX, UpperY, LowerX, LowerY, Ax, Bx, Cx, Ay, By, Cy, d, f, e,
126  Ratio;
127 
128  Ax = x2 - x1;
129  Bx = x3 - x4;
130 
131  if (Ax < 0)
132  {
133  LowerX = x2;
134  UpperX = x1;
135  }
136  else
137  {
138  UpperX = x2;
139  LowerX = x1;
140  }
141 
142  if (Bx > 0)
143  {
144  if (UpperX < x4 || x3 < LowerX) return false;
145  }
146  else if (UpperX < x3 || x4 < LowerX)
147  return false;
148 
149  Ay = y2 - y1;
150  By = y3 - y4;
151 
152  if (Ay < 0)
153  {
154  LowerY = y2;
155  UpperY = y1;
156  }
157  else
158  {
159  UpperY = y2;
160  LowerY = y1;
161  }
162 
163  if (By > 0)
164  {
165  if (UpperY < y4 || y3 < LowerY) return false;
166  }
167  else if (UpperY < y3 || y4 < LowerY)
168  return false;
169 
170  Cx = x1 - x3;
171  Cy = y1 - y3;
172  d = (By * Cx) - (Bx * Cy);
173  f = (Ay * Bx) - (Ax * By);
174 
175  if (f > 0)
176  {
177  if (d < 0 || d > f) return false;
178  }
179  else if (d > 0 || d < f)
180  return false;
181 
182  e = (Ax * Cy) - (Ay * Cx);
183 
184  if (f > 0)
185  {
186  if (e < 0 || e > f) return false;
187  }
188  else if (e > 0 || e < f)
189  return false;
190 
191  Ratio = (Ax * -By) - (Ay * -Bx);
192 
193  if (Ratio != 0)
194  {
195  Ratio = ((Cy * -Bx) - (Cx * -By)) / Ratio;
196  ix = x1 + (Ratio * Ax);
197  iy = y1 + (Ratio * Ay);
198  }
199  else
200  {
201  if ((Ax * -Cy) == (-Cx * Ay))
202  {
203  ix = x3;
204  iy = y3;
205  }
206  else
207  {
208  ix = x4;
209  iy = y4;
210  }
211  }
212  return true;
213 }
214 
215 /*---------------------------------------------------------------
216  Intersect
217  ---------------------------------------------------------------*/
219  const double x1, const double y1, const double x2, const double y2,
220  const double x3, const double y3, const double x4, const double y4,
221  float& ix, float& iy)
222 {
223  double x, y;
224  bool b = SegmentsIntersection(x1, y1, x2, y2, x3, y3, x4, y4, x, y);
225  ix = d2f(x);
226  iy = d2f(y);
227  return b;
228 }
229 
230 /*---------------------------------------------------------------
231  Intersect
232  ---------------------------------------------------------------*/
234  double px, double py, unsigned int polyEdges, const double* poly_xs,
235  const double* poly_ys)
236 {
237  unsigned int i, j;
238  bool res = false;
239 
240  if (polyEdges < 3) return res;
241 
242  j = polyEdges - 1;
243 
244  for (i = 0; i < polyEdges; i++)
245  {
246  if ((poly_ys[i] <= py && py < poly_ys[j]) || // an upward crossing
247  (poly_ys[j] <= py && py < poly_ys[i])) // a downward crossing
248  {
249  // compute the edge-ray intersect @ the x-coordinate
250  if (px - poly_xs[i] <
251  ((poly_xs[j] - poly_xs[i]) * (py - poly_ys[i]) /
252  (poly_ys[j] - poly_ys[i])))
253  res = !res;
254  }
255  j = i;
256  }
257 
258  return res;
259 }
260 
261 /*---------------------------------------------------------------
262  Intersect
263  ---------------------------------------------------------------*/
265  double px, double py, unsigned int polyEdges, const double* poly_xs,
266  const double* poly_ys)
267 {
268  unsigned int i, j;
269  double minDist = 1e20f;
270 
271  // Is the point INTO?
272  if (pointIntoPolygon2D(px, py, polyEdges, poly_xs, poly_ys)) return 0;
273 
274  // Compute the closest distance from the point to any segment:
275  j = polyEdges - 1;
276 
277  for (i = 0; i < polyEdges; i++)
278  {
279  // segment: [j]-[i]
280  // ----------------------
281  double closestX, closestY;
283  px, py, poly_xs[j], poly_ys[j], poly_xs[i], poly_ys[i], closestX,
284  closestY);
285 
286  minDist = min(d, minDist);
287 
288  // For next iter:
289  j = i;
290  }
291 
292  return minDist;
293 }
294 
295 /*---------------------------------------------------------------
296  minDistBetweenLines
297  --------------------------------------------------------------- */
299  double p1_x, double p1_y, double p1_z, double p2_x, double p2_y,
300  double p2_z, double p3_x, double p3_y, double p3_z, double p4_x,
301  double p4_y, double p4_z, double& x, double& y, double& z, double& dist)
302 {
303  const double EPS = 1e-30f;
304 
305  double p13_x, p13_y, p13_z;
306  double p43_x, p43_y, p43_z;
307  double p21_x, p21_y, p21_z;
308 
309  double d1343, d4321, d1321, d4343, d2121;
310  double numer, denom;
311 
312  p13_x = p1_x - p3_x;
313  p13_y = p1_y - p3_y;
314  p13_z = p1_z - p3_z;
315 
316  p43_x = p4_x - p3_x;
317  p43_y = p4_y - p3_y;
318  p43_z = p4_z - p3_z;
319 
320  if (fabs(p43_x) < EPS && fabs(p43_y) < EPS && fabs(p43_z) < EPS)
321  return false;
322 
323  p21_x = p2_x - p1_x;
324  p21_y = p2_y - p1_y;
325  p21_z = p2_z - p1_z;
326  if (fabs(p21_x) < EPS && fabs(p21_y) < EPS && fabs(p21_z) < EPS)
327  return false;
328 
329  d1343 = p13_x * p43_x + p13_y * p43_y + p13_z * p43_z;
330  d4321 = p43_x * p21_x + p43_y * p21_y + p43_z * p21_z;
331  d1321 = p13_x * p21_x + p13_y * p21_y + p13_z * p21_z;
332  d4343 = p43_x * p43_x + p43_y * p43_y + p43_z * p43_z;
333  d2121 = p21_x * p21_x + p21_y * p21_y + p21_z * p21_z;
334 
335  denom = d2121 * d4343 - d4321 * d4321;
336  if (fabs(denom) < EPS) return false;
337 
338  numer = d1343 * d4321 - d1321 * d4343;
339 
340  double mua = numer / denom;
341  double mub = (d1343 + d4321 * mua) / d4343;
342  double pa_x, pa_y, pa_z;
343  double pb_x, pb_y, pb_z;
344 
345  pa_x = p1_x + mua * p21_x;
346  pa_y = p1_y + mua * p21_y;
347  pa_z = p1_z + mua * p21_z;
348 
349  pb_x = p3_x + mub * p43_x;
350  pb_y = p3_y + mub * p43_y;
351  pb_z = p3_z + mub * p43_z;
352 
353  dist = (double)sqrt(
354  square(pa_x - pb_x) + square(pa_y - pb_y) + square(pa_z - pb_z));
355 
356  // the mid point:
357  x = 0.5 * (pa_x + pb_x);
358  y = 0.5 * (pa_y + pb_y);
359  z = 0.5 * (pa_z + pb_z);
360 
361  return true;
362 }
363 
364 /*---------------------------------------------------------------
365  Rectangles Intersect
366  ---------------------------------------------------------------*/
368  double R1_x_min, double R1_x_max, double R1_y_min, double R1_y_max,
369  double R2_x_min, double R2_x_max, double R2_y_min, double R2_y_max,
370  double R2_pose_x, double R2_pose_y, double R2_pose_phi)
371 {
372  // Compute the rotated R2:
373  // ----------------------------------------
374  CVectorDouble xs(4), ys(4);
375  double ccos = cos(R2_pose_phi);
376  double ssin = sin(R2_pose_phi);
377 
378  xs[0] = R2_pose_x + ccos * R2_x_min - ssin * R2_y_min;
379  ys[0] = R2_pose_y + ssin * R2_x_min + ccos * R2_y_min;
380 
381  xs[1] = R2_pose_x + ccos * R2_x_max - ssin * R2_y_min;
382  ys[1] = R2_pose_y + ssin * R2_x_max + ccos * R2_y_min;
383 
384  xs[2] = R2_pose_x + ccos * R2_x_max - ssin * R2_y_max;
385  ys[2] = R2_pose_y + ssin * R2_x_max + ccos * R2_y_max;
386 
387  xs[3] = R2_pose_x + ccos * R2_x_min - ssin * R2_y_max;
388  ys[3] = R2_pose_y + ssin * R2_x_min + ccos * R2_y_max;
389 
390  // Test for one vertice being inside the other rectangle:
391  // -------------------------------------------------------
392  if (R1_x_min <= xs[0] && xs[0] <= R1_x_max && R1_y_min <= ys[0] &&
393  ys[0] <= R1_y_max)
394  return true;
395  if (R1_x_min <= xs[1] && xs[1] <= R1_x_max && R1_y_min <= ys[1] &&
396  ys[1] <= R1_y_max)
397  return true;
398  if (R1_x_min <= xs[2] && xs[2] <= R1_x_max && R1_y_min <= ys[2] &&
399  ys[2] <= R1_y_max)
400  return true;
401  if (R1_x_min <= xs[3] && xs[3] <= R1_x_max && R1_y_min <= ys[3] &&
402  ys[3] <= R1_y_max)
403  return true;
404 
405  CPolygon poly;
406  poly.AddVertex(xs[0], ys[0]);
407  poly.AddVertex(xs[1], ys[1]);
408  poly.AddVertex(xs[2], ys[2]);
409  poly.AddVertex(xs[3], ys[3]);
410 
411  if (poly.PointIntoPolygon(R1_x_min, R1_y_min)) return true;
412  if (poly.PointIntoPolygon(R1_x_max, R1_y_min)) return true;
413  if (poly.PointIntoPolygon(R1_x_max, R1_y_max)) return true;
414  if (poly.PointIntoPolygon(R1_x_min, R1_y_max)) return true;
415 
416  // Test for intersections:
417  // ----------------------------------------
418  double ix, iy;
419 
420  for (int idx = 0; idx < 4; idx++)
421  {
423  R1_x_min, R1_y_min, R1_x_max, R1_y_min, xs[idx], ys[idx],
424  xs[(idx + 1) % 4], ys[(idx + 1) % 4], ix, iy))
425  return true;
427  R1_x_max, R1_y_min, R1_x_max, R1_y_max, xs[idx], ys[idx],
428  xs[(idx + 1) % 4], ys[(idx + 1) % 4], ix, iy))
429  return true;
431  R1_x_max, R1_y_max, R1_x_min, R1_y_max, xs[idx], ys[idx],
432  xs[(idx + 1) % 4], ys[(idx + 1) % 4], ix, iy))
433  return true;
435  R1_x_min, R1_y_max, R1_x_min, R1_y_min, xs[idx], ys[idx],
436  xs[(idx + 1) % 4], ys[(idx + 1) % 4], ix, iy))
437  return true;
438  }
439 
440  // No intersections:
441  return false;
442 }
443 
444 // Auxiliary functions needed to avoid code repetition and unnecesary
445 // recalculations
446 template <class T2D, class U2D, class T3D, class U3D>
448  const T3D& o1, const U3D& o2, const mrpt::math::TPlane& p,
450 {
451  T3D proj1;
452  U3D proj2;
453  // Project into 3D plane, ignoring Z coordinate.
454  TPose3D pose;
455  TPlane(p).getAsPose3D(pose);
456  TPose3D poseNeg = -pose;
457  project3D(o1, poseNeg, proj1);
458  project3D(o2, poseNeg, proj2);
459  T2D proj1_2D;
460  U2D proj2_2D;
461  proj1.generate2DObject(proj1_2D);
462  proj2.generate2DObject(proj2_2D);
463  // Compute easier intersection in 2D space
464  TObject2D obj2D;
465  if (intersect(proj1_2D, proj2_2D, obj2D))
466  {
467  TObject3D tmp;
468  obj2D.generate3DObject(tmp);
469  // Undo projection
470  project3D(tmp, pose, obj);
471  return true;
472  }
473  else
474  return false;
475 }
477  const mrpt::math::TSegment3D& s1, const mrpt::math::TSegment3D& s2,
479 {
480  // Move in a free coordinate, searching for minima and maxima.
481  size_t i1 = 0;
482  while (std::abs(lin.director[i1]) < geometryEpsilon) i1++;
483  TSegment3D s11 = (s1[0][i1] > s1[1][i1]) ? TSegment3D(s1[1], s1[0]) : s1;
484  TSegment3D s21 = (s2[0][i1] > s2[1][i1]) ? TSegment3D(s2[1], s2[0]) : s2;
485  TPoint3D pMin = ((s11[0][i1] < s21[0][i1]) ? s21 : s11)[0];
486  TPoint3D pMax = ((s11[1][i1] < s21[1][i1]) ? s11 : s21)[1];
487  if (std::abs(pMax[i1] - pMin[i1]) < geometryEpsilon)
488  { // Intersection is a point
489  obj = pMax;
490  return true;
491  }
492  else if (pMax[i1] < pMin[i1])
493  return false; // No intersection
494  else
495  {
496  obj = TSegment3D(pMin, pMax); // Intersection is a segment
497  return true;
498  }
499 }
501  const TSegment2D& s1, const TSegment2D& s2, const TLine2D& lin,
502  TObject2D& obj)
503 {
504  // Move in a free coordinate, searching for minima and maxima
505  size_t i1 = (std::abs(lin.coefs[0]) >= geometryEpsilon) ? 1 : 0;
506  TSegment2D s11 = (s1[0][i1] > s1[1][i1]) ? TSegment2D(s1[1], s1[0]) : s1;
507  TSegment2D s21 = (s2[0][i1] > s2[1][i1]) ? TSegment2D(s2[1], s2[0]) : s2;
508  TPoint2D pMin = ((s11[0][i1] < s21[0][i1]) ? s21 : s11)[0];
509  TPoint2D pMax = ((s11[1][i1] < s21[1][i1]) ? s11 : s21)[1];
510  if (std::abs(pMax[i1] - pMin[i1]) < geometryEpsilon)
511  { // Intersection is a point
512  obj = pMax;
513  return true;
514  }
515  else if (pMax[i1] < pMin[i1])
516  return false; // No intersection
517  else
518  {
519  obj = TSegment2D(pMin, pMax); // Intersection is a segment
520  return true;
521  }
522 }
523 inline void unsafeProjectPoint(
524  const TPoint3D& point, const TPose3D& pose, TPoint2D& newPoint)
525 {
526  TPoint3D dummy;
527  pose.composePoint(point, dummy);
528  newPoint.x = dummy.x;
529  newPoint.y = dummy.y;
530 }
532  const TPolygon3D& poly, const TPose3D& pose, TPolygon2D& newPoly)
533 {
534  size_t N = poly.size();
535  newPoly.resize(N);
536  for (size_t i = 0; i < N; i++)
537  unsafeProjectPoint(poly[i], pose, newPoly[i]);
538 }
540  const TPolygonWithPlane& p1, const TLine3D& l2, double& d, double bestKnown)
541 {
542  // LINE MUST BE UNITARY
543  TObject3D obj;
544  TPoint3D p;
545  if (intersect(p1.plane, l2, obj))
546  if (obj.getPoint(p))
547  {
548  for (size_t i = 0; i < 3; i++)
549  if (std::abs(l2.director[i]) > geometryEpsilon)
550  {
551  d = (p[i] - l2.pBase[i]) / l2.director[i];
552  break;
553  }
554  if (d < 0 || d > bestKnown) return false;
555  TPolygon2D newPoly;
556  TPoint2D newP;
557  unsafeProjectPoint(p, p1.inversePose, newP);
559  p1.poly, p1.inversePose, newPoly);
560  return newPoly.contains(newP);
561  }
562  return false;
563 }
565  const TPolygonWithPlane& p1, const TPolygonWithPlane& p2, TObject3D& obj)
566 {
567  if (!intersect(p1.plane, p2.plane, obj)) return false;
568  TLine3D lin3D;
569  TObject3D aux;
570  if (obj.getLine(lin3D))
571  {
572  TLine3D lin3D1, lin3D2;
573  TLine2D lin2D1, lin2D2;
574  TObject2D obj2D1, obj2D2;
575  project3D(lin3D, p1.inversePose, lin3D1);
576  project3D(lin3D, p2.inversePose, lin3D2);
577  lin3D1.generate2DObject(lin2D1);
578  lin3D2.generate2DObject(lin2D2);
579  if (intersect(p1.poly2D, lin2D1, obj2D1) &&
580  intersect(p2.poly2D, lin2D2, obj2D2))
581  {
582  TObject3D obj3D1, obj3D2, obj3Dp1, obj3Dp2;
583  obj2D1.generate3DObject(obj3D1);
584  obj2D2.generate3DObject(obj3D2);
585  project3D(obj3D1, p1.pose, obj3Dp1);
586  project3D(obj3D2, p2.pose, obj3Dp2);
587  TPoint3D po1, po2;
588  TSegment3D s1, s2;
589  if (obj3D1.getPoint(po1))
590  s1 = TSegment3D(po1, po1);
591  else
592  obj3D1.getSegment(s1);
593  if (obj3D2.getPoint(po2))
594  s2 = TSegment3D(po2, po2);
595  else
596  obj3D2.getSegment(s2);
597  return intersectInCommonLine(s1, s2, lin3D, obj);
598  }
599  else
600  return false;
601  }
602  else
603  {
604  TObject2D obj2D;
605  if (intersect(p1.poly2D, p2.poly2D, obj2D))
606  {
607  obj2D.generate3DObject(aux);
608  project3D(aux, p1.pose, obj);
609  return true;
610  }
611  else
612  return false;
613  }
614 }
615 // End of auxiliary methods
616 
617 bool math::intersect(const TSegment3D& s1, const TSegment3D& s2, TObject3D& obj)
618 {
619  TObject3D irr;
620  auto l = TLine3D(s1);
621  if (!intersect(l, TLine3D(s2), irr)) return false;
622  if (irr.isPoint())
623  {
624  // Both lines cross in a point.
625  TPoint3D p;
626  irr.getPoint(p);
627  if (s1.contains(p) && s2.contains(p))
628  {
629  obj = p;
630  return true;
631  }
632  else
633  return false;
634  }
635  else
636  return intersectInCommonLine(s1, s2, l, obj);
637 }
638 
639 bool math::intersect(const TSegment3D& s1, const TPlane& p1, TObject3D& obj)
640 {
641  if (!intersect(TLine3D(s1), p1, obj)) return false;
642  if (obj.isLine())
643  {
644  // Segment is fully inside the plane, so it is the return value.
645  obj = s1;
646  return true;
647  }
648  else
649  {
650  // Segment's line intersects the plane in a point. This may be or not be
651  // part of the segment.
652  TPoint3D p;
653  if (!obj.getPoint(p)) return false;
654  return s1.contains(p);
655  }
656 }
657 
658 bool math::intersect(const TSegment3D& s1, const TLine3D& r1, TObject3D& obj)
659 {
660  if (!intersect(TLine3D(s1), r1, obj)) return false;
661  if (obj.isLine())
662  {
663  // Segment's line is the other line.
664  obj = s1;
665  return true;
666  }
667  else
668  {
669  // Segment's line and the other line cross in a point, which may be or
670  // not be inside the segment.
671  TPoint3D p;
672  if (!obj.getPoint(p)) return false;
673  return s1.contains(p);
674  }
675 }
676 
677 bool math::intersect(const TPlane& p1, const TPlane& p2, TObject3D& obj)
678 {
679  TLine3D lin;
680  crossProduct3D(p1.coefs, p2.coefs, lin.director);
681  if ((std::abs(lin.director[0]) < geometryEpsilon) &&
682  (std::abs(lin.director[1]) < geometryEpsilon) &&
683  (std::abs(lin.director[2]) < geometryEpsilon))
684  {
685  // Planes are parallel
686  for (size_t i = 0; i < 3; i++)
687  if (std::abs(
688  p1.coefs[i] * p2.coefs[3] - p1.coefs[3] * p2.coefs[i]) >=
690  return false;
691  // Planes are the same
692  obj = p1;
693  return true;
694  }
695  else
696  {
697  // Planes cross in a line whose director vector is already calculated
698  // (normal to both planes' normal).
699  // The following process manages to create a random point in the line
700  // without loss of generality and almost without conditional sentences.
701  size_t i1 = 0;
702  while (std::abs(lin.director[i1]) < geometryEpsilon) i1++;
703  // At this point, i1 points to a coordinate (0->x, 1->y, 2->z) in which
704  // we can move freely.
705  // If we arbitrarily assign this coordinate to 0, we'll find a suitable
706  // base point by solving both planes' equations.
707  size_t c1 = (i1 + 1) % 3, c2 = (i1 + 2) % 3;
708  lin.pBase[i1] = 0.0;
709  lin.pBase[c1] =
710  (p2.coefs[3] * p1.coefs[c2] - p1.coefs[3] * p2.coefs[c2]) /
711  lin.director[i1];
712  lin.pBase[c2] =
713  (p2.coefs[c1] * p1.coefs[3] - p1.coefs[c1] * p2.coefs[3]) /
714  lin.director[i1];
715  lin.unitarize();
716  obj = lin;
717  return true;
718  }
719 }
720 
721 bool math::intersect(const TPlane& p1, const TLine3D& r2, TObject3D& obj)
722 {
723  // double
724  // n=p1.coefs[0]*r2.director[0]+p1.coefs[1]*r2.director[1]+p1.coefs[2]*r2.director[2];
725  double n = dotProduct<3, double>(p1.coefs, r2.director);
726  double e = p1.evaluatePoint(r2.pBase);
727  if (std::abs(n) < geometryEpsilon)
728  {
729  // Plane's normal and line's director are orthogonal, so both are
730  // parallel
731  if (std::abs(e) < geometryEpsilon)
732  {
733  // Line is contained in plane.
734  obj = r2;
735  return true;
736  }
737  else
738  return false;
739  }
740  else
741  {
742  // Plane and line cross in a point.
743  double t = e / n;
744  TPoint3D p;
745  p.x = r2.pBase.x - t * r2.director[0];
746  p.y = r2.pBase.y - t * r2.director[1];
747  p.z = r2.pBase.z - t * r2.director[2];
748  obj = p;
749  return true;
750  }
751 }
752 
753 bool math::intersect(const TLine3D& r1, const TLine3D& r2, TObject3D& obj)
754 {
755  double u, d[3];
756  TPoint3D p;
757  const static size_t c1[] = {1, 2, 0};
758  const static size_t c2[] = {2, 0, 1};
759  // With indirect memory accesses, almost all the code goes in a single loop.
760  for (size_t i = 0; i < 3; i++)
761  {
762  double sysDet = -r1.director[c1[i]] * r2.director[c2[i]] +
763  r2.director[c1[i]] * r1.director[c2[i]];
764  if (std::abs(sysDet) < geometryEpsilon) continue;
765  // We've found a coordinate in which we can solve the associated system
766  d[c1[i]] = r2.pBase[c1[i]] - r1.pBase[c1[i]];
767  d[c2[i]] = r2.pBase[c2[i]] - r1.pBase[c2[i]];
768  u = (r1.director[c1[i]] * d[c2[i]] - r1.director[c2[i]] * d[c1[i]]) /
769  sysDet;
770  for (size_t k = 0; k < 3; k++) p[k] = r2.pBase[k] + u * r2.director[k];
771  if (r1.contains(p))
772  {
773  obj = p;
774  return true;
775  }
776  else
777  return false;
778  }
779  // Lines are parallel
780  if (r1.contains(r2.pBase))
781  {
782  // Lines are the same
783  obj = r1;
784  return true;
785  }
786  else
787  return false;
788 }
789 
790 bool math::intersect(const TLine2D& r1, const TLine2D& r2, TObject2D& obj)
791 {
792  double sysDet = r1.coefs[0] * r2.coefs[1] - r1.coefs[1] * r2.coefs[0];
793  if (std::abs(sysDet) >= geometryEpsilon)
794  {
795  // Resulting point comes simply from solving an equation.
796  TPoint2D p;
797  p.x = (r1.coefs[1] * r2.coefs[2] - r1.coefs[2] * r2.coefs[1]) / sysDet;
798  p.y = (r1.coefs[2] * r2.coefs[0] - r1.coefs[0] * r2.coefs[2]) / sysDet;
799  obj = p;
800  return true;
801  }
802  else
803  {
804  // Lines are parallel
805  if (std::abs(r1.coefs[0] * r2.coefs[2] - r1.coefs[2] * r2.coefs[0]) >=
806  geometryEpsilon ||
807  std::abs(r1.coefs[1] * r2.coefs[2] - r1.coefs[2] * r2.coefs[1]) >=
809  return false;
810 
811  // Lines are the same
812  obj = r1;
813  return true;
814  }
815 }
816 
817 bool math::intersect(const TLine2D& r1, const TSegment2D& s2, TObject2D& obj)
818 {
819  if (!intersect(r1, TLine2D(s2), obj)) return false;
820  TPoint2D p;
821  if (obj.isLine())
822  {
823  // Segment is inside the line
824  obj = s2;
825  return true;
826  }
827  else if (obj.getPoint(p))
828  return s2.contains(p); // Both lines cross in a point.
829  return false;
830 }
831 
832 bool math::intersect(const TSegment2D& s1, const TSegment2D& s2, TObject2D& obj)
833 {
834  auto lin = TLine2D(s1);
835  if (!intersect(lin, TLine2D(s2), obj)) return false;
836  TPoint2D p;
837  if (obj.isLine())
838  return intersectInCommonLine(
839  s1, s2, lin, obj); // Segments' lines are parallel
840  else if (obj.getPoint(p))
841  return s1.contains(p) &&
842  s2.contains(p); // Segments' lines cross in a point
843  return false;
844 }
845 
846 double math::getAngle(const TPlane& s1, const TPlane& s2)
847 {
848  double c = 0, n1 = 0, n2 = 0;
849  for (size_t i = 0; i < 3; i++)
850  {
851  c += s1.coefs[i] * s2.coefs[i];
852  n1 += s1.coefs[i] * s1.coefs[i];
853  n2 += s2.coefs[i] + s2.coefs[i];
854  }
855  double s = sqrt(n1 * n2);
856  if (s < geometryEpsilon) throw std::logic_error("Invalid plane(s)");
857  if (std::abs(s) < std::abs(c))
858  return (c / s < 0) ? M_PI : 0;
859  else
860  return acos(c / s);
861 }
862 
863 double math::getAngle(const TPlane& s1, const TLine3D& r2)
864 {
865  double c = 0, n1 = 0, n2 = 0;
866  for (size_t i = 0; i < 3; i++)
867  {
868  c += s1.coefs[i] * r2.director[i];
869  n1 += s1.coefs[i] * s1.coefs[i];
870  n2 += r2.director[i] * r2.director[i];
871  }
872  double s = sqrt(n1 * n2);
873  if (s < geometryEpsilon) throw std::logic_error("Invalid plane or line");
874  if (std::abs(s) < std::abs(c))
875  return M_PI * sign(c / s) / 2;
876  else
877  return asin(c / s);
878 }
879 
880 double math::getAngle(const TLine3D& r1, const TLine3D& r2)
881 {
882  double c = 0, n1 = 0, n2 = 0;
883  for (size_t i = 0; i < 3; i++)
884  {
885  c += r1.director[i] * r2.director[i];
886  n1 += r1.director[i] * r1.director[i];
887  n2 += r2.director[i] * r2.director[i];
888  }
889  double s = sqrt(n1 * n2);
890  if (s < geometryEpsilon) throw std::logic_error("Invalid line(s)");
891  if (std::abs(s) < std::abs(c))
892  return (c / s < 0) ? M_PI : 0;
893  else
894  return acos(c / s);
895 }
896 
897 double math::getAngle(const TLine2D& r1, const TLine2D& r2)
898 {
899  const double ang1 = std::atan2(-r1.coefs[0], r1.coefs[1]);
900  const double ang2 = std::atan2(-r2.coefs[0], r2.coefs[1]);
901  return mrpt::math::wrapToPi(ang2 - ang1);
902 }
903 
904 // Auxiliary method
905 void createFromPoseAndAxis(const TPose3D& p, TLine3D& r, size_t axis)
906 {
907  CMatrixDouble44 m;
909  for (size_t i = 0; i < 3; i++)
910  {
911  r.pBase[i] = m(i, 3);
912  r.director[i] = m(i, axis);
913  }
914 }
915 // End of auxiliary method
916 
918 {
919  createFromPoseAndAxis(p, r, 0);
920 }
921 
923 {
924  createFromPoseAndAxis(p, r, 1);
925 }
926 
928 {
929  createFromPoseAndAxis(p, r, 2);
930 }
931 
933  const TPose3D& p, const double (&vector)[3], TLine3D& r)
934 {
935  CMatrixDouble44 m;
937  for (size_t i = 0; i < 3; i++)
938  {
939  r.pBase[i] = m(i, 3);
940  r.director[i] = 0;
941  for (size_t j = 0; j < 3; j++) r.director[i] += m(i, j) * vector[j];
942  }
943 }
944 
946 {
947  r.coefs[0] = cos(p.phi);
948  r.coefs[1] = -sin(p.phi);
949  r.coefs[2] = -r.coefs[0] * p.x - r.coefs[1] * p.y;
950 }
951 
953 {
954  r.coefs[0] = sin(p.phi);
955  r.coefs[1] = cos(p.phi);
956  r.coefs[2] = -r.coefs[0] * p.x - r.coefs[1] * p.y;
957 }
958 
960  const TPose2D& p, const double (&vector)[2], TLine2D& r)
961 {
962  double c = cos(p.phi);
963  double s = sin(p.phi);
964  r.coefs[0] = vector[0] * c + vector[1] * s;
965  r.coefs[1] = -vector[0] * s + vector[1] * c;
966  r.coefs[2] = -r.coefs[0] * p.x - r.coefs[1] * p.y;
967 }
968 
969 bool math::conformAPlane(const std::vector<TPoint3D>& points)
970 {
971  size_t N = points.size();
972  if (N < 3) return false;
973  CMatrixDouble mat(N - 1, 3);
974  const TPoint3D& orig = points[N - 1];
975  for (size_t i = 0; i < N - 1; i++)
976  {
977  const TPoint3D& p = points[i];
978  mat(i, 0) = p.x - orig.x;
979  mat(i, 1) = p.y - orig.y;
980  mat(i, 2) = p.z - orig.z;
981  }
982  return mat.rank(geometryEpsilon) == 2;
983 }
984 
985 bool math::conformAPlane(const std::vector<TPoint3D>& points, TPlane& p)
986 {
987  return std::abs(getRegressionPlane(points, p)) < geometryEpsilon;
988 }
989 
990 bool math::areAligned(const std::vector<TPoint2D>& points)
991 {
992  size_t N = points.size();
993  if (N < 2) return false;
994  CMatrixDouble mat(N - 1, 2);
995  const TPoint2D& orig = points[N - 1];
996  for (size_t i = 0; i < N - 1; i++)
997  {
998  const TPoint2D& p = points[i];
999  mat(i, 0) = p.x - orig.x;
1000  mat(i, 1) = p.y - orig.y;
1001  }
1002  return mat.rank(geometryEpsilon) == 1;
1003 }
1004 
1005 bool math::areAligned(const std::vector<TPoint2D>& points, TLine2D& r)
1006 {
1007  if (!areAligned(points)) return false;
1008  const TPoint2D& p0 = points[0];
1009  for (size_t i = 1;; i++)
1010  {
1011  try
1012  {
1013  r = TLine2D(p0, points[i]);
1014  return true;
1015  }
1016  catch (logic_error&)
1017  {
1018  }
1019  }
1020 }
1021 
1022 bool math::areAligned(const std::vector<TPoint3D>& points)
1023 {
1024  size_t N = points.size();
1025  if (N < 2) return false;
1026  CMatrixDouble mat(N - 1, 3);
1027  const TPoint3D& orig = points[N - 1];
1028  for (size_t i = 0; i < N - 1; i++)
1029  {
1030  const TPoint3D& p = points[i];
1031  mat(i, 0) = p.x - orig.x;
1032  mat(i, 1) = p.y - orig.y;
1033  mat(i, 2) = p.z - orig.z;
1034  }
1035  return mat.rank(geometryEpsilon) == 1;
1036 }
1037 
1038 bool math::areAligned(const std::vector<TPoint3D>& points, TLine3D& r)
1039 {
1040  if (!areAligned(points)) return false;
1041  const TPoint3D& p0 = points[0];
1042  for (size_t i = 1;; i++) try
1043  {
1044  r = TLine3D(p0, points[i]);
1045  return true;
1046  }
1047  catch (logic_error&)
1048  {
1049  }
1050 }
1051 
1053  const TLine3D& line, const TPose3D& newXYpose, TLine3D& newLine)
1054 {
1055  newXYpose.composePoint(line.pBase, newLine.pBase);
1056  CMatrixDouble44 mat;
1057  newXYpose.getHomogeneousMatrix(mat);
1058  for (size_t i = 0; i < 3; i++)
1059  {
1060  newLine.director[i] = 0;
1061  for (size_t j = 0; j < 3; j++)
1062  newLine.director[i] += mat(i, j) * line.director[j];
1063  }
1064  newLine.unitarize();
1065 }
1066 
1068  const TPlane& plane, const TPose3D& newXYpose, TPlane& newPlane)
1069 {
1070  CMatrixDouble44 mat;
1071  newXYpose.getHomogeneousMatrix(mat);
1072  for (size_t i = 0; i < 3; i++)
1073  {
1074  newPlane.coefs[i] = 0;
1075  for (size_t j = 0; j < 3; j++)
1076  newPlane.coefs[i] += mat(i, j) * plane.coefs[j];
1077  }
1078  // VORSICHT! NO INTENTEN HACER ESTO EN SUS CASAS (nota: comentar sĆ­ o sĆ­,
1079  // mĆ”s tarde)
1080  // La idea es mantener la distancia al nuevo origen igual a la distancia del
1081  // punto original antes de proyectar.
1082  // newPlane.coefs[3]=plane.evaluatePoint(TPoint3D(TPose3D(0,0,0,0,0,0)-newXYpose))*sqrt((newPlane.coefs[0]*newPlane.coefs[0]+newPlane.coefs[1]*newPlane.coefs[1]+newPlane.coefs[2]*newPlane.coefs[2])/(plane.coefs[0]*plane.coefs[0]+plane.coefs[1]*plane.coefs[1]+plane.coefs[2]*plane.coefs[2]));
1083  CMatrixDouble44 HMinv;
1084  newXYpose.getInverseHomogeneousMatrix(HMinv);
1085  newPlane.coefs[3] =
1086  plane.evaluatePoint(TPoint3D(HMinv(0, 3), HMinv(1, 3), HMinv(2, 3))) *
1087  sqrt(
1088  squareNorm<3, double>(newPlane.coefs) /
1089  squareNorm<3, double>(plane.coefs));
1090  newPlane.unitarize();
1091 }
1092 
1094  const TPolygon3D& polygon, const TPose3D& newXYpose, TPolygon3D& newPolygon)
1095 {
1096  size_t N = polygon.size();
1097  newPolygon.resize(N);
1098  for (size_t i = 0; i < N; i++)
1099  project3D(polygon[i], newXYpose, newPolygon[i]);
1100 }
1101 
1103  const TObject3D& object, const TPose3D& newXYpose, TObject3D& newObject)
1104 {
1105  switch (object.getType())
1106  {
1107  case GEOMETRIC_TYPE_POINT:
1108  {
1109  TPoint3D p, p2;
1110  object.getPoint(p);
1111  project3D(p, newXYpose, p2);
1112  newObject = p2;
1113  break;
1114  }
1116  {
1117  TSegment3D p, p2;
1118  object.getSegment(p);
1119  project3D(p, newXYpose, p2);
1120  newObject = p2;
1121  break;
1122  }
1123  case GEOMETRIC_TYPE_LINE:
1124  {
1125  TLine3D p, p2;
1126  object.getLine(p);
1127  project3D(p, newXYpose, p2);
1128  newObject = p2;
1129  break;
1130  }
1131  case GEOMETRIC_TYPE_PLANE:
1132  {
1133  TPlane p, p2;
1134  object.getPlane(p);
1135  project3D(p, newXYpose, p2);
1136  newObject = p2;
1137  break;
1138  }
1140  {
1141  TPolygon3D p, p2;
1142  object.getPolygon(p);
1143  project3D(p, newXYpose, p2);
1144  newObject = p2;
1145  break;
1146  }
1147  default:
1148  newObject = TObject3D();
1149  }
1150 }
1151 
1153  const TPoint2D& point, const TPose2D& newXpose, TPoint2D& newPoint)
1154 {
1155  newPoint = newXpose.composePoint(point);
1156 }
1157 
1159  const TLine2D& line, const TPose2D& newXpose, TLine2D& newLine)
1160 {
1161  double c = cos(newXpose.phi);
1162  double s = sin(newXpose.phi);
1163  newLine.coefs[0] = line.coefs[0] * c - line.coefs[1] * s;
1164  newLine.coefs[1] = line.coefs[1] * c + line.coefs[0] * s;
1165  newLine.coefs[2] = line.coefs[2] - (newLine.coefs[0] * newXpose.x +
1166  newLine.coefs[1] * newXpose.y);
1167  return;
1168 }
1169 
1171  const TPolygon2D& line, const TPose2D& newXpose, TPolygon2D& newLine)
1172 {
1173  size_t N = line.size();
1174  newLine.resize(N);
1175  for (size_t i = 0; i < N; i++) newLine[i] = newXpose + line[i];
1176  return;
1177 }
1178 
1180  const TObject2D& obj, const TPose2D& newXpose, TObject2D& newObject)
1181 {
1182  switch (obj.getType())
1183  {
1184  case GEOMETRIC_TYPE_POINT:
1185  {
1186  TPoint2D p, p2;
1187  obj.getPoint(p);
1188  project2D(p, newXpose, p2);
1189  newObject = p2;
1190  break;
1191  }
1193  {
1194  TSegment2D p, p2;
1195  obj.getSegment(p);
1196  project2D(p, newXpose, p2);
1197  newObject = p2;
1198  break;
1199  }
1200  case GEOMETRIC_TYPE_LINE:
1201  {
1202  TLine2D p, p2;
1203  obj.getLine(p);
1204  project2D(p, newXpose, p2);
1205  newObject = p2;
1206  break;
1207  }
1209  {
1210  TPolygon2D p, p2;
1211  obj.getPolygon(p);
1212  project2D(p, newXpose, p2);
1213  newObject = p2;
1214  break;
1215  }
1216  default:
1217  newObject = TObject2D();
1218  }
1219 }
1220 
1221 bool math::intersect(const TPolygon2D& p1, const TSegment2D& s2, TObject2D& obj)
1222 {
1223  auto l2 = TLine2D(s2);
1224  if (!intersect(p1, l2, obj)) return false;
1225  TPoint2D p;
1226  TSegment2D s;
1227  if (obj.getPoint(p))
1228  return s2.contains(p);
1229  else if (obj.getSegment(s))
1230  return intersectInCommonLine(s, s2, l2, obj);
1231  return false;
1232 }
1233 
1234 bool math::intersect(const TPolygon2D& p1, const TLine2D& r2, TObject2D& obj)
1235 {
1236  // Proceeding: project polygon so that the line happens to be y=0 (phi=0).
1237  // Then, search this new polygons for intersections with the X axis (very
1238  // simple).
1239  if (p1.size() < 3) return false;
1240  TPose2D pose, poseNeg;
1241  r2.getAsPose2D(pose);
1242  poseNeg = TPose2D(0, 0, 0) - pose;
1243  TPolygon2D projPoly;
1244  project2D(p1, poseNeg, projPoly);
1245  size_t N = projPoly.size();
1246  projPoly.push_back(projPoly[0]);
1247  double pre = projPoly[0].y;
1248  vector<TPoint2D> pnts;
1249  pnts.reserve(2);
1250  for (size_t i = 1; i <= N; i++)
1251  {
1252  double cur = projPoly[i].y;
1253  if (std::abs(cur) < geometryEpsilon)
1254  {
1255  if (std::abs(pre) < geometryEpsilon)
1256  {
1257  pnts.resize(2);
1258  pnts[0] = projPoly[i - 1];
1259  pnts[1] = projPoly[i];
1260  break;
1261  }
1262  else
1263  pnts.push_back(projPoly[i]);
1264  }
1265  else if ((std::abs(pre) >= geometryEpsilon) && (sign(cur) != sign(pre)))
1266  {
1267  double a = projPoly[i - 1].x;
1268  double c = projPoly[i].x;
1269  double x = a - pre * (c - a) / (cur - pre);
1270  pnts.emplace_back(x, 0);
1271  }
1272  pre = cur;
1273  }
1274  // All results must undo the initial projection
1275  switch (pnts.size())
1276  {
1277  case 0:
1278  return false;
1279  case 1:
1280  {
1281  TPoint2D p;
1282  project2D(pnts[0], pose, p);
1283  obj = p;
1284  return true;
1285  }
1286  case 2:
1287  {
1288  TSegment2D s;
1289  project2D(TSegment2D(pnts[0], pnts[1]), pose, s);
1290  obj = s;
1291  return true;
1292  }
1293  default:
1294  throw std::logic_error("Polygon is not convex");
1295  }
1296 }
1297 
1298 // Auxiliary structs and code for 2D polygon intersection
1300 {
1301  vector<TSegment2D> l1;
1302  vector<TSegment2D> l2;
1303 };
1304 // TODO: Replace by std::variant
1306 {
1307  unsigned char type; // 0 -> point, 1-> segment, any other-> empty
1308  union {
1309  TPoint2D* point = nullptr;
1311  } data;
1312  void destroy()
1313  {
1314  switch (type)
1315  {
1316  case 0:
1317  delete data.point;
1318  break;
1319  case 1:
1320  delete data.segment;
1321  break;
1322  }
1323  type = 255;
1324  }
1325  TCommonRegion(const TPoint2D& p) : type(0) { data.point = new TPoint2D(p); }
1326  TCommonRegion(const TSegment2D& s) : type(1)
1327  {
1328  data.segment = new TSegment2D(s);
1329  }
1330  ~TCommonRegion() { destroy(); }
1332  {
1333  if (&r == this) return *this;
1334  destroy();
1335  switch (type = r.type)
1336  {
1337  case 0:
1338  data.point = new TPoint2D(*(r.data.point));
1339  break;
1340  case 1:
1341  data.segment = new TSegment2D(*(r.data.segment));
1342  break;
1343  }
1344  return *this;
1345  }
1346  TCommonRegion(const TCommonRegion& r) : type(0) { operator=(r); }
1347 };
1348 // TODO: Replace by std::variant
1350 {
1351  unsigned char type; // 0->two lists of segments, 1-> common region
1352  union {
1353  T2ListsOfSegments* segms = nullptr;
1355  } data;
1356  void destroy()
1357  {
1358  switch (type)
1359  {
1360  case 0:
1361  delete data.segms;
1362  break;
1363  case 1:
1364  delete data.common;
1365  break;
1366  }
1367  type = 255;
1368  };
1369  TTempIntersection(const T2ListsOfSegments& segms) : type(0)
1370  {
1371  data.segms = new T2ListsOfSegments(segms);
1372  }
1373  TTempIntersection(const TCommonRegion& common) : type(1)
1374  {
1375  data.common = new TCommonRegion(common);
1376  }
1377  ~TTempIntersection() { destroy(); }
1379  {
1380  if (&t == this) return *this;
1381  destroy();
1382  switch (type = t.type)
1383  {
1384  case 0:
1385  data.segms = new T2ListsOfSegments(*(t.data.segms));
1386  break;
1387  case 1:
1388  data.common = new TCommonRegion(*(t.data.common));
1389  break;
1390  }
1391  return *this;
1392  }
1393  TTempIntersection(const TTempIntersection& t) : type(0) { operator=(t); }
1394 };
1396 {
1399  explicit TSegmentWithLine(const TSegment2D& s) : segment(s)
1400  {
1401  line = TLine2D(s[0], s[1]);
1402  }
1403  TSegmentWithLine(const TPoint2D& p1, const TPoint2D& p2) : segment(p1, p2)
1404  {
1405  line = TLine2D(p1, p2);
1406  }
1407  TSegmentWithLine() = default;
1408 };
1410  const TSegmentWithLine& s1, const TSegmentWithLine& s2, TObject2D& obj)
1411 {
1412  if (!intersect(s1.line, s2.line, obj)) return false;
1413  if (obj.isLine())
1414  return intersectInCommonLine(s1.segment, s2.segment, s1.line, obj);
1415  TPoint2D p;
1416  obj.getPoint(p);
1417  return s1.segment.contains(p) && s2.segment.contains(p);
1418 }
1419 void getSegmentsWithLine(const TPolygon2D& poly, vector<TSegmentWithLine>& segs)
1420 {
1421  size_t N = poly.size();
1422  segs.resize(N);
1423  for (size_t i = 0; i < N - 1; i++)
1424  segs[i] = TSegmentWithLine(poly[i], poly[i + 1]);
1425  segs[N - 1] = TSegmentWithLine(poly[N - 1], poly[0]);
1426 }
1427 
1428 inline char fromObject(const TObject2D& obj)
1429 {
1430  switch (obj.getType())
1431  {
1432  case GEOMETRIC_TYPE_POINT:
1433  return 'P';
1435  return 'S';
1436  case GEOMETRIC_TYPE_LINE:
1437  return 'L';
1439  return 'O';
1440  default:
1441  return 'U';
1442  }
1443 }
1444 
1446  const TPolygon2D& /*p1*/, const TPolygon2D& /*p2*/, TObject2D& /*obj*/)
1447 {
1448  THROW_EXCEPTION("TODO");
1449 #if 0
1450  return false; //TODO
1451 
1452  CSparseMatrixTemplate<TObject2D> intersections=CSparseMatrixTemplate<TObject2D>(p1.size(),p2.size());
1453  std::vector<TSegmentWithLine> segs1,segs2;
1454  getSegmentsWithLine(p1,segs1);
1455  getSegmentsWithLine(p2,segs2);
1456  unsigned int hmInters=0;
1457  for (size_t i=0;i<segs1.size();i++) {
1458  const TSegmentWithLine &s1=segs1[i];
1459  for (size_t j=0;j<segs2.size();j++) if (intersect(s1,segs2[j],obj)) {
1460  intersections(i,j)=obj;
1461  hmInters++;
1462  }
1463  }
1464  for (size_t i=0;i<intersections.rows();i++) {
1465  for (size_t j=0;j<intersections.cols();j++) cout<<fromObject(intersections(i,j));
1466  cout<<'\n';
1467  }
1468  if (hmInters==0) {
1469  if (p1.contains(p2[0])) {
1470  obj=p2;
1471  return true;
1472  } else if (p2.contains(p1[0])) {
1473  obj=p1;
1474  return true;
1475  } else return false;
1476  }
1477  //ESTO ES UNA PESADILLA, HAY CIEN MILLONES DE CASOS DISTINTOS A LA HORA DE RECORRER LAS POSIBILIDADES...
1478  /*
1479  Dividir cada segmento en sus distintas partes segĆŗn sus intersecciones, y generar un nuevo polĆ­gono.
1480  Recorrer de segmento en segmento, por cada uno de los dos lados (recorriendo desde un punto comĆŗn a otro;
1481  en un polĆ­gono se escoge el camino secuencial directo, mientras que del otro se escoge, de los dos posibles,
1482  el que no se corta con ningĆŗn elemento del primero).
1483  Seleccionar, para cada segmento, si estĆ” dentro o fuera.
1484  Parece fĆ”cil, pero es una puta mierda.
1485  TODO: hacer en algĆŗn momento de mucho tiempo libre...
1486  */
1487 
1488  /* ĀæSeguir? */
1489  return false;
1490 #endif
1491 }
1492 
1493 bool math::intersect(const TPolygon3D& p1, const TSegment3D& s2, TObject3D& obj)
1494 {
1495  TPlane p;
1496  if (!p1.getPlane(p)) return false;
1497  if (!intersect(p, s2, obj)) return false;
1498  TPoint3D pnt;
1499  TSegment3D sgm;
1500  if (obj.getPoint(pnt))
1501  {
1502  TPose3D pose;
1503  p.getAsPose3DForcingOrigin(p1[0], pose);
1504  CMatrixDouble44 HMinv;
1505  pose.getInverseHomogeneousMatrix(HMinv);
1506  TPose3D poseNeg;
1507  poseNeg.fromHomogeneousMatrix(HMinv);
1508  TPolygon3D projPoly;
1509  TPoint3D projPnt;
1510  project3D(p1, poseNeg, projPoly);
1511  project3D(pnt, poseNeg, projPnt);
1512  return TPolygon2D(projPoly).contains(TPoint2D(projPnt));
1513  }
1514  else if (obj.getSegment(sgm))
1515  return intersectInCommonPlane<TPolygon2D, TSegment2D>(p1, s2, p, obj);
1516  return false;
1517 }
1518 
1519 bool math::intersect(const TPolygon3D& p1, const TLine3D& r2, TObject3D& obj)
1520 {
1521  TPlane p;
1522  if (!p1.getPlane(p)) return false;
1523  if (!intersect(p, r2, obj)) return false;
1524  TPoint3D pnt;
1525  if (obj.getPoint(pnt))
1526  {
1527  TPose3D pose;
1528  p.getAsPose3DForcingOrigin(p1[0], pose);
1529  CMatrixDouble44 HMinv;
1530  pose.getInverseHomogeneousMatrix(HMinv);
1531  TPose3D poseNeg;
1532  poseNeg.fromHomogeneousMatrix(HMinv);
1533  TPolygon3D projPoly;
1534  TPoint3D projPnt;
1535  project3D(p1, poseNeg, projPoly);
1536  project3D(pnt, poseNeg, projPnt);
1537  return TPolygon2D(projPoly).contains(TPoint2D(projPnt));
1538  }
1539  else if (obj.isLine())
1540  return intersectInCommonPlane<TPolygon2D, TLine2D>(p1, r2, p, obj);
1541  return false;
1542 }
1543 
1544 bool math::intersect(const TPolygon3D& p1, const TPlane& p2, TObject3D& obj)
1545 {
1546  TPlane p;
1547  if (!p1.getPlane(p)) return false;
1548  if (!intersect(p, p2, obj)) return false;
1549  TLine3D ln;
1550  if (obj.isPlane())
1551  {
1552  // Polygon is inside the plane
1553  obj = p1;
1554  return true;
1555  }
1556  else if (obj.getLine(ln))
1557  return intersectInCommonPlane<TPolygon2D, TLine2D>(p1, ln, p, obj);
1558  return false;
1559 }
1560 
1561 // Auxiliary function2
1563  const TPolygon3D& p1, const TPlane& pl1, const TPolygon3D& p2,
1564  const TPlane& pl2, TObject3D& obj)
1565 {
1566  if (!intersect(pl1, pl2, obj)) return false;
1567  TLine3D ln;
1568  if (obj.isPlane())
1569  return intersectInCommonPlane<TPolygon2D, TPolygon2D>(
1570  p1, p2, pl1, obj); // Polygons are on the same plane
1571  else if (obj.getLine(ln))
1572  {
1573  TObject3D obj1, obj2;
1574  if (!intersectInCommonPlane<TPolygon2D, TLine2D>(p1, ln, pl1, obj1))
1575  return false;
1576  if (!intersectInCommonPlane<TPolygon2D, TLine2D>(p2, ln, pl2, obj2))
1577  return false;
1578  TPoint3D po1, po2;
1579  TSegment3D s1, s2;
1580  if (obj1.getPoint(po1))
1581  s1 = TSegment3D(po1, po1);
1582  else
1583  obj1.getSegment(s1);
1584  if (obj2.getPoint(po2))
1585  s2 = TSegment3D(po2, po2);
1586  else
1587  obj2.getSegment(s2);
1588  return intersectInCommonLine(s1, s2, ln, obj);
1589  }
1590  return false;
1591 }
1592 
1594  const TPoint3D& min1, const TPoint3D& max1, const TPoint3D& min2,
1595  const TPoint3D& max2)
1596 {
1597  for (size_t i = 0; i < 3; i++)
1598  if ((min1[i] > max2[i]) || (min2[i] > max1[i])) return false;
1599  return true;
1600 }
1601 // End of auxiliary functions
1602 
1603 bool math::intersect(const TPolygon3D& p1, const TPolygon3D& p2, TObject3D& obj)
1604 {
1605  TPoint3D min1, max1, min2, max2;
1606  getPrismBounds(p1, min1, max1);
1607  getPrismBounds(p2, min2, max2);
1608  if (!compatibleBounds(min1, max1, min2, max2)) return false;
1609  TPlane pl1, pl2;
1610  if (!p1.getPlane(pl1)) return false;
1611  if (!p2.getPlane(pl2)) return false;
1612  return intersectAux(p1, pl1, p2, pl2, obj);
1613 }
1614 
1615 // Auxiliary function
1616 inline void getPlanes(
1617  const std::vector<TPolygon3D>& polys, std::vector<TPlane>& planes)
1618 {
1619  size_t N = polys.size();
1620  planes.resize(N);
1621  for (size_t i = 0; i < N; i++) getRegressionPlane(polys[i], planes[i]);
1622 }
1623 
1624 // Auxiliary functions
1626  const std::vector<TPolygon3D>& v1, std::vector<TPoint3D>& minP,
1627  std::vector<TPoint3D>& maxP)
1628 {
1629  minP.resize(0);
1630  maxP.resize(0);
1631  size_t N = v1.size();
1632  minP.reserve(N);
1633  maxP.reserve(N);
1634  TPoint3D p1, p2;
1635  for (const auto& it : v1)
1636  {
1637  getPrismBounds(it, p1, p2);
1638  minP.push_back(p1);
1639  maxP.push_back(p2);
1640  }
1641 }
1642 
1644  const std::vector<TPolygon3D>& v1, const std::vector<TPolygon3D>& v2,
1646 {
1647  std::vector<TPlane> w1, w2;
1648  getPlanes(v1, w1);
1649  getPlanes(v2, w2);
1650  std::vector<TPoint3D> minBounds1, maxBounds1, minBounds2, maxBounds2;
1651  getMinAndMaxBounds(v1, minBounds1, maxBounds1);
1652  getMinAndMaxBounds(v2, minBounds2, maxBounds2);
1653  size_t M = v1.size(), N = v2.size();
1654  objs.clear();
1655  objs.resize(M, N);
1656  TObject3D obj;
1657  for (size_t i = 0; i < M; i++)
1658  for (size_t j = 0; j < N; j++)
1659  if (!compatibleBounds(
1660  minBounds1[i], maxBounds1[i], minBounds2[j], maxBounds2[j]))
1661  continue;
1662  else if (intersectAux(v1[i], w1[i], v2[j], w2[j], obj))
1663  objs(i, j) = obj;
1664  return objs.getNonNullElements();
1665 }
1666 
1668  const std::vector<TPolygon3D>& v1, const std::vector<TPolygon3D>& v2,
1669  std::vector<TObject3D>& objs)
1670 {
1671  objs.resize(0);
1672  std::vector<TPlane> w1, w2;
1673  getPlanes(v1, w1);
1674  getPlanes(v2, w2);
1675  std::vector<TPoint3D> minBounds1, maxBounds1, minBounds2, maxBounds2;
1676  getMinAndMaxBounds(v1, minBounds1, maxBounds1);
1677  getMinAndMaxBounds(v2, minBounds2, maxBounds2);
1678  TObject3D obj;
1679  auto itP1 = w1.begin();
1680  auto itMin1 = minBounds1.begin();
1681  auto itMax1 = maxBounds1.begin();
1682  for (auto it1 = v1.begin(); it1 != v1.end();
1683  ++it1, ++itP1, ++itMin1, ++itMax1)
1684  {
1685  const TPolygon3D& poly1 = *it1;
1686  const TPlane& plane1 = *itP1;
1687  auto itP2 = w2.begin();
1688  const TPoint3D &min1 = *itMin1, max1 = *itMax1;
1689  auto itMin2 = minBounds2.begin();
1690  auto itMax2 = maxBounds2.begin();
1691  for (auto it2 = v2.begin(); it2 != v2.end();
1692  ++it2, ++itP2, ++itMin2, ++itMax2)
1693  if (!compatibleBounds(min1, max1, *itMin2, *itMax2))
1694  continue;
1695  else if (intersectAux(poly1, plane1, *it2, *itP2, obj))
1696  objs.push_back(obj);
1697  }
1698  return objs.size();
1699 }
1700 
1701 bool math::intersect(const TObject2D& o1, const TObject2D& o2, TObject2D& obj)
1702 {
1703  TPoint2D p1, p2;
1704  TSegment2D s1, s2;
1705  TLine2D l1, l2;
1706  TPolygon2D po1, po2;
1707  if (o1.getPoint(p1))
1708  {
1709  obj = p1;
1710  if (o2.getPoint(p2))
1711  return distance(p1, p2) < geometryEpsilon;
1712  else if (o2.getSegment(s2))
1713  return s2.contains(p1);
1714  else if (o2.getLine(l2))
1715  return l2.contains(p1);
1716  else if (o2.getPolygon(po2))
1717  return po2.contains(p1); // else return false;
1718  }
1719  else if (o1.getSegment(s1))
1720  {
1721  if (o2.getPoint(p2))
1722  {
1723  if (s1.contains(p2))
1724  {
1725  obj = p2;
1726  return true;
1727  } // else return false;
1728  }
1729  else if (o2.getSegment(s2))
1730  return intersect(s1, s2, obj);
1731  else if (o2.getLine(l2))
1732  return intersect(s1, l2, obj);
1733  else if (o2.getPolygon(po2))
1734  return intersect(s1, po2, obj); // else return false;
1735  }
1736  else if (o1.getLine(l1))
1737  {
1738  if (o2.getPoint(p2))
1739  {
1740  if (l1.contains(p2))
1741  {
1742  obj = p2;
1743  return true;
1744  } // else return false;
1745  }
1746  else if (o2.getSegment(s2))
1747  return intersect(l1, s2, obj);
1748  else if (o2.getLine(l2))
1749  return intersect(l1, l2, obj);
1750  else if (o2.getPolygon(po2))
1751  return intersect(l1, po2, obj); // else return false;
1752  }
1753  else if (o1.getPolygon(po1))
1754  {
1755  if (o2.getPoint(p2))
1756  {
1757  if (po1.contains(p2))
1758  {
1759  obj = p2;
1760  return true;
1761  } // else return false;
1762  }
1763  else if (o2.getSegment(s2))
1764  return intersect(po1, s2, obj);
1765  else if (o2.getLine(l2))
1766  return intersect(po1, l2, obj);
1767  else if (o2.getPolygon(po2))
1768  return intersect(po1, po2, obj); // else return false;
1769  } // else return false;
1770  return false;
1771 }
1772 
1773 bool math::intersect(const TObject3D& o1, const TObject3D& o2, TObject3D& obj)
1774 {
1775  TPoint3D p1, p2;
1776  TSegment3D s1, s2;
1777  TLine3D l1, l2;
1778  TPolygon3D po1, po2;
1779  TPlane pl1, pl2;
1780  if (o1.getPoint(p1))
1781  {
1782  obj = p1;
1783  if (o2.getPoint(p2))
1784  return distance(p1, p2) < geometryEpsilon;
1785  else if (o2.getSegment(s2))
1786  return s2.contains(p1);
1787  else if (o2.getLine(l2))
1788  return l2.contains(p1);
1789  else if (o2.getPolygon(po2))
1790  return po2.contains(p1);
1791  else if (o2.getPlane(pl2))
1792  return pl2.contains(p1); // else return false;
1793  }
1794  else if (o1.getSegment(s1))
1795  {
1796  if (o2.getPoint(p2))
1797  {
1798  if (s1.contains(p2))
1799  {
1800  obj = p2;
1801  return true;
1802  } // else return false;
1803  }
1804  else if (o2.getSegment(s2))
1805  return intersect(s1, s2, obj);
1806  else if (o2.getLine(l2))
1807  return intersect(s1, l2, obj);
1808  else if (o2.getPolygon(po2))
1809  return intersect(s1, po2, obj);
1810  else if (o2.getPlane(pl2))
1811  return intersect(s1, pl2, obj); // else return false;
1812  }
1813  else if (o1.getLine(l1))
1814  {
1815  if (o2.getPoint(p2))
1816  {
1817  if (l1.contains(p2))
1818  {
1819  obj = p2;
1820  return true;
1821  } // else return false;
1822  }
1823  else if (o2.getSegment(s2))
1824  return intersect(l1, s2, obj);
1825  else if (o2.getLine(l2))
1826  return intersect(l1, l2, obj);
1827  else if (o2.getPolygon(po2))
1828  return intersect(l1, po2, obj);
1829  else if (o2.getPlane(pl2))
1830  return intersect(l2, pl2, obj); // else return false;
1831  }
1832  else if (o1.getPolygon(po1))
1833  {
1834  if (o2.getPoint(p2))
1835  {
1836  if (po1.contains(p2))
1837  {
1838  obj = p2;
1839  return true;
1840  } // else return false;
1841  }
1842  else if (o2.getSegment(s2))
1843  return intersect(po1, s2, obj);
1844  else if (o2.getLine(l2))
1845  return intersect(po1, l2, obj);
1846  else if (o2.getPolygon(po2))
1847  return intersect(po1, po2, obj);
1848  else if (o2.getPlane(pl2))
1849  return intersect(po1, pl2, obj); // else return false;
1850  }
1851  else if (o1.getPlane(pl1))
1852  {
1853  if (o2.getPoint(p2))
1854  {
1855  if (pl1.contains(p2))
1856  {
1857  obj = p2;
1858  return true;
1859  } // else return false;
1860  }
1861  else if (o2.getSegment(s2))
1862  return intersect(pl1, s2, obj);
1863  else if (o2.getLine(l2))
1864  return intersect(pl1, l2, obj);
1865  else if (o2.getPlane(pl2))
1866  return intersect(pl1, pl2, obj); // else return false;
1867  } // else return false;
1868  return false;
1869 }
1870 
1871 double math::distance(const TPoint2D& p1, const TPoint2D& p2)
1872 {
1873  double dx = p2.x - p1.x;
1874  double dy = p2.y - p1.y;
1875  return sqrt(dx * dx + dy * dy);
1876 }
1877 
1878 double math::distance(const TPoint3D& p1, const TPoint3D& p2)
1879 {
1880  double dx = p2.x - p1.x;
1881  double dy = p2.y - p1.y;
1882  double dz = p2.z - p1.z;
1883  return sqrt(dx * dx + dy * dy + dz * dz);
1884 }
1885 
1887  const std::vector<TPoint2D>& poly, TPoint2D& pMin, TPoint2D& pMax)
1888 {
1889  size_t N = poly.size();
1890  if (N < 1) throw logic_error("Empty polygon");
1891  pMin = poly[0];
1892  pMax = poly[0];
1893  for (size_t i = 1; i < N; i++)
1894  {
1895  pMin.x = min(pMin.x, poly[i].x);
1896  pMin.y = min(pMin.y, poly[i].y);
1897  pMax.x = max(pMax.x, poly[i].x);
1898  pMax.y = max(pMax.y, poly[i].y);
1899  }
1900 }
1901 
1902 double math::distance(const TLine2D& r1, const TLine2D& r2)
1903 {
1904  if (std::abs(r1.coefs[0] * r2.coefs[1] - r2.coefs[0] * r1.coefs[1]) <
1906  {
1907  // Lines are parallel
1908  size_t i1 = (std::abs(r1.coefs[0]) < geometryEpsilon) ? 0 : 1;
1909  TPoint2D p;
1910  p[i1] = 0.0;
1911  p[1 - i1] = -r1.coefs[2] / r1.coefs[1 - i1];
1912  return r2.distance(p);
1913  }
1914  else
1915  return 0; // Lines cross in some point
1916 }
1917 
1918 double math::distance(const TLine3D& r1, const TLine3D& r2)
1919 {
1920  if (std::abs(getAngle(r1, r2)) < geometryEpsilon)
1921  return r1.distance(r2.pBase); // Lines are parallel
1922  else
1923  {
1924  // We build a plane parallel to r2 which contains r1
1925  TPlane p;
1927  p.coefs[3] =
1928  -(p.coefs[0] * r1.pBase[0] + p.coefs[1] * r1.pBase[1] +
1929  p.coefs[2] * r1.pBase[2]);
1930  return p.distance(r2.pBase);
1931  }
1932 }
1933 
1934 double math::distance(const TPlane& p1, const TPlane& p2)
1935 {
1936  if (std::abs(getAngle(p1, p2)) < geometryEpsilon)
1937  {
1938  // Planes are parallel
1939  TPoint3D p(0, 0, 0);
1940  for (size_t i = 0; i < 3; i++)
1941  if (std::abs(p1.coefs[i]) >= geometryEpsilon)
1942  {
1943  p[i] = -p1.coefs[3] / p1.coefs[i];
1944  break;
1945  }
1946  return p2.distance(p);
1947  }
1948  else
1949  return 0; // Planes cross in a line
1950 }
1951 
1952 double math::distance(const TPolygon2D& p1, const TPolygon2D& p2)
1953 {
1954  MRPT_UNUSED_PARAM(p1);
1955  MRPT_UNUSED_PARAM(p2);
1956  THROW_EXCEPTION("TO DO:distance(TPolygon2D,TPolygon2D)");
1957 }
1958 
1959 double math::distance(const TPolygon2D& p1, const TSegment2D& s2)
1960 {
1961  MRPT_UNUSED_PARAM(p1);
1962  MRPT_UNUSED_PARAM(s2);
1963  THROW_EXCEPTION("TO DO:distance(TPolygon2D,TSegment)");
1964 }
1965 
1966 double math::distance(const TPolygon2D& p1, const TLine2D& l2)
1967 {
1968  MRPT_UNUSED_PARAM(p1);
1969  MRPT_UNUSED_PARAM(l2);
1970  THROW_EXCEPTION("TO DO:distance(TPolygon2D,TLine2D)");
1971 }
1972 
1973 double math::distance(const TPolygon3D& p1, const TPolygon3D& p2)
1974 {
1975  MRPT_UNUSED_PARAM(p1);
1976  MRPT_UNUSED_PARAM(p2);
1977  THROW_EXCEPTION("TO DO:distance(TPolygon3D,TPolygon3D");
1978 }
1979 
1980 double math::distance(const TPolygon3D& p1, const TSegment3D& s2)
1981 {
1982  MRPT_UNUSED_PARAM(p1);
1983  MRPT_UNUSED_PARAM(s2);
1984  THROW_EXCEPTION("TO DO:distance(TPolygon3D,TSegment3D");
1985 }
1986 
1987 double math::distance(const TPolygon3D& p1, const TLine3D& l2)
1988 {
1989  MRPT_UNUSED_PARAM(p1);
1990  MRPT_UNUSED_PARAM(l2);
1991  THROW_EXCEPTION("TO DO:distance(TPolygon3D,TLine3D");
1992 }
1993 
1994 double math::distance(const TPolygon3D& po, const TPlane& pl)
1995 {
1996  MRPT_UNUSED_PARAM(po);
1997  MRPT_UNUSED_PARAM(pl);
1998  THROW_EXCEPTION("TO DO:distance(TPolygon3D,TPlane");
1999 }
2000 
2002  const std::vector<TPoint3D>& poly, TPoint3D& pMin, TPoint3D& pMax)
2003 {
2004  size_t N = poly.size();
2005  if (N < 1) throw logic_error("Empty polygon");
2006  pMin = poly[0];
2007  pMax = poly[0];
2008  for (size_t i = 1; i < N; i++)
2009  {
2010  pMin.x = min(pMin.x, poly[i].x);
2011  pMin.y = min(pMin.y, poly[i].y);
2012  pMin.z = min(pMin.z, poly[i].z);
2013  pMax.x = max(pMax.x, poly[i].x);
2014  pMax.y = max(pMax.y, poly[i].y);
2015  pMax.z = max(pMax.z, poly[i].z);
2016  }
2017 }
2018 
2019 void createPlaneFromPoseAndAxis(const TPose3D& pose, TPlane& plane, size_t axis)
2020 {
2021  plane.coefs[3] = 0;
2022  CMatrixDouble44 m;
2023  pose.getHomogeneousMatrix(m);
2024  for (size_t i = 0; i < 3; i++)
2025  {
2026  plane.coefs[i] = m(i, axis);
2027  plane.coefs[3] -= plane.coefs[i] * m(i, 3);
2028  }
2029 }
2030 
2031 void math::createPlaneFromPoseXY(const TPose3D& pose, TPlane& plane)
2032 {
2033  createPlaneFromPoseAndAxis(pose, plane, 2);
2034 }
2035 
2036 void math::createPlaneFromPoseXZ(const TPose3D& pose, TPlane& plane)
2037 {
2038  createPlaneFromPoseAndAxis(pose, plane, 1);
2039 }
2040 
2041 void math::createPlaneFromPoseYZ(const TPose3D& pose, TPlane& plane)
2042 {
2043  createPlaneFromPoseAndAxis(pose, plane, 0);
2044 }
2045 
2047  const TPose3D& pose, const double (&normal)[3], TPlane& plane)
2048 {
2049  plane.coefs[3] = 0;
2050  CMatrixDouble44 m;
2051  pose.getHomogeneousMatrix(m);
2052  for (size_t i = 0; i < 3; i++)
2053  {
2054  plane.coefs[i] = 0;
2055  for (size_t j = 0; j < 3; j++) plane.coefs[i] += normal[j] * m(i, j);
2056  plane.coefs[3] -= plane.coefs[i] * m(i, 3);
2057  }
2058 }
2059 
2061  const TVector3D& vec, uint8_t coord)
2062 {
2063  CMatrixDouble44 m;
2064  // Assumes vector is unitary.
2065  // coord: 0=x, 1=y, 2=z.
2066  const uint8_t coord1 = (coord + 1) % 3;
2067  const uint8_t coord2 = (coord + 2) % 3;
2068  m.setZero();
2069  m(3, 3) = 1.0;
2070  for (size_t i = 0; i < 3; i++) m(i, coord) = vec[i];
2071  m(0, coord1) = 0;
2072  double h = hypot(vec[1], vec[2]);
2073  if (h < geometryEpsilon)
2074  {
2075  m(1, coord1) = 1;
2076  m(2, coord1) = 0;
2077  }
2078  else
2079  {
2080  m(1, coord1) = -vec[2] / h;
2081  m(2, coord1) = vec[1] / h;
2082  }
2083  m(0, coord2) = m(1, coord) * m(2, coord1) - m(2, coord) * m(1, coord1);
2084  m(1, coord2) = m(2, coord) * m(0, coord1) - m(0, coord) * m(2, coord1);
2085  m(2, coord2) = m(0, coord) * m(1, coord1) - m(1, coord) * m(0, coord1);
2086  return m;
2087 }
2088 
2089 double math::getRegressionLine(const vector<TPoint2D>& points, TLine2D& line)
2090 {
2091  CVectorFixedDouble<2> means;
2092  CMatrixDouble22 covars;
2093  covariancesAndMean(points, covars, means);
2094 
2095  std::vector<double> eigenVals;
2096  CMatrixDouble22 eigenVecs;
2097  covars.eig_symmetric(eigenVecs, eigenVals);
2098 
2099  // size_t selected = (eigenVal[0] >= eigenVal[1]) ? 0 : 1;
2100  line.coefs[0] = -eigenVecs(1, 1); // 1: largest eigenVal
2101  line.coefs[1] = eigenVecs(0, 1);
2102  line.coefs[2] = -line.coefs[0] * means[0] - line.coefs[1] * means[1];
2103  return std::sqrt(eigenVals[0] / eigenVals[1]);
2104 }
2105 
2106 template <class T>
2107 inline size_t getIndexOfMin(const T& e1, const T& e2, const T& e3)
2108 {
2109  return (e1 < e2) ? ((e1 < e3) ? 0 : 2) : ((e2 < e3) ? 1 : 2);
2110 }
2111 
2112 double math::getRegressionLine(const vector<TPoint3D>& points, TLine3D& line)
2113 {
2114  CVectorFixedDouble<3> means;
2115  CMatrixDouble33 covars;
2116  covariancesAndMean(points, covars, means);
2117 
2118  std::vector<double> eigenVal;
2119  CMatrixDouble33 eigenVec;
2120  covars.eig_symmetric(eigenVec, eigenVal);
2121 
2122  const size_t selected = 2; // sorted: max eigenvalue
2123  for (size_t i = 0; i < 3; i++)
2124  {
2125  line.pBase[i] = means[i];
2126  line.director[i] = eigenVec(i, selected);
2127  }
2128  size_t i1 = (selected + 1) % 3, i2 = (selected + 2) % 3;
2129  return std::sqrt((eigenVal[i1] + eigenVal[i2]) / eigenVal[selected]);
2130 }
2131 
2132 double math::getRegressionPlane(const vector<TPoint3D>& points, TPlane& plane)
2133 {
2134  vector<double> means;
2135  CMatrixDouble33 covars;
2136  covariancesAndMean(points, covars, means);
2137 
2138  std::vector<double> eigenVal;
2139  CMatrixDouble33 eigenVec;
2140  covars.eig_symmetric(eigenVec, eigenVal);
2141 
2142  for (size_t i = 0; i < 3; ++i)
2143  if (eigenVal[i] < 0 && std::abs(eigenVal[i]) < geometryEpsilon)
2144  eigenVal[i] = 0;
2145 
2146  const size_t selected = 0; // sorted: minimum eigenVal
2147  plane.coefs[3] = 0;
2148  for (size_t i = 0; i < 3; i++)
2149  {
2150  plane.coefs[i] = eigenVec(i, selected);
2151  plane.coefs[3] -= plane.coefs[i] * means[i];
2152  }
2153  size_t i1 = (selected + 1) % 3, i2 = (selected + 2) % 3;
2154  return std::sqrt(eigenVal[selected] / (eigenVal[i1] + eigenVal[i2]));
2155 }
2156 
2158  const std::vector<TSegment3D>& segms, std::vector<TPolygon3D>& polys)
2159 {
2160  std::vector<TSegment3D> tmp;
2161  assemblePolygons(segms, polys, tmp);
2162 }
2163 
2165 {
2166  size_t seg1;
2167  size_t seg2;
2168  bool seg1Point; // true for point2, false for point1
2169  bool seg2Point; // same
2170  MatchingVertex() = default;
2171  MatchingVertex(size_t s1, size_t s2, bool s1p, bool s2p)
2172  : seg1(s1), seg2(s2), seg1Point(s1p), seg2Point(s2p)
2173  {
2174  }
2175 };
2177 {
2178  public:
2179  const std::vector<TSegment3D>& segs;
2180  FCreatePolygon(const std::vector<TSegment3D>& s) : segs(s) {}
2181  TPolygon3D operator()(const std::vector<MatchingVertex>& vertices)
2182  {
2183  TPolygon3D res;
2184  size_t N = vertices.size();
2185  res.reserve(N);
2186  for (const auto& vertice : vertices)
2187  res.push_back(segs[vertice.seg2][vertice.seg2Point ? 1 : 0]);
2188  return res;
2189  }
2190 };
2191 inline bool firstOrNonPresent(size_t i, const std::vector<MatchingVertex>& v)
2192 {
2193  if (v.size() > 0 && v[0].seg1 == i) return true;
2194  for (const auto& it : v)
2195  if (it.seg1 == i || it.seg2 == i) return false;
2196  return true;
2197 }
2200  std::vector<std::vector<MatchingVertex>>& res, std::vector<bool>& used,
2201  size_t searching, unsigned char mask, std::vector<MatchingVertex>& current)
2202 {
2203  for (size_t i = 0; i < mat.cols(); i++)
2204  if (!used[i] && mat.isNotNull(searching, i))
2205  {
2206  unsigned char match = mat(searching, i) & mask;
2207  if (!match)
2208  continue;
2209  else if (firstOrNonPresent(i, current))
2210  {
2211  bool s1p, s2p;
2212  if (true == (s1p = (!(match & 3)))) match >>= 2;
2213  s2p = !(match & 1);
2214  if (current.size() >= 2 && current[0].seg1 == i)
2215  {
2216  if (s2p != current[0].seg1Point)
2217  {
2218  current.emplace_back(searching, i, s1p, s2p);
2219  for (auto it = current.begin(); it != current.end();
2220  ++it)
2221  used[it->seg2] = true;
2222  res.push_back(current);
2223  return true;
2224  }
2225  else
2226  continue; // Strange shape... not a polygon, although
2227  // it'll be without the first segment
2228  }
2229  else
2230  {
2231  current.emplace_back(searching, i, s1p, s2p);
2232  if (depthFirstSearch(
2233  mat, res, used, i, s2p ? 0x3 : 0xC, current))
2234  return true;
2235  current.pop_back();
2236  }
2237  }
2238  }
2239  // No match has been found. Backtrack
2240  return false;
2241 }
2244  std::vector<std::vector<MatchingVertex>>& res, std::vector<bool>& used)
2245 {
2246  vector<MatchingVertex> cur;
2247  for (size_t i = 0; i < used.size(); i++)
2248  if (!used[i])
2249  if (depthFirstSearch(mat, res, used, i, 0xf, cur)) cur.clear();
2250 }
2252  const std::vector<TSegment3D>& segms, std::vector<TPolygon3D>& polys,
2253  std::vector<TSegment3D>& remainder)
2254 {
2255  std::vector<TSegment3D> tmp;
2256  tmp.reserve(segms.size());
2257  for (const auto& segm : segms)
2258  if (segm.length() >= geometryEpsilon)
2259  tmp.push_back(segm);
2260  else
2261  remainder.push_back(segm);
2262  size_t N = tmp.size();
2264  for (size_t i = 0; i < N - 1; i++)
2265  for (size_t j = i + 1; j < N; j++)
2266  {
2267  if (distance(tmp[i].point1, tmp[j].point1) < geometryEpsilon)
2268  {
2269  matches(i, j) |= 1;
2270  matches(j, i) |= 1;
2271  }
2272  if (distance(tmp[i].point1, tmp[j].point2) < geometryEpsilon)
2273  {
2274  matches(i, j) |= 2;
2275  matches(j, i) |= 4;
2276  }
2277  if (distance(tmp[i].point2, tmp[j].point1) < geometryEpsilon)
2278  {
2279  matches(i, j) |= 4;
2280  matches(j, i) |= 2;
2281  }
2282  if (distance(tmp[i].point2, tmp[j].point2) < geometryEpsilon)
2283  {
2284  matches(i, j) |= 8;
2285  matches(j, i) |= 8;
2286  }
2287  }
2288  std::vector<std::vector<MatchingVertex>> results;
2289  std::vector<bool> usedSegments(N, false);
2290  depthFirstSearch(matches, results, usedSegments);
2291  polys.resize(results.size());
2292  transform(
2293  results.begin(), results.end(), polys.begin(), FCreatePolygon(segms));
2294  for (size_t i = 0; i < N; i++)
2295  if (!usedSegments[i]) remainder.push_back(tmp[i]);
2296 }
2297 
2299  const std::vector<TObject3D>& objs, std::vector<TPolygon3D>& polys)
2300 {
2301  std::vector<TObject3D> tmp;
2302  std::vector<TSegment3D> sgms;
2303  TObject3D::getPolygons(objs, polys, tmp);
2304  TObject3D::getSegments(tmp, sgms);
2305  assemblePolygons(sgms, polys);
2306 }
2307 
2309  const std::vector<TObject3D>& objs, std::vector<TPolygon3D>& polys,
2310  std::vector<TObject3D>& remainder)
2311 {
2312  std::vector<TObject3D> tmp;
2313  std::vector<TSegment3D> sgms, remainderSgms;
2314  TObject3D::getPolygons(objs, polys, tmp);
2315  TObject3D::getSegments(tmp, sgms, remainder);
2316  assemblePolygons(sgms, polys, remainderSgms);
2317  remainder.insert(
2318  remainder.end(), remainderSgms.begin(), remainderSgms.end());
2319 }
2320 
2322  const std::vector<TObject3D>& objs, std::vector<TPolygon3D>& polys,
2323  std::vector<TSegment3D>& remainder1, std::vector<TObject3D>& remainder2)
2324 {
2325  std::vector<TObject3D> tmp;
2326  std::vector<TSegment3D> sgms;
2327  TObject3D::getPolygons(objs, polys, tmp);
2328  TObject3D::getSegments(tmp, sgms, remainder2);
2329  assemblePolygons(sgms, polys, remainder1);
2330 }
2331 
2332 bool intersect(const TLine2D& l1, const TSegmentWithLine& s2, TObject2D& obj)
2333 {
2334  if (intersect(l1, s2.line, obj))
2335  {
2336  if (obj.isLine())
2337  {
2338  obj = s2.segment;
2339  return true;
2340  }
2341  else
2342  {
2343  TPoint2D p;
2344  obj.getPoint(p);
2345  return s2.segment.contains(p);
2346  }
2347  }
2348  else
2349  return false;
2350 }
2351 
2352 inline bool intersect(
2353  const TSegmentWithLine& s1, const TLine2D& l2, TObject2D& obj)
2354 {
2355  return intersect(l2, s1, obj);
2356 }
2357 
2359  const TPolygon2D& poly, vector<TPolygon2D>& components)
2360 {
2361  components.clear();
2362  size_t N = poly.size();
2363  if (N <= 3) return false;
2364  vector<TSegmentWithLine> segms(N);
2365  for (size_t i = 0; i < N - 1; i++)
2366  segms[i] = TSegmentWithLine(poly[i], poly[i + 1]);
2367  segms[N - 1] = TSegmentWithLine(poly[N - 1], poly[0]);
2368  TObject2D obj;
2369  TPoint2D pnt;
2370  for (size_t i = 0; i < N; i++)
2371  {
2372  size_t ii = (i + 2) % N, i_ = (i + N - 1) % N;
2373  for (size_t j = ii; j != i_; j = (j + 1) % N)
2374  if (intersect(segms[i].line, segms[j], obj) && obj.getPoint(pnt))
2375  {
2377  pnt, segms[i].segment
2378  [(distance(pnt, segms[i].segment.point1) <
2379  distance(pnt, segms[i].segment.point2))
2380  ? 0
2381  : 1]);
2382  bool cross = false;
2383  TPoint2D pTmp;
2384  for (size_t k = 0; (k < N) && !cross; k++)
2385  if (intersect(sTmp, segms[k], obj))
2386  {
2387  if (obj.getPoint(pTmp) &&
2388  (distance(pTmp, sTmp.segment[0]) >=
2389  geometryEpsilon) &&
2390  (distance(pTmp, sTmp.segment[1]) >=
2391  geometryEpsilon))
2392  cross = true;
2393  }
2394  if (cross) continue;
2395  // At this point, we have a suitable point, although we must
2396  // check if the division is right.
2397  // We do this by evaluating, in the expanded segment's line, the
2398  // next and previous points. If both signs differ, proceed.
2399  if (sign(segms[i].line.evaluatePoint(poly[(i + N - 1) % N])) ==
2400  sign(segms[i].line.evaluatePoint(poly[(i + 2) % N])))
2401  continue;
2402  TPolygon2D p1, p2;
2403  if (i > j)
2404  {
2405  p1.insert(p1.end(), poly.begin() + i + 1, poly.end());
2406  p1.insert(p1.end(), poly.begin(), poly.begin() + j + 1);
2407  p2.insert(
2408  p2.end(), poly.begin() + j + 1, poly.begin() + i + 1);
2409  }
2410  else
2411  {
2412  p1.insert(
2413  p1.end(), poly.begin() + i + 1, poly.begin() + j + 1);
2414  p2.insert(p2.end(), poly.begin() + j + 1, poly.end());
2415  p2.insert(p2.end(), poly.begin(), poly.begin() + i + 1);
2416  }
2417  if (distance(*(p1.rbegin()), pnt) >= geometryEpsilon)
2418  p1.push_back(pnt);
2419  if (distance(*(p2.rbegin()), pnt) >= geometryEpsilon)
2420  p2.push_back(pnt);
2423  vector<TPolygon2D> tempComps;
2424  if (splitInConvexComponents(p1, tempComps))
2425  components.insert(
2426  components.end(), tempComps.begin(), tempComps.end());
2427  else
2428  components.push_back(p1);
2429  if (splitInConvexComponents(p2, tempComps))
2430  components.insert(
2431  components.end(), tempComps.begin(), tempComps.end());
2432  else
2433  components.push_back(p2);
2434  return true;
2435  }
2436  }
2437  return false;
2438 }
2439 
2441 {
2442  public:
2443  const TPose3D& pose;
2445  FUnprojectPolygon2D(const TPose3D& p) : pose(p), tmp1(0), tmp2(0) {}
2447  {
2448  tmp1 = TPolygon3D(poly2D);
2449  project3D(tmp1, pose, tmp2);
2450  return tmp2;
2451  }
2452 };
2454  const TPolygon3D& poly, vector<TPolygon3D>& components)
2455 {
2456  TPlane p;
2457  if (!poly.getPlane(p)) throw std::logic_error("Polygon is skew");
2458  TPose3D pose1;
2459  p.getAsPose3DForcingOrigin(poly[0], pose1);
2460  const TPose3D pose2 = -pose1;
2461  TPolygon3D polyTmp;
2462  project3D(poly, pose2, polyTmp);
2463  TPolygon2D poly2D = TPolygon2D(polyTmp);
2464  vector<TPolygon2D> components2D;
2465  if (splitInConvexComponents(poly2D, components2D))
2466  {
2467  components.resize(components2D.size());
2468  transform(
2469  components2D.begin(), components2D.end(), components.begin(),
2470  FUnprojectPolygon2D(pose1));
2471  return true;
2472  }
2473  else
2474  return false;
2475 }
2476 
2478 {
2479  TPoint2D p;
2480  sgm.getCenter(p);
2481  bis.coefs[0] = sgm.point2.x - sgm.point1.x;
2482  bis.coefs[1] = sgm.point2.y - sgm.point1.y;
2483  bis.coefs[2] = -bis.coefs[0] * p.x - bis.coefs[1] * p.y;
2484  bis.unitarize();
2485 }
2486 
2488 {
2489  TPoint3D p;
2490  sgm.getCenter(p);
2491  bis.coefs[0] = sgm.point2.x - sgm.point1.x;
2492  bis.coefs[1] = sgm.point2.y - sgm.point1.y;
2493  bis.coefs[2] = sgm.point2.z - sgm.point1.z;
2494  bis.coefs[2] =
2495  -bis.coefs[0] * p.x - bis.coefs[1] * p.y - bis.coefs[2] * p.z;
2496  bis.unitarize();
2497 }
2498 
2499 void math::getAngleBisector(const TLine2D& l1, const TLine2D& l2, TLine2D& bis)
2500 {
2501  TPoint2D p;
2502  TObject2D obj;
2503  if (!intersect(l1, l2, obj))
2504  {
2505  // Both lines are parallel
2506  double mod1 = sqrt(square(l1.coefs[0]) + square(l1.coefs[1]));
2507  double mod2 = sqrt(square(l2.coefs[0]) + square(l2.coefs[2]));
2508  bis.coefs[0] = l1.coefs[0] / mod1;
2509  bis.coefs[1] = l1.coefs[1] / mod1;
2510  bool sameSign;
2511  if (std::abs(bis.coefs[0]) < geometryEpsilon)
2512  sameSign = (l1.coefs[1] * l2.coefs[1]) > 0;
2513  else
2514  sameSign = (l1.coefs[0] * l2.coefs[0]) > 0;
2515  if (sameSign)
2516  bis.coefs[2] = (l1.coefs[2] / mod1) + (l2.coefs[2] / mod2);
2517  else
2518  bis.coefs[2] = (l1.coefs[2] / mod1) - (l2.coefs[2] / mod2);
2519  }
2520  else if (obj.getPoint(p))
2521  {
2522  // Both lines cross
2523  double ang1 = atan2(-l1.coefs[0], l1.coefs[1]);
2524  double ang2 = atan2(-l2.coefs[0], l2.coefs[1]);
2525  double ang = (ang1 + ang2) / 2;
2526  bis.coefs[0] = -sin(ang);
2527  bis.coefs[1] = cos(ang);
2528  bis.coefs[2] = -bis.coefs[0] * p.x - bis.coefs[1] * p.y;
2529  }
2530  else
2531  {
2532  bis = l1;
2533  bis.unitarize();
2534  }
2535 }
2536 
2537 void math::getAngleBisector(const TLine3D& l1, const TLine3D& l2, TLine3D& bis)
2538 {
2539  TPlane p = TPlane(l1, l2); // May throw an exception
2540  TLine3D l1P, l2P;
2541  TLine2D bis2D;
2542  TPose3D pose, pose2;
2543  p.getAsPose3D(pose);
2544  pose2 = -pose;
2545  project3D(l1, pose2, l1P);
2546  project3D(l2, pose2, l2P);
2547  getAngleBisector(TLine2D(l1P), TLine2D(l2P), bis2D);
2548  project3D(TLine3D(bis2D), pose, bis);
2549 }
2550 
2552  const vector<TPolygonWithPlane>& vec, const TPose3D& pose, double& dist)
2553 {
2554  dist = HUGE_VAL;
2555  double nDist = 0;
2556  TLine3D lin;
2557  createFromPoseX(pose, lin);
2558  lin.unitarize();
2559  bool res = false;
2560  for (const auto& it : vec)
2561  if (::intersect(it, lin, nDist, dist))
2562  {
2563  res = true;
2564  dist = nDist;
2565  }
2566  return res;
2567 }
2568 
2570  double dx, double dy, double dz)
2571 {
2572  MRPT_START
2573 
2574  if (std::abs(dx) < 1e-10 && std::abs(dy) < 1e-10 && std::abs(dz) < 1e-10)
2575  THROW_EXCEPTION("Invalid input: Direction vector is (0,0,0);");
2576 
2577  CMatrixDouble33 P;
2578 
2579  // 1st vector:
2580  double n_xy = square(dx) + square(dy);
2581  double n = sqrt(n_xy + square(dz));
2582  n_xy = sqrt(n_xy);
2583  P(0, 0) = dx / n;
2584  P(1, 0) = dy / n;
2585  P(2, 0) = dz / n;
2586 
2587  // 2nd perpendicular vector:
2588  if (fabs(dx) > 1e-4 || fabs(dy) > 1e-4)
2589  {
2590  P(0, 1) = -dy / n_xy;
2591  P(1, 1) = dx / n_xy;
2592  P(2, 1) = 0;
2593  }
2594  else
2595  {
2596  // Any vector in the XY plane will work:
2597  P(0, 1) = 1;
2598  P(1, 1) = 0;
2599  P(2, 1) = 0;
2600  }
2601 
2602  // 3rd perpendicular vector: cross product of the two last vectors:
2603  Eigen::Vector3d c2;
2604  crossProduct3D(P.col(0), P.col(1), c2);
2605  P.col(2) = c2;
2606 
2607  return P;
2608  MRPT_END
2609 }
bool RectanglesIntersection(double R1_x_min, double R1_x_max, double R1_y_min, double R1_y_max, double R2_x_min, double R2_x_max, double R2_y_min, double R2_y_max, double R2_pose_x, double R2_pose_y, double R2_pose_phi)
Returns whether two rotated rectangles intersect.
Definition: geometry.cpp:367
void getCenter(TPoint2D &p) const
Segment&#39;s central point.
Definition: TSegment2D.h:80
void project3D(const TPoint3D &point, const mrpt::math::TPose3D &newXYpose, TPoint3D &newPoint)
Uses the given pose 3D to project a point into a new base.
Definition: geometry.h:300
bool contains(const TPoint3D &point) const
Check whether a point is inside the segment.
Definition: TSegment3D.cpp:112
bool intersectInCommonLine(const mrpt::math::TSegment3D &s1, const mrpt::math::TSegment3D &s2, const mrpt::math::TLine3D &lin, mrpt::math::TObject3D &obj)
Definition: geometry.cpp:476
void closestFromPointToLine(double Px, double Py, double x1, double y1, double x2, double y2, double &out_x, double &out_y)
Computes the closest point from a given point to a (infinite) line.
Definition: geometry.cpp:77
bool getPoint(TPoint2D &p) const
Gets the content as a point, returning false if the type is inadequate.
Definition: TObject2D.h:109
bool isNotNull(size_t nRow, size_t nCol) const
Checks whether an element of the matrix is not the default object.
TSegmentWithLine(const TPoint2D &p1, const TPoint2D &p2)
Definition: geometry.cpp:1403
TPolygon3D operator()(const TPolygon2D &poly2D)
Definition: geometry.cpp:2446
bool getPolygon(TPolygon2D &p) const
Gets the content as a polygon, returning false if the type is inadequate.
Definition: TObject2D.h:150
A compile-time fixed-size numeric matrix container.
Definition: CMatrixFixed.h:33
#define MRPT_START
Definition: exceptions.h:241
bool splitInConvexComponents(const TPolygon2D &poly, std::vector< TPolygon2D > &components)
Splits a 2D polygon into convex components.
Definition: geometry.cpp:2358
TPoint2D_< double > TPoint2D
Lightweight 2D point.
Definition: TPoint2D.h:213
unsigned char getType() const
Gets content type.
Definition: TObject2D.h:105
auto col(int colIdx)
Definition: MatrixBase.h:89
void unsafeProjectPoint(const TPoint3D &point, const TPose3D &pose, TPoint2D &newPoint)
Definition: geometry.cpp:523
bool intersect(const TPolygonWithPlane &p1, const TLine3D &l2, double &d, double bestKnown)
Definition: geometry.cpp:539
void getPlanes(const std::vector< TPolygon3D > &polys, std::vector< TPlane > &planes)
Definition: geometry.cpp:1616
double x
X,Y coordinates.
Definition: TPose2D.h:30
bool firstOrNonPresent(size_t i, const std::vector< MatchingVertex > &v)
Definition: geometry.cpp:2191
#define THROW_EXCEPTION(msg)
Definition: exceptions.h:67
T x
X,Y coordinates.
Definition: TPoint2D.h:25
bool depthFirstSearch(const CSparseMatrixTemplate< unsigned char > &mat, std::vector< std::vector< MatchingVertex >> &res, std::vector< bool > &used, size_t searching, unsigned char mask, std::vector< MatchingVertex > &current)
Definition: geometry.cpp:2198
static constexpr unsigned char GEOMETRIC_TYPE_POLYGON
Object type identifier for TPolygon2D or TPolygon3D.
Definition: TPoseOrPoint.h:125
bool traceRay(const std::vector< TPolygonWithPlane > &vec, const mrpt::math::TPose3D &pose, double &dist)
Fast ray tracing method using polygons&#39; properties.
Definition: geometry.cpp:2551
bool getSegment(TSegment3D &s) const
Gets the content as a segment, returning false if the type is not adequate.
Definition: TObject3D.h:134
FUnprojectPolygon2D(const TPose3D &p)
Definition: geometry.cpp:2445
void destroy()
Definition: geometry.cpp:1312
size_t getNonNullElements() const
Gets the amount of non-null elements inside the matrix.
void setEpsilon(double nE)
Changes the value of the geometric epsilon (default = 1e-5)
Definition: geometry.cpp:35
void assemblePolygons(const std::vector< TSegment3D > &segms, std::vector< TPolygon3D > &polys)
Tries to assemble a set of segments into a set of closed polygons.
Definition: geometry.cpp:2157
void getSegmentBisector(const TSegment2D &sgm, TLine2D &bis)
Gets the bisector of a 2D segment.
Definition: geometry.cpp:2477
char fromObject(const TObject2D &obj)
Definition: geometry.cpp:1428
mrpt::math::TPose3D inversePose
Plane&#39;s inverse pose.
void createFromPoseAndVector(const mrpt::math::TPose3D &p, const double(&vector)[3], TLine3D &r)
Gets a 3D line corresponding to any arbitrary vector, in the base given by the pose.
Definition: geometry.cpp:932
Slightly heavyweight type to speed-up calculations with polygons in 3D.
This file implements several operations that operate element-wise on individual or pairs of container...
void fromHomogeneousMatrix(const mrpt::math::CMatrixDouble44 &HG)
Definition: TPose3D.cpp:201
vector< TSegment2D > l2
Definition: geometry.cpp:1302
bool minDistBetweenLines(double p1_x, double p1_y, double p1_z, double p2_x, double p2_y, double p2_z, double p3_x, double p3_y, double p3_z, double p4_x, double p4_y, double p4_z, double &x, double &y, double &z, double &dist)
Calculates the minimum distance between a pair of lines.
Definition: geometry.cpp:298
void createPlaneFromPoseXY(const mrpt::math::TPose3D &pose, TPlane &plane)
Given a pose, creates a plane orthogonal to its Z vector.
Definition: geometry.cpp:2031
double closestSquareDistanceFromPointToLine(double Px, double Py, double x1, double y1, double x2, double y2)
Returns the square distance from a point to a line.
Definition: geometry.cpp:100
Standard type for storing any lightweight 2D type.
Definition: TObject2D.h:24
A wrapper of a TPolygon2D class, implementing CSerializable.
Definition: CPolygon.h:19
bool getLine(TLine2D &r) const
Gets the content as a line, returning false if the type is inadequate.
Definition: TObject2D.h:136
void getHomogeneousMatrix(mrpt::math::CMatrixDouble44 &HG) const
Definition: TPose3D.cpp:217
static constexpr unsigned char GEOMETRIC_TYPE_POINT
Object type identifier for TPoint2D or TPoint3D.
Definition: TPoseOrPoint.h:110
bool getPlane(TPlane &p) const
Gets the content as a plane, returning false if the type is not adequate.
Definition: TObject3D.h:175
TPoint3D pBase
Base point.
Definition: TLine3D.h:23
Standard object for storing any 3D lightweight object.
Definition: TObject3D.h:25
STL namespace.
bool getSegment(TSegment2D &s) const
Gets the content as a segment, returning false if the type is inadequate.
Definition: TObject2D.h:123
TSegmentWithLine(const TSegment2D &s)
Definition: geometry.cpp:1399
void getSegmentsWithLine(const TPolygon2D &poly, vector< TSegmentWithLine > &segs)
Definition: geometry.cpp:1419
bool intersectInCommonPlane(const T3D &o1, const U3D &o2, const mrpt::math::TPlane &p, mrpt::math::TObject3D &obj)
Definition: geometry.cpp:447
void createPlaneFromPoseAndNormal(const mrpt::math::TPose3D &pose, const double(&normal)[3], TPlane &plane)
Given a pose and any vector, creates a plane orthogonal to that vector in the pose&#39;s coordinates...
Definition: geometry.cpp:2046
void generate2DObject(TLine2D &l) const
Project into 2D space, discarding the Z coordinate.
Definition: TLine3D.cpp:23
bool contains(const TPoint2D &point) const
Check whether a point is inside (or within geometryEpsilon of a polygon edge).
Definition: TPolygon2D.cpp:69
size_t getIndexOfMin(const T &e1, const T &e2, const T &e3)
Definition: geometry.cpp:2107
int rank(Scalar threshold=0) const
Finds the rank of the matrix via LU decomposition.
bool eig_symmetric(Derived &eVecs, std::vector< Scalar > &eVals, bool sorted=true) const
Read: eig()
TSegment2D segment
Definition: geometry.cpp:1397
void getAngleBisector(const TLine2D &l1, const TLine2D &l2, TLine2D &bis)
Gets the bisector of two lines or segments (implicit constructor will be used if necessary) ...
Definition: geometry.cpp:2499
void unitarize()
Unitarize line&#39;s normal vector.
Definition: TLine2D.cpp:48
A sparse matrix container (with cells of any type), with iterators.
TTempIntersection(const TCommonRegion &common)
Definition: geometry.cpp:1373
void createFromPoseY(const mrpt::math::TPose3D &p, TLine3D &r)
Gets a 3D line corresponding to the Y axis in a given pose.
Definition: geometry.cpp:922
void crossProduct3D(const T &v0, const U &v1, V &vOut)
Computes the cross product of two 3D vectors, returning a vector normal to both.
Definition: geometry.h:765
TPoint3D point1
origin point
Definition: TSegment3D.h:23
bool conformAPlane(const std::vector< TPoint3D > &points)
Checks whether this polygon or set of points acceptably fits a plane.
Definition: geometry.cpp:969
const std::vector< TSegment3D > & segs
Definition: geometry.cpp:2179
TTempIntersection & operator=(const TTempIntersection &t)
Definition: geometry.cpp:1378
unsigned char type
Definition: geometry.cpp:1307
static constexpr unsigned char GEOMETRIC_TYPE_PLANE
Object type identifier for TPlane.
Definition: TPoseOrPoint.h:130
float d2f(const double d)
shortcut for static_cast<float>(double)
void getAsPose3D(mrpt::math::TPose3D &outPose) const
Definition: TPlane.cpp:73
void removeRedundantVertices()
Erase every redundant vertex from the polygon, saving space.
Definition: TPolygon2D.cpp:141
bool getPolygon(TPolygon3D &p) const
Gets the content as a polygon, returning false if the type is not adequate.
Definition: TObject3D.h:161
This base provides a set of functions for maths stuff.
vector< TSegment2D > l1
Definition: geometry.cpp:1301
2D segment, consisting of two points.
Definition: TSegment2D.h:20
bool isPoint() const
Checks whether content is a point.
Definition: TObject3D.h:95
void unsafeProjectPolygon(const TPolygon3D &poly, const TPose3D &pose, TPolygon2D &newPoly)
Definition: geometry.cpp:531
TCommonRegion & operator=(const TCommonRegion &r)
Definition: geometry.cpp:1331
double evaluatePoint(const TPoint3D &point) const
Evaluate a point in the plane&#39;s equation.
Definition: TPlane.cpp:24
map< string, CVectorDouble > results
3D segment, consisting of two points.
Definition: TSegment3D.h:20
size_t cols() const
Returns the amount of columns in this matrix.
static double geometryEpsilon
Definition: geometry.cpp:32
std::array< double, 3 > director
Director vector.
Definition: TLine3D.h:25
TPoint3D point2
final point
Definition: TSegment3D.h:24
void covariancesAndMean(const VECTOR_OF_VECTORS &elements, MATRIXLIKE &covariances, VECTORLIKE &means, const bool *elem_do_wrap2pi=nullptr)
Computes covariances and mean of any vector of containers.
Definition: data_utils.h:381
void generate3DObject(TObject3D &obj) const
Project into 3D space.
Definition: TObject2D.cpp:24
bool PointIntoPolygon(double x, double y) const
Check if a point is inside the polygon.
Definition: CPolygon.h:63
void getRectangleBounds(const std::vector< TPoint2D > &poly, TPoint2D &pMin, TPoint2D &pMax)
Gets the rectangular bounds of a 2D polygon or set of 2D points.
Definition: geometry.cpp:1886
void createPlaneFromPoseXZ(const mrpt::math::TPose3D &pose, TPlane &plane)
Given a pose, creates a plane orthogonal to its Y vector.
Definition: geometry.cpp:2036
void getAsPose2D(TPose2D &outPose) const
Definition: TLine2D.cpp:59
double distance(const TPoint2D &point) const
Distance from a given point.
Definition: TLine2D.cpp:33
size_t rows() const
Returns the amount of rows in this matrix.
TPolygon3D poly
Actual polygon.
void getAsPose3DForcingOrigin(const TPoint3D &center, TPose3D &pose) const
Definition: TPlane.cpp:85
3D Plane, represented by its equation
Definition: TPlane.h:22
const double eps
void composePoint(const TPoint3D &l, TPoint3D &g) const
Definition: TPose3D.cpp:80
void unitarize()
Unitarize normal vector.
Definition: TPlane.cpp:66
int sign(T x)
Returns the sign of X as "1" or "-1".
double getRegressionPlane(const std::vector< TPoint3D > &points, TPlane &plane)
Using eigenvalues, gets the best fitting plane for a set of 3D points.
Definition: geometry.cpp:2132
TPoint3D_< double > TPoint3D
Lightweight 3D point.
Definition: TPoint3D.h:268
void getCenter(TPoint3D &p) const
Segment&#39;s central point.
Definition: TSegment3D.h:71
FCreatePolygon(const std::vector< TSegment3D > &s)
Definition: geometry.cpp:2180
TPoint2D point2
Destiny point.
Definition: TSegment2D.h:30
TPolygon2D poly2D
Polygon, after being projected to the plane using inversePose.
TCommonRegion(const TPoint2D &p)
Definition: geometry.cpp:1325
bool pointIntoPolygon2D(double px, double py, unsigned int polyEdges, const double *poly_xs, const double *poly_ys)
Returns true if the 2D point (px,py) falls INTO the given polygon.
Definition: geometry.cpp:233
double getAngle(const TPlane &p1, const TPlane &p2)
Computes the angle between two planes.
Definition: geometry.cpp:846
bool isPlane() const
Checks whether content is a plane.
Definition: TObject3D.h:111
bool contains(const TPoint3D &point) const
Check whether a point is inside the line.
Definition: TLine3D.cpp:25
T wrapToPi(T a)
Modifies the given angle to translate it into the ]-pi,pi] range.
Definition: wrap2pi.h:50
double distance(const TPoint3D &point) const
Distance to 3D point.
Definition: TPlane.cpp:38
bool contains(const TPoint2D &point) const
Check whether a point is inside a segment.
Definition: TSegment2D.cpp:45
union TTempIntersection::@66 data
bool getPoint(TPoint3D &p) const
Gets the content as a point, returning false if the type is not adequate.
Definition: TObject3D.h:120
TPoint2D point1
Origin point.
Definition: TSegment2D.h:26
bool SegmentsIntersection(const double x1, const double y1, const double x2, const double y2, const double x3, const double y3, const double x4, const double y4, double &ix, double &iy)
Returns the intersection point, and if it exists, between two segments.
Definition: geometry.cpp:120
return_t square(const num_t x)
Inline function for the square of a number.
void clear()
Completely removes all elements, although maintaining the matrix&#39;s size.
T x
X,Y,Z coordinates.
Definition: TPoint3D.h:29
bool isLine() const
Checks whether content is a line.
Definition: TObject2D.h:97
This is the global namespace for all Mobile Robot Programming Toolkit (MRPT) libraries.
union TCommonRegion::@65 data
std::array< double, 3 > coefs
Line coefficients, stored as an array: .
Definition: TLine2D.h:23
TTempIntersection(const T2ListsOfSegments &segms)
Definition: geometry.cpp:1369
TPolygon3D operator()(const std::vector< MatchingVertex > &vertices)
Definition: geometry.cpp:2181
CMatrixDouble44 generateAxisBaseFromDirectionAndAxis(const mrpt::math::TVector3D &vec, uint8_t coord)
Creates a homogeneus matrix (4x4) such that the coordinate given (0 for x, 1 for y, 2 for z) corresponds to the provided vector.
Definition: geometry.cpp:2060
double getRegressionLine(const std::vector< TPoint2D > &points, TLine2D &line)
Using eigenvalues, gets the best fitting line for a set of 2D points.
Definition: geometry.cpp:2089
double getEpsilon()
Gets the value of the geometric epsilon (default = 1e-5)
Definition: geometry.cpp:34
void createFromPoseX(const mrpt::math::TPose3D &p, TLine3D &r)
Gets a 3D line corresponding to the X axis in a given pose.
Definition: geometry.cpp:917
const TPose3D & pose
Definition: geometry.cpp:2443
mrpt::math::TPose3D pose
Plane&#39;s pose.
T2ListsOfSegments * segms
Definition: geometry.cpp:1353
void getPrismBounds(const std::vector< TPoint3D > &poly, TPoint3D &pMin, TPoint3D &pMax)
Gets the prism bounds of a 3D polygon or set of 3D points.
Definition: geometry.cpp:2001
TPoint2D * point
Definition: geometry.cpp:1309
void unitarize()
Unitarize director vector.
Definition: TLine3D.cpp:56
void getInverseHomogeneousMatrix(mrpt::math::CMatrixDouble44 &HG) const
Definition: TPose3D.cpp:228
void resize(size_t nRows, size_t nCols)
Changes the size of the matrix.
CMatrixDouble33 generateAxisBaseFromDirection(double dx, double dy, double dz)
Computes an axis base (a set of three 3D normal vectors) with the given vector being the first of the...
Definition: geometry.cpp:2569
#define MRPT_END
Definition: exceptions.h:245
void createPlaneFromPoseAndAxis(const TPose3D &pose, TPlane &plane, size_t axis)
Definition: geometry.cpp:2019
mrpt::math::TPoint2D composePoint(const TPoint2D l) const
Definition: TPose2D.cpp:64
Lightweight 3D pose (three spatial coordinates, plus three angular coordinates).
Definition: TPose3D.h:24
Lightweight 2D pose.
Definition: TPose2D.h:22
MatchingVertex(size_t s1, size_t s2, bool s1p, bool s2p)
Definition: geometry.cpp:2171
bool getLine(TLine3D &r) const
Gets the content as a line, returning false if the type is not adequate.
Definition: TObject3D.h:147
void project2D(const TPoint2D &point, const TPose2D &newXpose, TPoint2D &newPoint)
Uses the given pose 2D to project a point into a new base.
Definition: geometry.cpp:1152
bool isLine() const
Checks whether content is a line.
Definition: TObject3D.h:103
void createFromPoseZ(const mrpt::math::TPose3D &p, TLine3D &r)
Gets a 3D line corresponding to the Z axis in a given pose.
Definition: geometry.cpp:927
void createPlaneFromPoseYZ(const mrpt::math::TPose3D &pose, TPlane &plane)
Given a pose, creates a plane orthogonal to its X vector.
Definition: geometry.cpp:2041
TCommonRegion * common
Definition: geometry.cpp:1354
void createFromPoseAndAxis(const TPose3D &p, TLine3D &r, size_t axis)
Definition: geometry.cpp:905
bool areAligned(const std::vector< TPoint2D > &points)
Checks whether this set of points acceptably fits a 2D line.
Definition: geometry.cpp:990
bool compatibleBounds(const TPoint3D &min1, const TPoint3D &max1, const TPoint3D &min2, const TPoint3D &max2)
Definition: geometry.cpp:1593
bool contains(const TPoint2D &point) const
Check whether a point is inside the line.
Definition: TLine2D.cpp:29
TCommonRegion(const TCommonRegion &r)
Definition: geometry.cpp:1346
bool intersectAux(const TPolygon3D &p1, const TPlane &pl1, const TPolygon3D &p2, const TPlane &pl2, TObject3D &obj)
Definition: geometry.cpp:1562
void closestFromPointToSegment(double Px, double Py, double x1, double y1, double x2, double y2, double &out_x, double &out_y)
Computes the closest point from a given point to a segment.
Definition: geometry.cpp:39
static constexpr unsigned char GEOMETRIC_TYPE_SEGMENT
Object type identifier for TSegment2D or TSegment3D.
Definition: TPoseOrPoint.h:115
TTempIntersection(const TTempIntersection &t)
Definition: geometry.cpp:1393
bool contains(const TPoint3D &point) const
Check whether a point is contained into the plane.
Definition: TPlane.cpp:28
double distance(const TPoint3D &point) const
Distance between the line and a point.
Definition: TLine3D.cpp:40
TPlane plane
Plane containing the polygon.
void AddVertex(double x, double y)
Add a new vertex to polygon.
Definition: CPolygon.h:28
double minimumDistanceFromPointToSegment(const double Px, const double Py, const double x1, const double y1, const double x2, const double y2, T &out_x, T &out_y)
Computes the closest point from a given point to a segment, and returns that minimum distance...
Definition: geometry.h:934
std::array< double, 4 > coefs
Plane coefficients, stored as an array: .
Definition: TPlane.h:26
bool intersect(const TSegment3D &s1, const TSegment3D &s2, TObject3D &obj)
Gets the intersection between two 3D segments.
Definition: geometry.cpp:617
bool getPlane(TPlane &p) const
Gets a plane which contains the polygon.
Definition: TPolygon3D.cpp:76
unsigned char type
Definition: geometry.cpp:1351
double phi
Orientation (rads)
Definition: TPose2D.h:32
TCommonRegion(const TSegment2D &s)
Definition: geometry.cpp:1326
bool contains(const TPoint3D &point) const
Check whether a point is inside (or within geometryEpsilon of a polygon edge).
Definition: TPolygon3D.cpp:43
static constexpr unsigned char GEOMETRIC_TYPE_LINE
Object type identifier for TLine2D or TLine3D.
Definition: TPoseOrPoint.h:120
2D polygon, inheriting from std::vector<TPoint2D>.
Definition: TPolygon2D.h:21
3D polygon, inheriting from std::vector<TPoint3D>
Definition: TPolygon3D.h:20
double distance(const TPoint2D &p1, const TPoint2D &p2)
Gets the distance between two points in a 2D space.
Definition: geometry.cpp:1871
void getMinAndMaxBounds(const std::vector< TPolygon3D > &v1, std::vector< TPoint3D > &minP, std::vector< TPoint3D > &maxP)
Definition: geometry.cpp:1625
TSegment2D * segment
Definition: geometry.cpp:1310
double distancePointToPolygon2D(double px, double py, unsigned int polyEdges, const double *poly_xs, const double *poly_ys)
Returns the closest distance of a given 2D point to a polygon, or "0" if the point is INTO the polygo...
Definition: geometry.cpp:264
3D line, represented by a base point and a director vector.
Definition: TLine3D.h:19
#define MRPT_UNUSED_PARAM(a)
Determines whether this is an X86 or AMD64 platform.
Definition: common.h:186
static struct FontData data
Definition: gltext.cpp:144
2D line without bounds, represented by its equation .
Definition: TLine2D.h:19



Page generated by Doxygen 1.8.14 for MRPT 1.9.9 Git: 3a26b90fd Wed Mar 25 20:17:03 2020 +0100 at miƩ mar 25 23:05:41 CET 2020