00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
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
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;
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;
00113
00114 t_numer = line2.x() * aux.y() - line2.y() * aux.x();
00115 if ((t_numer < 0) == denomPositive) return false;
00116
00117 if (((s_numer > denom) == denomPositive) || ((t_numer > denom) == denomPositive)) return false;
00118
00119
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
00142
00143
00144 if (check_line_segments_intersection_2d(line1_start, line1_end, line2_start, line2_end))
00145 return 0;
00146
00147
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
00170 if (vertices.size() == 1)
00171 {
00172 return (point - vertices.front()).norm();
00173 }
00174
00175
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
00180 if (new_dist < dist)
00181 dist = new_dist;
00182 }
00183
00184 if (vertices.size()>2)
00185 {
00186 double new_dist = distance_point_to_segment_2d(point, vertices.back(), vertices.front());
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
00206 if (vertices.size() == 1)
00207 {
00208 return distance_point_to_segment_2d(vertices.front(), line_start, line_end);
00209 }
00210
00211
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
00216 if (new_dist < dist)
00217 dist = new_dist;
00218 }
00219
00220 if (vertices.size()>2)
00221 {
00222 double new_dist = distance_segment_to_segment_2d(line_start, line_end, vertices.back(), vertices.front());
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
00241 if (vertices1.size() == 1)
00242 {
00243 return distance_point_to_polygon_2d(vertices1.front(), vertices2);
00244 }
00245
00246
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)
00255 {
00256 double new_dist = distance_segment_to_polygon_2d(vertices1.back(), vertices1.front(), vertices2);
00257 if (new_dist < dist)
00258 return new_dist;
00259 }
00260
00261 return dist;
00262 }
00263
00264
00265
00266
00267
00268
00269
00270
00271
00272
00273
00274
00275
00276
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();
00283 double b = u.dot(v);
00284 double c = v.squaredNorm();
00285 double d = u.dot(w);
00286 double e = v.dot(w);
00287 double D = a*c - b*b;
00288 double sc, tc;
00289
00290
00291 if (D < SMALL_NUM) {
00292 sc = 0.0;
00293 tc = (b>c ? d/b : e/c);
00294 }
00295 else {
00296 sc = (b*e - c*d) / D;
00297 tc = (a*e - b*d) / D;
00298 }
00299
00300
00301 Eigen::Vector3d dP = w + (sc * u) - (tc * v);
00302
00303 return dP.norm();
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();
00317 double b = u.dot(v);
00318 double c = v.squaredNorm();
00319 double d = u.dot(w);
00320 double e = v.dot(w);
00321 double D = a*c - b*b;
00322 double sc, sN, sD = D;
00323 double tc, tN, tD = D;
00324
00325
00326 if (D < SMALL_NUM)
00327 {
00328 sN = 0.0;
00329 sD = 1.0;
00330 tN = e;
00331 tD = c;
00332 }
00333 else
00334 {
00335 sN = (b*e - c*d);
00336 tN = (a*e - b*d);
00337 if (sN < 0.0)
00338 {
00339 sN = 0.0;
00340 tN = e;
00341 tD = c;
00342 }
00343 else if (sN > sD)
00344 {
00345 sN = sD;
00346 tN = e + b;
00347 tD = c;
00348 }
00349 }
00350
00351 if (tN < 0.0)
00352 {
00353 tN = 0.0;
00354
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 {
00367 tN = tD;
00368
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
00380 sc = (abs(sN) < SMALL_NUM ? 0.0 : sN / sD);
00381 tc = (abs(tN) < SMALL_NUM ? 0.0 : tN / tD);
00382
00383
00384 Eigen::Vector3d dP = w + (sc * u) - (tc * v);
00385
00386 return dP.norm();
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();
00398 if (dv2 < SMALL_NUM)
00399 return 0.0;
00400
00401 VectorType w0 = x1 - x2;
00402 double cpatime = -w0.dot(dv) / dv2;
00403
00404 return cpatime;
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();
00416 }
00417
00418
00419
00420
00421
00422
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
00439
00440
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 }
00463
00464 #endif