distance_calculations.h
Go to the documentation of this file.
00001 /*********************************************************************
00002  *
00003  * Software License Agreement (BSD License)
00004  *
00005  *  Copyright (c) 2016,
00006  *  TU Dortmund - Institute of Control Theory and Systems Engineering.
00007  *  All rights reserved.
00008  *
00009  *  Redistribution and use in source and binary forms, with or without
00010  *  modification, are permitted provided that the following conditions
00011  *  are met:
00012  *
00013  *   * Redistributions of source code must retain the above copyright
00014  *     notice, this list of conditions and the following disclaimer.
00015  *   * Redistributions in binary form must reproduce the above
00016  *     copyright notice, this list of conditions and the following
00017  *     disclaimer in the documentation and/or other materials provided
00018  *     with the distribution.
00019  *   * Neither the name of the institute nor the names of its
00020  *     contributors may be used to endorse or promote products derived
00021  *     from this software without specific prior written permission.
00022  *
00023  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00024  *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00025  *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00026  *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
00027  *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00028  *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00029  *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00030  *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00031  *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00032  *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
00033  *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00034  *  POSSIBILITY OF SUCH DAMAGE.
00035  *
00036  * Author: Christoph Rösmann
00037  *********************************************************************/
00038 
00039 #ifndef DISTANCE_CALCULATIONS_H
00040 #define DISTANCE_CALCULATIONS_H
00041 
00042 #include <Eigen/Core>
00043 #include <teb_local_planner/misc.h>
00044 
00045 
00046 namespace teb_local_planner
00047 {
00048   
00050 typedef std::vector< Eigen::Vector2d, Eigen::aligned_allocator<Eigen::Vector2d> > Point2dContainer;
00051 
00052   
00060 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)
00061 {
00062   Eigen::Vector2d diff = line_end - line_start;
00063   double sq_norm = diff.squaredNorm();
00064   
00065   if (sq_norm == 0)
00066     return line_start;
00067 
00068   double u = ((point.x() - line_start.x()) * diff.x() + (point.y() - line_start.y())*diff.y()) / sq_norm;
00069   
00070   if (u <= 0) return line_start;
00071   else if (u >= 1) return line_end;
00072   
00073   return line_start + u*diff;
00074 }
00075   
00083 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)
00084 {
00085   return  (point - closest_point_on_line_segment_2d(point, line_start, line_end)).norm(); 
00086 }
00087   
00097 inline bool check_line_segments_intersection_2d(const Eigen::Ref<const Eigen::Vector2d>& line1_start, const Eigen::Ref<const Eigen::Vector2d>& line1_end, 
00098                                                 const Eigen::Ref<const Eigen::Vector2d>& line2_start, const Eigen::Ref<const Eigen::Vector2d>& line2_end, Eigen::Vector2d* intersection = NULL)
00099 {
00100   // http://stackoverflow.com/questions/563198/how-do-you-detect-where-two-line-segments-intersect
00101   double s_numer, t_numer, denom, t;
00102   Eigen::Vector2d line1 = line1_end - line1_start;
00103   Eigen::Vector2d line2 = line2_end - line2_start;
00104   
00105   denom = line1.x() * line2.y() - line2.x() * line1.y();
00106   if (denom == 0) return false; // Collinear
00107   bool denomPositive = denom > 0;
00108 
00109   Eigen::Vector2d aux = line1_start - line2_start;
00110   
00111   s_numer = line1.x() * aux.y() - line1.y() * aux.x();
00112   if ((s_numer < 0) == denomPositive)  return false; // No collision
00113 
00114   t_numer = line2.x() * aux.y() - line2.y() * aux.x();
00115   if ((t_numer < 0) == denomPositive)  return false; // No collision
00116 
00117   if (((s_numer > denom) == denomPositive) || ((t_numer > denom) == denomPositive)) return false; // No collision
00118   
00119   // Otherwise collision detected
00120   t = t_numer / denom;
00121   if (intersection)
00122   {
00123     *intersection = line1_start + t * line1;
00124   }
00125 
00126   return true;
00127 }
00128   
00129   
00138 inline double distance_segment_to_segment_2d(const Eigen::Ref<const Eigen::Vector2d>& line1_start, const Eigen::Ref<const Eigen::Vector2d>& line1_end, 
00139                                              const Eigen::Ref<const Eigen::Vector2d>& line2_start, const Eigen::Ref<const Eigen::Vector2d>& line2_end)
00140 {
00141   // TODO more efficient implementation
00142   
00143   // check if segments intersect
00144   if (check_line_segments_intersection_2d(line1_start, line1_end, line2_start, line2_end))
00145     return 0;
00146   
00147   // check all 4 combinations
00148   std::array<double,4> distances;
00149   
00150   distances[0] = distance_point_to_segment_2d(line1_start, line2_start, line2_end);
00151   distances[1] = distance_point_to_segment_2d(line1_end, line2_start, line2_end);
00152   distances[2] = distance_point_to_segment_2d(line2_start, line1_start, line1_end);
00153   distances[3] = distance_point_to_segment_2d(line2_end, line1_start, line1_end);
00154   
00155   return *std::min_element(distances.begin(), distances.end());
00156 }
00157   
00158   
00165 inline double distance_point_to_polygon_2d(const Eigen::Vector2d& point, const Point2dContainer& vertices)
00166 {
00167   double dist = HUGE_VAL;
00168     
00169   // the polygon is a point
00170   if (vertices.size() == 1)
00171   {
00172     return (point - vertices.front()).norm();
00173   }
00174     
00175   // check each polygon edge
00176   for (int i=0; i<(int)vertices.size()-1; ++i)
00177   {
00178       double new_dist = distance_point_to_segment_2d(point, vertices.at(i), vertices.at(i+1));
00179 //       double new_dist = calc_distance_point_to_segment( position,  vertices.at(i), vertices.at(i+1));
00180       if (new_dist < dist)
00181         dist = new_dist;
00182   }
00183 
00184   if (vertices.size()>2) // if not a line close polygon
00185   {
00186     double new_dist = distance_point_to_segment_2d(point, vertices.back(), vertices.front()); // check last edge
00187     if (new_dist < dist)
00188       return new_dist;
00189   }
00190   
00191   return dist;
00192 }  
00193 
00201 inline double distance_segment_to_polygon_2d(const Eigen::Vector2d& line_start, const Eigen::Vector2d& line_end, const Point2dContainer& vertices)
00202 {
00203   double dist = HUGE_VAL;
00204     
00205   // the polygon is a point
00206   if (vertices.size() == 1)
00207   {
00208     return distance_point_to_segment_2d(vertices.front(), line_start, line_end);
00209   }
00210     
00211   // check each polygon edge
00212   for (int i=0; i<(int)vertices.size()-1; ++i)
00213   {
00214       double new_dist = distance_segment_to_segment_2d(line_start, line_end, vertices.at(i), vertices.at(i+1));
00215 //       double new_dist = calc_distance_point_to_segment( position,  vertices.at(i), vertices.at(i+1));
00216       if (new_dist < dist)
00217         dist = new_dist;
00218   }
00219 
00220   if (vertices.size()>2) // if not a line close polygon
00221   {
00222     double new_dist = distance_segment_to_segment_2d(line_start, line_end, vertices.back(), vertices.front()); // check last edge
00223     if (new_dist < dist)
00224       return new_dist;
00225   }
00226   
00227   return dist;
00228 }
00229 
00236 inline double distance_polygon_to_polygon_2d(const Point2dContainer& vertices1, const Point2dContainer& vertices2)
00237 {
00238   double dist = HUGE_VAL;
00239     
00240   // the polygon1 is a point
00241   if (vertices1.size() == 1)
00242   {
00243     return distance_point_to_polygon_2d(vertices1.front(), vertices2);
00244   }
00245     
00246   // check each edge of polygon1
00247   for (int i=0; i<(int)vertices1.size()-1; ++i)
00248   {
00249       double new_dist = distance_segment_to_polygon_2d(vertices1[i], vertices1[i+1], vertices2);
00250       if (new_dist < dist)
00251         dist = new_dist;
00252   }
00253 
00254   if (vertices1.size()>2) // if not a line close polygon1
00255   {
00256     double new_dist = distance_segment_to_polygon_2d(vertices1.back(), vertices1.front(), vertices2); // check last edge
00257     if (new_dist < dist)
00258       return new_dist;
00259   }
00260 
00261   return dist;
00262 }
00263   
00264   
00265   
00266   
00267 // Further distance calculations:
00268 
00269 
00270 // The Distance Calculations are mainly copied from http://geomalgorithms.com/a07-_distance.html
00271 // Copyright 2001 softSurfer, 2012 Dan Sunday
00272 // This code may be freely used and modified for any purpose
00273 // providing that this copyright notice is included with it.
00274 // SoftSurfer makes no warranty for this code, and cannot be held
00275 // liable for any real or imagined damage resulting from its use.
00276 // Users of this code must verify correctness for their application.
00277 
00278 inline double calc_distance_line_to_line_3d(const Eigen::Ref<const Eigen::Vector3d>& x1, Eigen::Ref<const Eigen::Vector3d>& u,
00279               const Eigen::Ref<const Eigen::Vector3d>& x2, Eigen::Ref<const Eigen::Vector3d>& v)
00280 {
00281   Eigen::Vector3d   w = x2 - x1;
00282   double a = u.squaredNorm();         // dot(u,u) always >= 0
00283   double b = u.dot(v);
00284   double c = v.squaredNorm();         // dot(v,v) always >= 0
00285   double d = u.dot(w);
00286   double e = v.dot(w);
00287   double D = a*c - b*b;        // always >= 0
00288   double sc, tc;
00289 
00290   // compute the line parameters of the two closest points
00291   if (D < SMALL_NUM) {          // the lines are almost parallel
00292     sc = 0.0;
00293     tc = (b>c ? d/b : e/c);    // use the largest denominator
00294   }
00295   else {
00296     sc = (b*e - c*d) / D;
00297     tc = (a*e - b*d) / D;
00298   }
00299 
00300   // get the difference of the two closest points
00301   Eigen::Vector3d dP = w + (sc * u) - (tc * v);  // =  L1(sc) - L2(tc)
00302 
00303   return dP.norm();   // return the closest distance
00304 }
00305 
00306 
00307 
00308 
00309 
00310 inline double calc_distance_segment_to_segment3D(const Eigen::Ref<const Eigen::Vector3d>& line1_start, Eigen::Ref<const Eigen::Vector3d>& line1_end,
00311              const Eigen::Ref<const Eigen::Vector3d>& line2_start, Eigen::Ref<const Eigen::Vector3d>& line2_end)
00312 {
00313   Eigen::Vector3d u = line1_end - line1_start;
00314   Eigen::Vector3d v = line2_end - line2_start;
00315   Eigen::Vector3d w = line2_start - line1_start;
00316   double a = u.squaredNorm();         // dot(u,u) always >= 0
00317   double b = u.dot(v);
00318   double c = v.squaredNorm();         // dot(v,v) always >= 0
00319   double d = u.dot(w);
00320   double e = v.dot(w);
00321   double D = a*c - b*b;        // always >= 0
00322   double sc, sN, sD = D;       // sc = sN / sD, default sD = D >= 0
00323   double tc, tN, tD = D;       // tc = tN / tD, default tD = D >= 0
00324 
00325   // compute the line parameters of the two closest points
00326   if (D < SMALL_NUM) 
00327   { // the lines are almost parallel
00328     sN = 0.0;         // force using point P0 on segment S1
00329     sD = 1.0;         // to prevent possible division by 0.0 later
00330     tN = e;
00331     tD = c;
00332   }
00333   else 
00334   {       // get the closest points on the infinite lines
00335     sN = (b*e - c*d);
00336     tN = (a*e - b*d);
00337     if (sN < 0.0)
00338     {        // sc < 0 => the s=0 edge is visible
00339       sN = 0.0;
00340       tN = e;
00341       tD = c;
00342     }
00343     else if (sN > sD)
00344     {  // sc > 1  => the s=1 edge is visible
00345       sN = sD;
00346       tN = e + b;
00347       tD = c;
00348     }
00349   }
00350 
00351   if (tN < 0.0) 
00352   {   // tc < 0 => the t=0 edge is visible
00353     tN = 0.0;
00354     // recompute sc for this edge
00355     if (-d < 0.0)
00356       sN = 0.0;
00357     else if (-d > a)
00358       sN = sD;
00359     else 
00360     {
00361       sN = -d;
00362       sD = a;
00363     }
00364   }
00365   else if (tN > tD)
00366   {      // tc > 1  => the t=1 edge is visible
00367     tN = tD;
00368     // recompute sc for this edge
00369     if ((-d + b) < 0.0)
00370       sN = 0;
00371     else if ((-d + b) > a)
00372       sN = sD;
00373     else
00374     {
00375       sN = (-d +  b);
00376       sD = a;
00377     }
00378   }
00379   // finally do the division to get sc and tc
00380   sc = (abs(sN) < SMALL_NUM ? 0.0 : sN / sD);
00381   tc = (abs(tN) < SMALL_NUM ? 0.0 : tN / tD);
00382 
00383   // get the difference of the two closest points
00384   Eigen::Vector3d dP = w + (sc * u) - (tc * v);  // =  S1(sc) - S2(tc)
00385 
00386   return dP.norm();   // return the closest distance
00387 }
00388 
00389 
00390 
00391 
00392 template <typename VectorType>
00393 double calc_closest_point_to_approach_time(const VectorType& x1, const VectorType& vel1, const VectorType& x2, const VectorType& vel2)
00394 {
00395   VectorType dv = vel1 - vel2;
00396 
00397   double dv2 = dv.squaredNorm(); // dot(v,v)
00398   if (dv2 < SMALL_NUM)      // the  tracks are almost parallel
00399     return 0.0;             // any time is ok.  Use time 0.
00400 
00401   VectorType w0 = x1 - x2;
00402   double cpatime = -w0.dot(dv) / dv2;
00403 
00404   return cpatime;             // time of CPA
00405 }
00406 
00407 template <typename VectorType>
00408 double calc_closest_point_to_approach_distance(const VectorType& x1, const VectorType& vel1, const VectorType& x2, const VectorType& vel2, double bound_cpa_time = 0)
00409 {
00410   double ctime = calc_closest_point_to_approach_time<VectorType>(x1, vel1, x2, vel2);
00411   if (bound_cpa_time!=0 && ctime > bound_cpa_time) ctime = bound_cpa_time;
00412   VectorType P1 = x1 + (ctime * vel1);
00413   VectorType P2 = x2 + (ctime * vel2);
00414 
00415   return (P2-P1).norm(); // distance at CPA
00416 }
00417 
00418 
00419 
00420 // dist_Point_to_Line(): get the distance of a point to a line
00421 //     Input:  a Point P and a Line L (in any dimension)
00422 //     Return: the shortest distance from P to L
00423 template <typename VectorType>
00424 double calc_distance_point_to_line( const VectorType& point, const VectorType& line_base, const VectorType& line_dir)
00425 {
00426   VectorType w = point - line_base;
00427 
00428   double c1 = w.dot(line_dir);
00429   double c2 = line_dir.dot(line_dir);
00430   double b = c1 / c2;
00431 
00432   VectorType Pb = line_base + b * line_dir;
00433   return (point-Pb).norm();
00434 }
00435 //===================================================================
00436 
00437 
00438 // dist_Point_to_Segment(): get the distance of a point to a segment
00439 //     Input:  a Point P and a Segment S (in any dimension)
00440 //     Return: the shortest distance from P to S
00441 template <typename VectorType>
00442 double calc_distance_point_to_segment( const VectorType& point, const VectorType& line_start, const VectorType& line_end)
00443 {
00444   VectorType v = line_end - line_start;
00445   VectorType w = point - line_start;
00446 
00447   double c1 = w.dot(v);
00448   if ( c1 <= 0 )
00449     return w.norm();
00450 
00451   double c2 = v.dot(v);
00452   if ( c2 <= c1 )
00453     return (point-line_end).norm();
00454 
00455   double b = c1 / c2;
00456   VectorType Pb = line_start + b * v;
00457   return (point-Pb).norm();
00458 }
00459 
00460   
00461   
00462 } // namespace teb_local_planner
00463 
00464 #endif /* DISTANCE_CALCULATIONS_H */


teb_local_planner
Author(s): Christoph Rösmann
autogenerated on Mon Oct 24 2016 05:31:15