/* * Copyright (c) 2013, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include "nav2_costmap_2d/footprint.hpp" #include #include #include #include #include "geometry_msgs/msg/point32.hpp" #include "nav2_costmap_2d/array_parser.hpp" #include "nav2_costmap_2d/costmap_math.hpp" namespace nav2_costmap_2d { void calculateMinAndMaxDistances( const std::vector & footprint, double & min_dist, double & max_dist) { min_dist = std::numeric_limits::max(); max_dist = 0.0; if (footprint.size() <= 2) { return; } for (unsigned int i = 0; i < footprint.size() - 1; ++i) { // check the distance from the robot center point to the first vertex double vertex_dist = distance(0.0, 0.0, footprint[i].x, footprint[i].y); double edge_dist = distanceToLine( 0.0, 0.0, footprint[i].x, footprint[i].y, footprint[i + 1].x, footprint[i + 1].y); min_dist = std::min(min_dist, std::min(vertex_dist, edge_dist)); max_dist = std::max(max_dist, std::max(vertex_dist, edge_dist)); } // we also need to do the last vertex and the first vertex double vertex_dist = distance(0.0, 0.0, footprint.back().x, footprint.back().y); double edge_dist = distanceToLine( 0.0, 0.0, footprint.back().x, footprint.back().y, footprint.front().x, footprint.front().y); min_dist = std::min(min_dist, std::min(vertex_dist, edge_dist)); max_dist = std::max(max_dist, std::max(vertex_dist, edge_dist)); } geometry_msgs::msg::Point32 toPoint32(geometry_msgs::msg::Point pt) { geometry_msgs::msg::Point32 point32; point32.x = pt.x; point32.y = pt.y; point32.z = pt.z; return point32; } geometry_msgs::msg::Point toPoint(geometry_msgs::msg::Point32 pt) { geometry_msgs::msg::Point point; point.x = pt.x; point.y = pt.y; point.z = pt.z; return point; } geometry_msgs::msg::Polygon toPolygon(std::vector pts) { geometry_msgs::msg::Polygon polygon; for (unsigned int i = 0; i < pts.size(); i++) { polygon.points.push_back(toPoint32(pts[i])); } return polygon; } std::vector toPointVector(geometry_msgs::msg::Polygon::SharedPtr polygon) { std::vector pts; for (unsigned int i = 0; i < polygon->points.size(); i++) { pts.push_back(toPoint(polygon->points[i])); } return pts; } void transformFootprint( double x, double y, double theta, const std::vector & footprint_spec, std::vector & oriented_footprint) { // build the oriented footprint at a given location oriented_footprint.resize(footprint_spec.size()); double cos_th = cos(theta); double sin_th = sin(theta); for (unsigned int i = 0; i < footprint_spec.size(); ++i) { double new_x = x + (footprint_spec[i].x * cos_th - footprint_spec[i].y * sin_th); double new_y = y + (footprint_spec[i].x * sin_th + footprint_spec[i].y * cos_th); geometry_msgs::msg::Point & new_pt = oriented_footprint[i]; new_pt.x = new_x; new_pt.y = new_y; } } void transformFootprint( double x, double y, double theta, const std::vector & footprint_spec, geometry_msgs::msg::PolygonStamped & oriented_footprint) { // build the oriented footprint at a given location oriented_footprint.polygon.points.clear(); double cos_th = cos(theta); double sin_th = sin(theta); for (unsigned int i = 0; i < footprint_spec.size(); ++i) { geometry_msgs::msg::Point32 new_pt; new_pt.x = x + (footprint_spec[i].x * cos_th - footprint_spec[i].y * sin_th); new_pt.y = y + (footprint_spec[i].x * sin_th + footprint_spec[i].y * cos_th); oriented_footprint.polygon.points.push_back(new_pt); } } void padFootprint(std::vector & footprint, double padding) { // pad footprint in place for (unsigned int i = 0; i < footprint.size(); i++) { geometry_msgs::msg::Point & pt = footprint[i]; pt.x += sign0(pt.x) * padding; pt.y += sign0(pt.y) * padding; } } std::vector makeFootprintFromRadius(double radius) { std::vector points; // Loop over 16 angles around a circle making a point each time int N = 16; geometry_msgs::msg::Point pt; for (int i = 0; i < N; ++i) { double angle = i * 2 * M_PI / N; pt.x = cos(angle) * radius; pt.y = sin(angle) * radius; points.push_back(pt); } return points; } bool makeFootprintFromString( const std::string & footprint_string, std::vector & footprint) { std::string error; std::vector> vvf = parseVVF(footprint_string, error); if (error != "") { RCLCPP_ERROR( rclcpp::get_logger( "nav2_costmap_2d"), "Error parsing footprint parameter: '%s'", error.c_str()); RCLCPP_ERROR( rclcpp::get_logger( "nav2_costmap_2d"), " Footprint string was '%s'.", footprint_string.c_str()); return false; } // convert vvf into points. if (vvf.size() < 3) { RCLCPP_ERROR( rclcpp::get_logger( "nav2_costmap_2d"), "You must specify at least three points for the robot footprint, reverting to previous footprint."); //NOLINT return false; } footprint.reserve(vvf.size()); for (unsigned int i = 0; i < vvf.size(); i++) { if (vvf[i].size() == 2) { geometry_msgs::msg::Point point; point.x = vvf[i][0]; point.y = vvf[i][1]; point.z = 0; footprint.push_back(point); } else { RCLCPP_ERROR( rclcpp::get_logger( "nav2_costmap_2d"), "Points in the footprint specification must be pairs of numbers. Found a point with %d numbers.", //NOLINT static_cast(vvf[i].size())); return false; } } return true; } } // end namespace nav2_costmap_2d