path_ops.cpp
Go to the documentation of this file.
00001 /*
00002  * Software License Agreement (BSD License)
00003  *
00004  *  Copyright (c) 2017, Locus Robotics
00005  *  All rights reserved.
00006  *
00007  *  Redistribution and use in source and binary forms, with or without
00008  *  modification, are permitted provided that the following conditions
00009  *  are met:
00010  *
00011  *   * Redistributions of source code must retain the above copyright
00012  *     notice, this list of conditions and the following disclaimer.
00013  *   * Redistributions in binary form must reproduce the above
00014  *     copyright notice, this list of conditions and the following
00015  *     disclaimer in the documentation and/or other materials provided
00016  *     with the distribution.
00017  *   * Neither the name of the copyright holder nor the names of its
00018  *     contributors may be used to endorse or promote products derived
00019  *     from this software without specific prior written permission.
00020  *
00021  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00022  *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00023  *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00024  *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
00025  *  COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00026  *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00027  *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00028  *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00029  *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00030  *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
00031  *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00032  *  POSSIBILITY OF SUCH DAMAGE.
00033  */
00034 
00035 #include <nav_2d_utils/path_ops.h>
00036 #include <nav_2d_utils/geometry_help.h>
00037 #include <cmath>
00038 #include <vector>
00039 
00040 namespace nav_2d_utils
00041 {
00042 
00043 double poseDistance(const geometry_msgs::Pose2D& pose0, const geometry_msgs::Pose2D& pose1)
00044 {
00045   return hypot(pose0.x - pose1.x, pose0.y - pose1.y);
00046 }
00047 
00048 double getPlanLength(const nav_2d_msgs::Path2D& plan, const unsigned int start_index)
00049 {
00050   double length = 0.0;
00051   for (unsigned int i = start_index + 1; i < plan.poses.size(); i++)
00052   {
00053     length += poseDistance(plan.poses[i - 1], plan.poses[i]);
00054   }
00055   return length;
00056 }
00057 
00058 double getPlanLength(const nav_2d_msgs::Path2D& plan, const geometry_msgs::Pose2D& query_pose)
00059 {
00060   if (plan.poses.size() == 0) return 0.0;
00061 
00062   unsigned int closest_index = 0;
00063   double closest_distance = poseDistance(plan.poses[0], query_pose);
00064   for (unsigned int i = 1; i < plan.poses.size(); i++)
00065   {
00066     double distance = poseDistance(plan.poses[i], query_pose);
00067     if (closest_distance > distance)
00068     {
00069       closest_index = i;
00070       closest_distance = distance;
00071     }
00072   }
00073   return getPlanLength(plan, closest_index);
00074 }
00075 
00076 nav_2d_msgs::Path2D adjustPlanResolution(const nav_2d_msgs::Path2D& global_plan_in, double resolution)
00077 {
00078   nav_2d_msgs::Path2D global_plan_out;
00079   global_plan_out.header = global_plan_in.header;
00080   if (global_plan_in.poses.size() == 0)
00081   {
00082     return global_plan_out;
00083   }
00084 
00085   geometry_msgs::Pose2D last = global_plan_in.poses[0];
00086   global_plan_out.poses.push_back(last);
00087 
00088   double sq_resolution = resolution * resolution;
00089 
00090   for (unsigned int i = 1; i < global_plan_in.poses.size(); ++i)
00091   {
00092     geometry_msgs::Pose2D loop = global_plan_in.poses[i];
00093     double sq_dist = (loop.x - last.x) * (loop.x - last.x) + (loop.y - last.y) * (loop.y - last.y);
00094     if (sq_dist > sq_resolution)
00095     {
00096       // add points in-between
00097       double diff = sqrt(sq_dist) - resolution;
00098       double steps_double = ceil(diff / resolution) + 1.0;
00099       int steps = static_cast<int>(steps_double);
00100 
00101       double delta_x = (loop.x - last.x) / steps_double;
00102       double delta_y = (loop.y - last.y) / steps_double;
00103       double delta_t = (loop.theta - last.theta) / steps_double;
00104 
00105       for (int j = 1; j < steps; ++j)
00106       {
00107         geometry_msgs::Pose2D pose;
00108         pose.x = last.x + j * delta_x;
00109         pose.y = last.y + j * delta_y;
00110         pose.theta = last.theta + j * delta_t;
00111         global_plan_out.poses.push_back(pose);
00112       }
00113     }
00114     global_plan_out.poses.push_back(global_plan_in.poses[i]);
00115     last.x = loop.x;
00116     last.y = loop.y;
00117   }
00118   return global_plan_out;
00119 }
00120 
00121 using PoseList = std::vector<geometry_msgs::Pose2D>;
00122 
00134 PoseList compressPlan(const PoseList& input, unsigned int start_index, unsigned int end_index, double epsilon)
00135 {
00136   // Skip if only two points
00137   if (end_index - start_index <= 1)
00138   {
00139     PoseList::const_iterator first = input.begin() + start_index;
00140     PoseList::const_iterator last = input.begin() + end_index + 1;
00141     return PoseList(first, last);
00142   }
00143 
00144   // Find the point with the maximum distance to the line from start to end
00145   const geometry_msgs::Pose2D& start = input[start_index],
00146                                  end = input[end_index];
00147   double max_distance = 0.0;
00148   unsigned int max_index = 0;
00149   for (unsigned int i = start_index + 1; i < end_index; i++)
00150   {
00151     const geometry_msgs::Pose2D& pose = input[i];
00152     double d = distanceToLine(pose.x, pose.y, start.x, start.y, end.x, end.y);
00153     if (d > max_distance)
00154     {
00155       max_index = i;
00156       max_distance = d;
00157     }
00158   }
00159 
00160   // If max distance is less than epsilon, eliminate all the points between start and end
00161   if (max_distance <= epsilon)
00162   {
00163     PoseList outer;
00164     outer.push_back(start);
00165     outer.push_back(end);
00166     return outer;
00167   }
00168 
00169   // If max distance is greater than epsilon, recursively simplify
00170   PoseList first_part = compressPlan(input, start_index, max_index, epsilon);
00171   PoseList second_part = compressPlan(input, max_index, end_index, epsilon);
00172   first_part.insert(first_part.end(), second_part.begin() + 1, second_part.end());
00173   return first_part;
00174 }
00175 
00176 nav_2d_msgs::Path2D compressPlan(const nav_2d_msgs::Path2D& input_path, double epsilon)
00177 {
00178   nav_2d_msgs::Path2D results;
00179   results.header = input_path.header;
00180   results.poses = compressPlan(input_path.poses, 0, input_path.poses.size() - 1, epsilon);
00181   return results;
00182 }
00183 
00184 void addPose(nav_2d_msgs::Path2D& path, double x, double y, double theta)
00185 {
00186   geometry_msgs::Pose2D pose;
00187   pose.x = x;
00188   pose.y = y;
00189   pose.theta = theta;
00190   path.poses.push_back(pose);
00191 }
00192 }  // namespace nav_2d_utils


nav_2d_utils
Author(s):
autogenerated on Wed Jun 26 2019 20:09:36