distance_calculations.h
Go to the documentation of this file.
1 /*********************************************************************
2  *
3  * Software License Agreement (BSD License)
4  *
5  * Copyright (c) 2016,
6  * TU Dortmund - Institute of Control Theory and Systems Engineering.
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  *
13  * * Redistributions of source code must retain the above copyright
14  * notice, this list of conditions and the following disclaimer.
15  * * Redistributions in binary form must reproduce the above
16  * copyright notice, this list of conditions and the following
17  * disclaimer in the documentation and/or other materials provided
18  * with the distribution.
19  * * Neither the name of the institute nor the names of its
20  * contributors may be used to endorse or promote products derived
21  * from this software without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
26  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
27  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
28  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
29  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
31  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
33  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34  * POSSIBILITY OF SUCH DAMAGE.
35  *
36  * Author: Christoph Rösmann
37  *********************************************************************/
38 
39 #ifndef DISTANCE_CALCULATIONS_H
40 #define DISTANCE_CALCULATIONS_H
41 
42 #include <Eigen/Core>
43 #include <teb_local_planner/misc.h>
44 
45 
47 {
48 
50 typedef std::vector< Eigen::Vector2d, Eigen::aligned_allocator<Eigen::Vector2d> > Point2dContainer;
51 
52 
60 inline Eigen::Vector2d closest_point_on_line_segment_2d(const Eigen::Ref<const Eigen::Vector2d>& point, const Eigen::Ref<const Eigen::Vector2d>& line_start, const Eigen::Ref<const Eigen::Vector2d>& line_end)
61 {
62  Eigen::Vector2d diff = line_end - line_start;
63  double sq_norm = diff.squaredNorm();
64 
65  if (sq_norm == 0)
66  return line_start;
67 
68  double u = ((point.x() - line_start.x()) * diff.x() + (point.y() - line_start.y())*diff.y()) / sq_norm;
69 
70  if (u <= 0) return line_start;
71  else if (u >= 1) return line_end;
72 
73  return line_start + u*diff;
74 }
75 
83 inline double distance_point_to_segment_2d(const Eigen::Ref<const Eigen::Vector2d>& point, const Eigen::Ref<const Eigen::Vector2d>& line_start, const Eigen::Ref<const Eigen::Vector2d>& line_end)
84 {
85  return (point - closest_point_on_line_segment_2d(point, line_start, line_end)).norm();
86 }
87 
97 inline bool check_line_segments_intersection_2d(const Eigen::Ref<const Eigen::Vector2d>& line1_start, const Eigen::Ref<const Eigen::Vector2d>& line1_end,
98  const Eigen::Ref<const Eigen::Vector2d>& line2_start, const Eigen::Ref<const Eigen::Vector2d>& line2_end, Eigen::Vector2d* intersection = NULL)
99 {
100  // http://stackoverflow.com/questions/563198/how-do-you-detect-where-two-line-segments-intersect
101  double s_numer, t_numer, denom, t;
102  Eigen::Vector2d line1 = line1_end - line1_start;
103  Eigen::Vector2d line2 = line2_end - line2_start;
104 
105  denom = line1.x() * line2.y() - line2.x() * line1.y();
106  if (denom == 0) return false; // Collinear
107  bool denomPositive = denom > 0;
108 
109  Eigen::Vector2d aux = line1_start - line2_start;
110 
111  s_numer = line1.x() * aux.y() - line1.y() * aux.x();
112  if ((s_numer < 0) == denomPositive) return false; // No collision
113 
114  t_numer = line2.x() * aux.y() - line2.y() * aux.x();
115  if ((t_numer < 0) == denomPositive) return false; // No collision
116 
117  if (((s_numer > denom) == denomPositive) || ((t_numer > denom) == denomPositive)) return false; // No collision
118 
119  // Otherwise collision detected
120  t = t_numer / denom;
121  if (intersection)
122  {
123  *intersection = line1_start + t * line1;
124  }
125 
126  return true;
127 }
128 
129 
138 inline double distance_segment_to_segment_2d(const Eigen::Ref<const Eigen::Vector2d>& line1_start, const Eigen::Ref<const Eigen::Vector2d>& line1_end,
139  const Eigen::Ref<const Eigen::Vector2d>& line2_start, const Eigen::Ref<const Eigen::Vector2d>& line2_end)
140 {
141  // TODO more efficient implementation
142 
143  // check if segments intersect
144  if (check_line_segments_intersection_2d(line1_start, line1_end, line2_start, line2_end))
145  return 0;
146 
147  // check all 4 combinations
148  std::array<double,4> distances;
149 
150  distances[0] = distance_point_to_segment_2d(line1_start, line2_start, line2_end);
151  distances[1] = distance_point_to_segment_2d(line1_end, line2_start, line2_end);
152  distances[2] = distance_point_to_segment_2d(line2_start, line1_start, line1_end);
153  distances[3] = distance_point_to_segment_2d(line2_end, line1_start, line1_end);
154 
155  return *std::min_element(distances.begin(), distances.end());
156 }
157 
158 
165 inline double distance_point_to_polygon_2d(const Eigen::Vector2d& point, const Point2dContainer& vertices)
166 {
167  double dist = HUGE_VAL;
168 
169  // the polygon is a point
170  if (vertices.size() == 1)
171  {
172  return (point - vertices.front()).norm();
173  }
174 
175  // check each polygon edge
176  for (int i=0; i<(int)vertices.size()-1; ++i)
177  {
178  double new_dist = distance_point_to_segment_2d(point, vertices.at(i), vertices.at(i+1));
179 // double new_dist = calc_distance_point_to_segment( position, vertices.at(i), vertices.at(i+1));
180  if (new_dist < dist)
181  dist = new_dist;
182  }
183 
184  if (vertices.size()>2) // if not a line close polygon
185  {
186  double new_dist = distance_point_to_segment_2d(point, vertices.back(), vertices.front()); // check last edge
187  if (new_dist < dist)
188  return new_dist;
189  }
190 
191  return dist;
192 }
193 
201 inline double distance_segment_to_polygon_2d(const Eigen::Vector2d& line_start, const Eigen::Vector2d& line_end, const Point2dContainer& vertices)
202 {
203  double dist = HUGE_VAL;
204 
205  // the polygon is a point
206  if (vertices.size() == 1)
207  {
208  return distance_point_to_segment_2d(vertices.front(), line_start, line_end);
209  }
210 
211  // check each polygon edge
212  for (int i=0; i<(int)vertices.size()-1; ++i)
213  {
214  double new_dist = distance_segment_to_segment_2d(line_start, line_end, vertices.at(i), vertices.at(i+1));
215 // double new_dist = calc_distance_point_to_segment( position, vertices.at(i), vertices.at(i+1));
216  if (new_dist < dist)
217  dist = new_dist;
218  }
219 
220  if (vertices.size()>2) // if not a line close polygon
221  {
222  double new_dist = distance_segment_to_segment_2d(line_start, line_end, vertices.back(), vertices.front()); // check last edge
223  if (new_dist < dist)
224  return new_dist;
225  }
226 
227  return dist;
228 }
229 
236 inline double distance_polygon_to_polygon_2d(const Point2dContainer& vertices1, const Point2dContainer& vertices2)
237 {
238  double dist = HUGE_VAL;
239 
240  // the polygon1 is a point
241  if (vertices1.size() == 1)
242  {
243  return distance_point_to_polygon_2d(vertices1.front(), vertices2);
244  }
245 
246  // check each edge of polygon1
247  for (int i=0; i<(int)vertices1.size()-1; ++i)
248  {
249  double new_dist = distance_segment_to_polygon_2d(vertices1[i], vertices1[i+1], vertices2);
250  if (new_dist < dist)
251  dist = new_dist;
252  }
253 
254  if (vertices1.size()>2) // if not a line close polygon1
255  {
256  double new_dist = distance_segment_to_polygon_2d(vertices1.back(), vertices1.front(), vertices2); // check last edge
257  if (new_dist < dist)
258  return new_dist;
259  }
260 
261  return dist;
262 }
263 
264 
265 
266 
267 // Further distance calculations:
268 
269 
270 // The Distance Calculations are mainly copied from http://geomalgorithms.com/a07-_distance.html
271 // Copyright 2001 softSurfer, 2012 Dan Sunday
272 // This code may be freely used and modified for any purpose
273 // providing that this copyright notice is included with it.
274 // SoftSurfer makes no warranty for this code, and cannot be held
275 // liable for any real or imagined damage resulting from its use.
276 // Users of this code must verify correctness for their application.
277 
278 inline double calc_distance_line_to_line_3d(const Eigen::Ref<const Eigen::Vector3d>& x1, Eigen::Ref<const Eigen::Vector3d>& u,
279  const Eigen::Ref<const Eigen::Vector3d>& x2, Eigen::Ref<const Eigen::Vector3d>& v)
280 {
281  Eigen::Vector3d w = x2 - x1;
282  double a = u.squaredNorm(); // dot(u,u) always >= 0
283  double b = u.dot(v);
284  double c = v.squaredNorm(); // dot(v,v) always >= 0
285  double d = u.dot(w);
286  double e = v.dot(w);
287  double D = a*c - b*b; // always >= 0
288  double sc, tc;
289 
290  // compute the line parameters of the two closest points
291  if (D < SMALL_NUM) { // the lines are almost parallel
292  sc = 0.0;
293  tc = (b>c ? d/b : e/c); // use the largest denominator
294  }
295  else {
296  sc = (b*e - c*d) / D;
297  tc = (a*e - b*d) / D;
298  }
299 
300  // get the difference of the two closest points
301  Eigen::Vector3d dP = w + (sc * u) - (tc * v); // = L1(sc) - L2(tc)
302 
303  return dP.norm(); // return the closest distance
304 }
305 
306 
307 
308 
309 
310 inline double calc_distance_segment_to_segment3D(const Eigen::Ref<const Eigen::Vector3d>& line1_start, Eigen::Ref<const Eigen::Vector3d>& line1_end,
311  const Eigen::Ref<const Eigen::Vector3d>& line2_start, Eigen::Ref<const Eigen::Vector3d>& line2_end)
312 {
313  Eigen::Vector3d u = line1_end - line1_start;
314  Eigen::Vector3d v = line2_end - line2_start;
315  Eigen::Vector3d w = line2_start - line1_start;
316  double a = u.squaredNorm(); // dot(u,u) always >= 0
317  double b = u.dot(v);
318  double c = v.squaredNorm(); // dot(v,v) always >= 0
319  double d = u.dot(w);
320  double e = v.dot(w);
321  double D = a*c - b*b; // always >= 0
322  double sc, sN, sD = D; // sc = sN / sD, default sD = D >= 0
323  double tc, tN, tD = D; // tc = tN / tD, default tD = D >= 0
324 
325  // compute the line parameters of the two closest points
326  if (D < SMALL_NUM)
327  { // the lines are almost parallel
328  sN = 0.0; // force using point P0 on segment S1
329  sD = 1.0; // to prevent possible division by 0.0 later
330  tN = e;
331  tD = c;
332  }
333  else
334  { // get the closest points on the infinite lines
335  sN = (b*e - c*d);
336  tN = (a*e - b*d);
337  if (sN < 0.0)
338  { // sc < 0 => the s=0 edge is visible
339  sN = 0.0;
340  tN = e;
341  tD = c;
342  }
343  else if (sN > sD)
344  { // sc > 1 => the s=1 edge is visible
345  sN = sD;
346  tN = e + b;
347  tD = c;
348  }
349  }
350 
351  if (tN < 0.0)
352  { // tc < 0 => the t=0 edge is visible
353  tN = 0.0;
354  // recompute sc for this edge
355  if (-d < 0.0)
356  sN = 0.0;
357  else if (-d > a)
358  sN = sD;
359  else
360  {
361  sN = -d;
362  sD = a;
363  }
364  }
365  else if (tN > tD)
366  { // tc > 1 => the t=1 edge is visible
367  tN = tD;
368  // recompute sc for this edge
369  if ((-d + b) < 0.0)
370  sN = 0;
371  else if ((-d + b) > a)
372  sN = sD;
373  else
374  {
375  sN = (-d + b);
376  sD = a;
377  }
378  }
379  // finally do the division to get sc and tc
380  sc = (abs(sN) < SMALL_NUM ? 0.0 : sN / sD);
381  tc = (abs(tN) < SMALL_NUM ? 0.0 : tN / tD);
382 
383  // get the difference of the two closest points
384  Eigen::Vector3d dP = w + (sc * u) - (tc * v); // = S1(sc) - S2(tc)
385 
386  return dP.norm(); // return the closest distance
387 }
388 
389 
390 
391 
392 template <typename VectorType>
393 double calc_closest_point_to_approach_time(const VectorType& x1, const VectorType& vel1, const VectorType& x2, const VectorType& vel2)
394 {
395  VectorType dv = vel1 - vel2;
396 
397  double dv2 = dv.squaredNorm(); // dot(v,v)
398  if (dv2 < SMALL_NUM) // the tracks are almost parallel
399  return 0.0; // any time is ok. Use time 0.
400 
401  VectorType w0 = x1 - x2;
402  double cpatime = -w0.dot(dv) / dv2;
403 
404  return cpatime; // time of CPA
405 }
406 
407 template <typename VectorType>
408 double calc_closest_point_to_approach_distance(const VectorType& x1, const VectorType& vel1, const VectorType& x2, const VectorType& vel2, double bound_cpa_time = 0)
409 {
410  double ctime = calc_closest_point_to_approach_time<VectorType>(x1, vel1, x2, vel2);
411  if (bound_cpa_time!=0 && ctime > bound_cpa_time) ctime = bound_cpa_time;
412  VectorType P1 = x1 + (ctime * vel1);
413  VectorType P2 = x2 + (ctime * vel2);
414 
415  return (P2-P1).norm(); // distance at CPA
416 }
417 
418 
419 
420 // dist_Point_to_Line(): get the distance of a point to a line
421 // Input: a Point P and a Line L (in any dimension)
422 // Return: the shortest distance from P to L
423 template <typename VectorType>
424 double calc_distance_point_to_line( const VectorType& point, const VectorType& line_base, const VectorType& line_dir)
425 {
426  VectorType w = point - line_base;
427 
428  double c1 = w.dot(line_dir);
429  double c2 = line_dir.dot(line_dir);
430  double b = c1 / c2;
431 
432  VectorType Pb = line_base + b * line_dir;
433  return (point-Pb).norm();
434 }
435 //===================================================================
436 
437 
438 // dist_Point_to_Segment(): get the distance of a point to a segment
439 // Input: a Point P and a Segment S (in any dimension)
440 // Return: the shortest distance from P to S
441 template <typename VectorType>
442 double calc_distance_point_to_segment( const VectorType& point, const VectorType& line_start, const VectorType& line_end)
443 {
444  VectorType v = line_end - line_start;
445  VectorType w = point - line_start;
446 
447  double c1 = w.dot(v);
448  if ( c1 <= 0 )
449  return w.norm();
450 
451  double c2 = v.dot(v);
452  if ( c2 <= c1 )
453  return (point-line_end).norm();
454 
455  double b = c1 / c2;
456  VectorType Pb = line_start + b * v;
457  return (point-Pb).norm();
458 }
459 
460 
461 
462 } // namespace teb_local_planner
463 
464 #endif /* DISTANCE_CALCULATIONS_H */
d
bool check_line_segments_intersection_2d(const Eigen::Ref< const Eigen::Vector2d > &line1_start, const Eigen::Ref< const Eigen::Vector2d > &line1_end, const Eigen::Ref< const Eigen::Vector2d > &line2_start, const Eigen::Ref< const Eigen::Vector2d > &line2_end, Eigen::Vector2d *intersection=NULL)
Helper function to check whether two line segments intersects.
double calc_distance_line_to_line_3d(const Eigen::Ref< const Eigen::Vector3d > &x1, Eigen::Ref< const Eigen::Vector3d > &u, const Eigen::Ref< const Eigen::Vector3d > &x2, Eigen::Ref< const Eigen::Vector3d > &v)
double distance_segment_to_segment_2d(const Eigen::Ref< const Eigen::Vector2d > &line1_start, const Eigen::Ref< const Eigen::Vector2d > &line1_end, const Eigen::Ref< const Eigen::Vector2d > &line2_start, const Eigen::Ref< const Eigen::Vector2d > &line2_end)
Helper function to calculate the smallest distance between two line segments.
double calc_distance_point_to_line(const VectorType &point, const VectorType &line_base, const VectorType &line_dir)
IMETHOD Vector diff(const Vector &p_w_a, const Vector &p_w_b, double dt=1)
std::vector< Eigen::Vector2d, Eigen::aligned_allocator< Eigen::Vector2d > > Point2dContainer
Abbrev. for a container storing 2d points.
#define SMALL_NUM
Definition: misc.h:50
Eigen::Vector2d closest_point_on_line_segment_2d(const Eigen::Ref< const Eigen::Vector2d > &point, const Eigen::Ref< const Eigen::Vector2d > &line_start, const Eigen::Ref< const Eigen::Vector2d > &line_end)
Helper function to obtain the closest point on a line segment w.r.t. a reference point.
double calc_distance_segment_to_segment3D(const Eigen::Ref< const Eigen::Vector3d > &line1_start, Eigen::Ref< const Eigen::Vector3d > &line1_end, const Eigen::Ref< const Eigen::Vector3d > &line2_start, Eigen::Ref< const Eigen::Vector3d > &line2_end)
double distance_point_to_segment_2d(const Eigen::Ref< const Eigen::Vector2d > &point, const Eigen::Ref< const Eigen::Vector2d > &line_start, const Eigen::Ref< const Eigen::Vector2d > &line_end)
Helper function to calculate the distance between a line segment and a point.
double calc_distance_point_to_segment(const VectorType &point, const VectorType &line_start, const VectorType &line_end)
double distance_polygon_to_polygon_2d(const Point2dContainer &vertices1, const Point2dContainer &vertices2)
Helper function to calculate the smallest distance between two closed polygons.
double distance_point_to_polygon_2d(const Eigen::Vector2d &point, const Point2dContainer &vertices)
Helper function to calculate the smallest distance between a point and a closed polygon.
TFSIMD_FORCE_INLINE const tfScalar & w() const
double calc_closest_point_to_approach_time(const VectorType &x1, const VectorType &vel1, const VectorType &x2, const VectorType &vel2)
INLINE Rall1d< T, V, S > abs(const Rall1d< T, V, S > &x)
double distance_segment_to_polygon_2d(const Eigen::Vector2d &line_start, const Eigen::Vector2d &line_end, const Point2dContainer &vertices)
Helper function to calculate the smallest distance between a line segment and a closed polygon...
double calc_closest_point_to_approach_distance(const VectorType &x1, const VectorType &vel1, const VectorType &x2, const VectorType &vel2, double bound_cpa_time=0)


teb_local_planner
Author(s): Christoph Rösmann
autogenerated on Wed Jun 5 2019 19:25:10