util.cpp
Go to the documentation of this file.
00001 // *****************************************************************************
00002 //
00003 // Copyright (c) 2016, Southwest Research Institute® (SwRI®)
00004 // All rights reserved.
00005 //
00006 // Redistribution and use in source and binary forms, with or without
00007 // modification, are permitted provided that the following conditions are met:
00008 //     * Redistributions of source code must retain the above copyright
00009 //       notice, this list of conditions and the following disclaimer.
00010 //     * Redistributions in binary form must reproduce the above copyright
00011 //       notice, this list of conditions and the following disclaimer in the
00012 //       documentation and/or other materials provided with the distribution.
00013 //     * Neither the name of Southwest Research Institute® (SwRI®) nor the
00014 //       names of its contributors may be used to endorse or promote products
00015 //       derived from this software without specific prior written permission.
00016 //
00017 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00018 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00019 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00020 // ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
00021 // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00022 // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00023 // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
00024 // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00025 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00026 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
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     // todo(exjohnson): if orientation is valid, project it to a
00057     // rotation around the Z axis only.
00058   }
00059 }
00060 
00061 void fillOrientations(Route &route, const tf::Vector3 &up)
00062 {
00063   // We can't estimate any orientations for 0 or 1 points.
00064   if (route.points.size() < 2) {
00065     return;
00066   }
00067   
00068   for (size_t i = 0; i < route.points.size(); ++i) {
00069     // We're going to estimate the orientation at this point by
00070     // getting the vector from the previous point and the vector to
00071     // the next point, averaging them together to get a new forward
00072     // vector.
00073     tf::Vector3 v_prev;
00074     tf::Vector3 v_next;
00075     if (i == 0) {
00076       // For the first point, we use v_next for both vectors so the
00077       // average is just v_next.
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       // For the last point, we use v_prev for both vectors so the
00082       // average is just v_prev.
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     // Y = Z x X
00096     tf::Vector3 v_left = up.cross(v_forward);
00097     // Since Z and X were not orthogonal, we need to normalize this to
00098     // get a unit vector.  This is where we'll have problems if our
00099     // v_forward happens to be really closely aligned with the up
00100     // axis.  We ignore that.
00101     v_left.normalize();
00102 
00103     // We now have left unit vector that is perpendicular to the
00104     // forward unit vector, so we can find our actual up vector, which
00105     // should be in the plane spanned by v_forward and the user
00106     // provided up direction.
00107     tf::Vector3 v_up = v_forward.cross(v_left);
00108     // We shouldn't need to normalize v_up, but it's good practice
00109     // since I don't know if the Matrix3x3 handles errors well.
00110     v_up.normalize();
00111 
00112     // Don't understand why Matrix3x3 doesn't have a constructor for 3
00113     // vectors.
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     // Finally we can extract the orientation as a quaternion from the
00120     // matrix.
00121     tf::Quaternion orientation;
00122     rotation.getRotation(orientation);
00123     route.points[i].setOrientation(orientation);
00124 
00125     // There is probably a simpler, more elegant way to do this.
00126   }
00127 }
00128 
00129 // This is a private helper function that finds the nearest distance
00130 // between a point p and the line segment defined by p0 ad p1.  It
00131 // also returns the distance along the segment to the point that is
00132 // nearest to p.  If extrapolate_start/extrapolate_end are true, the
00133 // calculation considers the line segment to extend infinitely in the
00134 // corresponding directions. 
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   // s will be the normalized distance along v that is closest to the
00149   // desired point.
00150   double s = 0.0;
00151   if (v_len_sq > 1e-6) {
00152     s = v.dot(p - p0) / v_len_sq;
00153   } else {
00154     // The two points are too close to define a reasonable line
00155     // segment, so just pick p1 as the closest point.
00156     s = 1.0;
00157   }
00158 
00159   // If we don't allow extrapolation and the nearest point is beyond
00160   // the line segment boundaries, we need to clamp to the boundary.
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     // We can't do anything with this.
00181     return false;
00182   }
00183 
00184   if (route.points.size() == 1) {
00185     // We can't do much with this.
00186     position.id = route.points[0].id();
00187     position.distance = 0.0;
00188     return true;
00189   }
00190   
00191   // First we find the nearest point on the route, without allowing
00192   // extrapolation.
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   // If the nearest segment is the first or last segment, we redo
00216   // the search while allowing the segment to be extrapolated
00217   // backward or forward, respectively.  This allows graceful
00218   // operation if the vehicle is past the boundary of the route.
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     // The end of the route is a special case.  If we go past the end,
00230     // we want to return a position with the id of the last point and
00231     // the distance past it.  This annoying complicates things in a
00232     // number of places, but makes it easy to check if a point is past
00233     // the end of a route.    
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     // We can't do anything with this.
00267     return false;
00268   }
00269 
00270   // First we normalize the window boundaries.
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   // Handle the special case where the start and end points are
00281   // identical.
00282   if (start.id == end.id && start.distance == end.distance) {
00283     position = start;
00284     return true;
00285   }
00286 
00287   // Find the indices of the start and end points.  Since we have
00288   // normalized positions, we know they exist in the route.
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   // Fix the ordering so that start comes before end.
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   // If either of the points are past the end of the route, we want to
00302   // back them up to the previous segment to reduce the number of
00303   // special cases we have to handle.
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   // Although it causes a little duplication, it's easier over all to
00318   // explicitly handle the special case where the window is over a
00319   // single segment.
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   // Find the nearest point on the route, without allowing
00347   // extrapolation.
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   // We have identified the closest segment.  We need to clamp it
00371   // to the window boundaries.
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     // This is a degenerate case where the points are too close
00418     // together to define a numerically stable route point.
00419     if (distance < 0) {
00420       // If the distance is negative, the interpolated value will be
00421       // the first route point.
00422       s = 0.0;
00423     } else if (distance > 1) {
00424       // If the distance is positive, the interpolated value will be
00425       // the second route point.
00426       s = 1.0;
00427     } else {
00428       // Otherwise just take the center of the two points.
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   // Interpolate other known properties here.
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     // We can't go past the start of the route.
00451     if (index == 0) {
00452       break;
00453     }
00454     
00455     // The distance is still negative, so we can't be on this
00456     // segment.  Move to the preceding segment.
00457     distance += (route.points[index-0].position() -
00458                  route.points[index-1].position()).length();
00459     index--;
00460   }
00461 
00462   while (distance > 0.0) {
00463     // We can't go past the end of the route.
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       // The distance is greater than this segment length, so we're
00472       // not on this segment.  Move to the following segment.
00473       distance -= segment_length;
00474       index++;
00475     } else {
00476       // The distance is within the length of this segment, so the
00477       // point is on this segment.
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   // Since we have a normalized position, we know it exists in the route.
00499   size_t index;
00500   route.findPointId(index, norm_position.id);
00501 
00502   // Special case when the point is before the start of the route.
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       // This route point is before the start of the route and we
00510       // don't have enough information to extrapolate.
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   // Special case when the point is after the end of the route.
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       // This route point is after the end of the route and we don't
00528       // have enough information to extrapolate.
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     // Without a start index, we can't calculate anything.
00597     return false;
00598   }
00599 
00600   // Find the indices for every point in the route, and the minimum
00601   // and maximum indices that we need to work over (the ROI).
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   // This is the index of the start point in the ROI.
00618   const size_t roi_start_index = start_index - min_index;
00619 
00620   // We calculate the arc length of each point in the ROI relative to
00621   // the start point.  This vector covers the ROI (so it corresponds
00622   // from min_index to max_index)
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     // Calculate the lengths before the start point.
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     // Calculate the lengths after the start point.
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     // Assume Euclidean coordinates.
00643     // Calculate the lengths before the start point.
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     // Calculate the lengths after the start point.
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   // Now we can calculate the distances.
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   // Since we have a normalized position, we know it exists in the route.
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   // If the end distance is after the id point, round up to the next
00702   // point.
00703   if (norm_end.distance > 0.0) {
00704     end_index += 1;
00705   }
00706 
00707   // Increment the end_index so that we can iterate from [start, end),
00708   // and make sure we stay within the array bounds.
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 }  // namespace swri_route_util


swri_route_util
Author(s):
autogenerated on Tue Oct 3 2017 03:19:53