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 #include <swri_route_util/util.h>
00030 #include <swri_route_util/route.h>
00031 #include <swri_route_util/route_point.h>
00032
00033 #include <swri_transform_util/frames.h>
00034 #include <swri_transform_util/transform_util.h>
00035
00036 namespace mnm = marti_nav_msgs;
00037 namespace stu = swri_transform_util;
00038
00039 namespace swri_route_util
00040 {
00041 void transform(Route &route,
00042 const stu::Transform &transform,
00043 const std::string &target_frame)
00044 {
00045 for (auto &point : route.points) {
00046 point.setPosition(transform*point.position());
00047 point.setOrientation(transform*point.orientation());
00048 }
00049 route.header.frame_id = target_frame;
00050 }
00051
00052 void projectToXY(Route &route)
00053 {
00054 for (auto &point : route.points) {
00055 point.position().setZ(0.0);
00056
00057
00058 }
00059 }
00060
00061 void fillOrientations(Route &route, const tf::Vector3 &up)
00062 {
00063
00064 if (route.points.size() < 2) {
00065 return;
00066 }
00067
00068 for (size_t i = 0; i < route.points.size(); ++i) {
00069
00070
00071
00072
00073 tf::Vector3 v_prev;
00074 tf::Vector3 v_next;
00075 if (i == 0) {
00076
00077
00078 v_next = route.points[i+1].position() - route.points[i+0].position();
00079 v_prev = v_next;
00080 } else if (i+1 == route.points.size()) {
00081
00082
00083 v_prev = route.points[i+0].position() - route.points[i-1].position();
00084 v_next = v_prev;
00085 } else {
00086 v_prev = route.points[i+0].position() - route.points[i-1].position();
00087 v_next = route.points[i+1].position() - route.points[i+0].position();
00088 }
00089
00090 v_prev.normalize();
00091 v_next.normalize();
00092
00093 tf::Vector3 v_forward = (v_prev+v_next)/2.0;
00094
00095
00096 tf::Vector3 v_left = up.cross(v_forward);
00097
00098
00099
00100
00101 v_left.normalize();
00102
00103
00104
00105
00106
00107 tf::Vector3 v_up = v_forward.cross(v_left);
00108
00109
00110 v_up.normalize();
00111
00112
00113
00114 tf::Matrix3x3 rotation(
00115 v_forward.x(), v_left.x(), v_up.x(),
00116 v_forward.y(), v_left.y(), v_up.y(),
00117 v_forward.z(), v_left.z(), v_up.z());
00118
00119
00120
00121 tf::Quaternion orientation;
00122 rotation.getRotation(orientation);
00123 route.points[i].setOrientation(orientation);
00124
00125
00126 }
00127 }
00128
00129
00130
00131
00132
00133
00134
00135 static
00136 void nearestDistanceToLineSegment(
00137 double &min_distance_from_line,
00138 double &min_distance_on_line,
00139 const tf::Vector3 &p0,
00140 const tf::Vector3 &p1,
00141 const tf::Vector3 &p,
00142 bool extrapolate_start,
00143 bool extrapolate_end)
00144 {
00145 tf::Vector3 v = p1 - p0;
00146 const double v_len_sq = v.dot(v);
00147
00148
00149
00150 double s = 0.0;
00151 if (v_len_sq > 1e-6) {
00152 s = v.dot(p - p0) / v_len_sq;
00153 } else {
00154
00155
00156 s = 1.0;
00157 }
00158
00159
00160
00161 if (!extrapolate_start && s < 0.0) {
00162 s = 0.0;
00163 } else if (!extrapolate_end && s > 1.0) {
00164 s = 1.0;
00165 }
00166
00167 tf::Vector3 x_nearest = p0 + s*v;
00168
00169 min_distance_from_line = x_nearest.distance(p);
00170 min_distance_on_line = s*std::sqrt(v_len_sq);
00171 }
00172
00173 bool projectOntoRoute(mnm::RoutePosition &position,
00174 const Route &route,
00175 const tf::Vector3 &point,
00176 bool extrapolate_before_start,
00177 bool extrapolate_past_end)
00178 {
00179 if (route.points.size() == 0) {
00180
00181 return false;
00182 }
00183
00184 if (route.points.size() == 1) {
00185
00186 position.id = route.points[0].id();
00187 position.distance = 0.0;
00188 return true;
00189 }
00190
00191
00192
00193 double min_distance_from_line = std::numeric_limits<double>::infinity();
00194 double min_distance_on_line = std::numeric_limits<double>::infinity();
00195 size_t min_segment_index = 0;
00196
00197 for (size_t i = 0; i+1 < route.points.size(); ++i) {
00198 double distance_from_line;
00199 double distance_on_line;
00200
00201 nearestDistanceToLineSegment(distance_from_line,
00202 distance_on_line,
00203 route.points[i+0].position(),
00204 route.points[i+1].position(),
00205 point,
00206 false, false);
00207
00208 if (distance_from_line <= min_distance_from_line) {
00209 min_segment_index = i;
00210 min_distance_on_line = distance_on_line;
00211 min_distance_from_line = distance_from_line;
00212 }
00213 }
00214
00215
00216
00217
00218
00219
00220 if (extrapolate_before_start && min_segment_index == 0) {
00221 size_t i = 0;
00222 nearestDistanceToLineSegment(min_distance_from_line,
00223 min_distance_on_line,
00224 route.points[i+0].position(),
00225 route.points[i+1].position(),
00226 point,
00227 true, false);
00228 } else if (min_segment_index + 2 == route.points.size()) {
00229
00230
00231
00232
00233
00234 size_t i = min_segment_index;
00235 nearestDistanceToLineSegment(min_distance_from_line,
00236 min_distance_on_line,
00237 route.points[i+0].position(),
00238 route.points[i+1].position(),
00239 point,
00240 false, true);
00241
00242 double last_length = (route.points[i+1].position() - route.points[i+0].position()).length();
00243 if (min_distance_on_line > last_length) {
00244 min_segment_index++;
00245 min_distance_on_line -= last_length;
00246 }
00247
00248 if (!extrapolate_past_end) {
00249 min_distance_on_line = 0.0;
00250 }
00251 }
00252
00253 position.id = route.points[min_segment_index].id();
00254 position.distance = min_distance_on_line;
00255 return true;
00256 }
00257
00258 bool projectOntoRouteWindow(
00259 mnm::RoutePosition &position,
00260 const Route &route,
00261 const tf::Vector3 &point,
00262 const mnm::RoutePosition &window_start,
00263 const mnm::RoutePosition &window_end)
00264 {
00265 if (route.points.size() < 2) {
00266
00267 return false;
00268 }
00269
00270
00271 mnm::RoutePosition start;
00272 if (!normalizeRoutePosition(start, route, window_start)) {
00273 return false;
00274 }
00275 mnm::RoutePosition end;
00276 if (!normalizeRoutePosition(end, route, window_end)) {
00277 return false;
00278 }
00279
00280
00281
00282 if (start.id == end.id && start.distance == end.distance) {
00283 position = start;
00284 return true;
00285 }
00286
00287
00288
00289 size_t start_index;
00290 route.findPointId(start_index, start.id);
00291 size_t end_index;
00292 route.findPointId(end_index, end.id);
00293
00294
00295 if ((end_index < start_index) ||
00296 (start_index == end_index && end.distance < start.distance)) {
00297 std::swap(end, start);
00298 std::swap(start_index, end_index);
00299 }
00300
00301
00302
00303
00304 if (start_index+1 == route.points.size()) {
00305 start_index -= 1;
00306 start.id = route.points[start_index].id();
00307 start.distance += (route.points[start_index+1].position() -
00308 route.points[start_index+0].position()).length();
00309 }
00310 if (end_index+1 == route.points.size()) {
00311 end_index -= 1;
00312 end.id = route.points[end_index].id();
00313 end.distance += (route.points[end_index+1].position() -
00314 route.points[end_index+0].position()).length();
00315 }
00316
00317
00318
00319
00320 if (start_index == end_index) {
00321 double distance_from_line;
00322 double distance_on_line;
00323
00324 nearestDistanceToLineSegment(distance_from_line,
00325 distance_on_line,
00326 route.points[start_index+0].position(),
00327 route.points[start_index+1].position(),
00328 point,
00329 true, true);
00330
00331 if (distance_on_line < start.distance) {
00332 distance_on_line = start.distance;
00333 } else if (distance_on_line > end.distance) {
00334 distance_on_line = end.distance;
00335 }
00336
00337 mnm::RoutePosition denormal_position;
00338 denormal_position.id = start.id;
00339 denormal_position.distance = distance_on_line;
00340 if (!normalizeRoutePosition(position, route, denormal_position)) {
00341 return false;
00342 }
00343 return true;
00344 }
00345
00346
00347
00348 double min_distance_from_line = std::numeric_limits<double>::infinity();
00349 double min_distance_on_line = std::numeric_limits<double>::infinity();
00350 size_t min_segment_index = 0;
00351
00352 for (size_t i = start_index; i <= end_index; ++i) {
00353 double distance_from_line;
00354 double distance_on_line;
00355
00356 nearestDistanceToLineSegment(distance_from_line,
00357 distance_on_line,
00358 route.points[i+0].position(),
00359 route.points[i+1].position(),
00360 point,
00361 false, false);
00362
00363 if (distance_from_line <= min_distance_from_line) {
00364 min_segment_index = i;
00365 min_distance_on_line = distance_on_line;
00366 min_distance_from_line = distance_from_line;
00367 }
00368 }
00369
00370
00371
00372 if (min_segment_index == start_index) {
00373 nearestDistanceToLineSegment(min_distance_from_line,
00374 min_distance_on_line,
00375 route.points[min_segment_index+0].position(),
00376 route.points[min_segment_index+1].position(),
00377 point,
00378 true, false);
00379 if (min_distance_on_line < start.distance) {
00380 min_distance_on_line = start.distance;
00381 }
00382 } else if (min_segment_index == end_index) {
00383 nearestDistanceToLineSegment(min_distance_from_line,
00384 min_distance_on_line,
00385 route.points[min_segment_index+0].position(),
00386 route.points[min_segment_index+1].position(),
00387 point,
00388 false, true);
00389 if (min_distance_on_line > end.distance) {
00390 min_distance_on_line = end.distance;
00391 }
00392 }
00393
00394 mnm::RoutePosition denormal_position;
00395 denormal_position.id = route.points[min_segment_index].id();
00396 denormal_position.distance = min_distance_on_line;
00397 if (!normalizeRoutePosition(position, route, denormal_position)) {
00398 return false;
00399 }
00400
00401 return true;
00402 }
00403
00404 static
00405 void interpolateRouteSegment(
00406 RoutePoint &dst,
00407 const RoutePoint &p0,
00408 const RoutePoint &p1,
00409 double distance)
00410 {
00411 double len = (p0.position()-p1.position()).length();
00412
00413 double s;
00414 if (len > 1e-6) {
00415 s = distance / len;
00416 } else {
00417
00418
00419 if (distance < 0) {
00420
00421
00422 s = 0.0;
00423 } else if (distance > 1) {
00424
00425
00426 s = 1.0;
00427 } else {
00428
00429 s = 0.5;
00430 }
00431 }
00432
00433 dst.setPosition((1.0-s)*p0.position() + s*p1.position());
00434 dst.setOrientation(p0.orientation().slerp(p1.orientation(), s));
00435
00436
00437 }
00438
00439 bool normalizeRoutePosition(mnm::RoutePosition &normalized_position,
00440 const Route &route,
00441 const mnm::RoutePosition &position)
00442 {
00443 size_t index;
00444 if (!route.findPointId(index, position.id)) {
00445 return false;
00446 }
00447
00448 double distance = position.distance;
00449 while (distance < 0.0) {
00450
00451 if (index == 0) {
00452 break;
00453 }
00454
00455
00456
00457 distance += (route.points[index-0].position() -
00458 route.points[index-1].position()).length();
00459 index--;
00460 }
00461
00462 while (distance > 0.0) {
00463
00464 if (index+1 == route.points.size()) {
00465 break;
00466 }
00467
00468 double segment_length = (route.points[index+0].position() -
00469 route.points[index+1].position()).length();
00470 if (distance > segment_length) {
00471
00472
00473 distance -= segment_length;
00474 index++;
00475 } else {
00476
00477
00478 break;
00479 }
00480 }
00481
00482 normalized_position.distance = distance;
00483 normalized_position.id = route.points[index].id();
00484 return true;
00485 }
00486
00487
00488 bool interpolateRoutePosition(RoutePoint &dst,
00489 const Route &route,
00490 const mnm::RoutePosition &position,
00491 bool allow_extrapolation)
00492 {
00493 mnm::RoutePosition norm_position;
00494 if (!normalizeRoutePosition(norm_position, route, position)) {
00495 return false;
00496 }
00497
00498
00499 size_t index;
00500 route.findPointId(index, norm_position.id);
00501
00502
00503 if (index == 0 && norm_position.distance < 0.0) {
00504 if (!allow_extrapolation) {
00505 return false;
00506 }
00507
00508 if (route.points.size() < 2) {
00509
00510
00511 return false;
00512 }
00513
00514 interpolateRouteSegment(dst,
00515 route.points[0],
00516 route.points[1],
00517 norm_position.distance);
00518 return true;
00519 }
00520
00521
00522 if (index+1 == route.points.size() && norm_position.distance > 0.0) {
00523 if (!allow_extrapolation) {
00524 return false;
00525 }
00526 if (route.points.size() < 2) {
00527
00528
00529 return false;
00530 }
00531
00532 const RoutePoint &p0 = route.points[index-1];
00533 const RoutePoint &p1 = route.points[index-0];
00534 double extra_dist = (p1.position() - p0.position()).length();
00535
00536 interpolateRouteSegment(dst,
00537 p0,
00538 p1,
00539 norm_position.distance + extra_dist);
00540 return true;
00541 }
00542
00543 interpolateRouteSegment(dst,
00544 route.points[index+0],
00545 route.points[index+1],
00546 norm_position.distance);
00547 return true;
00548 }
00549
00550 bool routeDistance(
00551 double &distance,
00552 const mnm::RoutePosition &start,
00553 const mnm::RoutePosition &end,
00554 const Route &route)
00555 {
00556 size_t start_index;
00557 if (!route.findPointId(start_index, start.id)) {
00558 return false;
00559 }
00560
00561 size_t end_index;
00562 if (!route.findPointId(end_index, end.id)) {
00563 return false;
00564 }
00565
00566 size_t min_index = std::min(start_index, end_index);
00567 size_t max_index = std::max(start_index, end_index);
00568
00569 double d = 0.0;
00570 if (route.header.frame_id == stu::_wgs84_frame) {
00571 for (size_t i = min_index; i < max_index; i++) {
00572 d += stu::GreatCircleDistance(route.points[i+1].position(), route.points[i].position());
00573 }
00574 } else {
00575 for (size_t i = min_index; i < max_index; i++) {
00576 d += (route.points[i+1].position() - route.points[i].position()).length();
00577 }
00578 }
00579
00580 if (end_index < start_index) {
00581 d = -d;
00582 }
00583
00584 distance = d + end.distance - start.distance;
00585 return true;
00586 }
00587
00588 bool routeDistances(
00589 std::vector<double> &distances,
00590 const mnm::RoutePosition &start,
00591 const std::vector<mnm::RoutePosition> &ends,
00592 const Route &route)
00593 {
00594 size_t start_index;
00595 if (!route.findPointId(start_index, start.id)) {
00596
00597 return false;
00598 }
00599
00600
00601
00602 size_t min_index = start_index;
00603 size_t max_index = start_index;
00604 std::vector<int> indices;
00605 indices.resize(ends.size());
00606 for (size_t i = 0; i < ends.size(); ++i) {
00607 size_t pt_index;
00608 if (route.findPointId(pt_index, ends[i].id)) {
00609 indices[i] = pt_index;
00610 min_index = std::min(min_index, pt_index);
00611 max_index = std::max(max_index, pt_index);
00612 } else {
00613 indices[i] = -1;
00614 }
00615 }
00616
00617
00618 const size_t roi_start_index = start_index - min_index;
00619
00620
00621
00622
00623 std::vector<double> arc_lengths;
00624 arc_lengths.resize(max_index-min_index+1);
00625
00626 arc_lengths[roi_start_index] = 0.0;
00627 if (route.header.frame_id == stu::_wgs84_frame) {
00628
00629 for (size_t rev_i = 1; rev_i <= roi_start_index; ++rev_i) {
00630 const size_t i = roi_start_index - rev_i;
00631 const tf::Vector3 pt1 = route.points[min_index+i].position();
00632 const tf::Vector3 pt2 = route.points[min_index+i+1].position();
00633 arc_lengths[i] = arc_lengths[i+1] - stu::GreatCircleDistance(pt1, pt2);
00634 }
00635
00636 for (size_t i = roi_start_index+1; i < arc_lengths.size(); ++i) {
00637 const tf::Vector3 pt1 = route.points[min_index+i].position();
00638 const tf::Vector3 pt2 = route.points[min_index+i-1].position();
00639 arc_lengths[i] = arc_lengths[i-1] + stu::GreatCircleDistance(pt1, pt2);
00640 }
00641 } else {
00642
00643
00644 for (size_t rev_i = 1; rev_i <= roi_start_index; ++rev_i) {
00645 const size_t i = roi_start_index - rev_i;
00646 const tf::Vector3 pt1 = route.points[min_index+i].position();
00647 const tf::Vector3 pt2 = route.points[min_index+i+1].position();
00648 arc_lengths[i] = arc_lengths[i+1] - (pt2-pt1).length();
00649 }
00650
00651 for (size_t i = roi_start_index+1; i < arc_lengths.size(); ++i) {
00652 const tf::Vector3 pt1 = route.points[min_index+i].position();
00653 const tf::Vector3 pt2 = route.points[min_index+i-1].position();
00654 arc_lengths[i] = arc_lengths[i-1] + (pt2-pt1).length();
00655 }
00656 }
00657
00658
00659 distances.resize(ends.size());
00660 for (size_t i = 0; i < distances.size(); ++i) {
00661 if (indices[i] < 0) {
00662 distances[i] = std::numeric_limits<double>::quiet_NaN();
00663 continue;
00664 }
00665
00666 const size_t cache_index = indices[i]-min_index;
00667 distances[i] = arc_lengths[cache_index] + ends[i].distance - start.distance;
00668 }
00669
00670 return true;
00671 }
00672
00673 bool extractSubroute(
00674 Route &sub_route,
00675 const Route &route,
00676 const marti_nav_msgs::RoutePosition &start,
00677 const marti_nav_msgs::RoutePosition &end)
00678 {
00679 sub_route.header = route.header;
00680 sub_route.properties_ = route.properties_;
00681 sub_route.guid_ = route.guid_;
00682 sub_route.name_ = route.name_;
00683
00684 mnm::RoutePosition norm_start;
00685 if (!normalizeRoutePosition(norm_start, route, start)) {
00686 return false;
00687 }
00688
00689 mnm::RoutePosition norm_end;
00690 if (!normalizeRoutePosition(norm_end, route, end)) {
00691 return false;
00692 }
00693
00694
00695 size_t start_index;
00696 route.findPointId(start_index, norm_start.id);
00697
00698 size_t end_index;
00699 route.findPointId(end_index, norm_end.id);
00700
00701
00702
00703 if (norm_end.distance > 0.0) {
00704 end_index += 1;
00705 }
00706
00707
00708
00709 end_index++;
00710 end_index = std::min(end_index, route.points.size());
00711
00712 if (end_index <= start_index)
00713 {
00714 sub_route.points.clear();
00715 sub_route.rebuildPointIndex();
00716 return true;
00717 }
00718
00719 sub_route.points.reserve(end_index - start_index);
00720 for (size_t i = start_index; i < end_index; i++) {
00721 sub_route.points.push_back(route.points[i]);
00722 }
00723 sub_route.rebuildPointIndex();
00724
00725 return true;
00726 }
00727 }