40 #include <boost/thread.hpp> 41 #include <boost/thread/mutex.hpp> 78 dynamic_recfg_ =
new dynamic_reconfigure::Server<CostmapToPolygonsDBSMCCHConfig>(nh);
86 std::vector< std::vector<KeyPoint> > clusters;
94 for (std::size_t i = 1; i <clusters.size(); ++i)
96 polygons->push_back( geometry_msgs::Polygon() );
101 if (!clusters.empty())
103 for (std::size_t i=0; i < clusters.front().size(); ++i)
105 polygons->push_back( geometry_msgs::Polygon() );
130 ROS_ERROR(
"Cannot update costmap since the mutex pointer is null");
158 std::vector<bool> visited(occupied_cells.size(),
false);
164 clusters.push_back(std::vector<KeyPoint>());
165 for(
int i = 0; i< (int)occupied_cells.size(); i++)
170 std::vector<int> neighbors;
172 if((
int)neighbors.size() <
min_pts_)
174 clusters[0].push_back(occupied_cells[i]);
179 clusters.push_back(std::vector<KeyPoint>());
182 clusters[cluster_id].push_back(occupied_cells[i]);
183 for(
int j = 0; j<(int)neighbors.size(); j++)
185 if ((
int)clusters[cluster_id].size() ==
max_pts_)
188 if(!visited[neighbors[j]])
190 visited[neighbors[j]] =
true;
191 std::vector<int> further_neighbors;
192 regionQuery(occupied_cells, neighbors[j], further_neighbors);
198 if ((
int)further_neighbors.size() >=
min_pts_)
201 neighbors.insert(neighbors.end(), further_neighbors.begin(), further_neighbors.end());
202 clusters[cluster_id].push_back(occupied_cells[neighbors[j]]);
214 double curr_index_x = occupied_cells[curr_index].x;
215 double curr_index_y = occupied_cells[curr_index].y;
217 for(
int i = 0; i < (int)occupied_cells.size(); i++)
219 double neighbor_x = occupied_cells[i].x;
220 double neighbor_y = occupied_cells[i].y;
221 double dist = sqrt(pow((curr_index_x - neighbor_x),2)+pow((curr_index_y - neighbor_y),2));
223 neighbors.push_back(i);
229 return p1.
x < p2.
x || (p1.
x == p2.
x && p1.
y < p2.
y);
237 int n = cluster.size();
242 polygon.points.resize(2*n);
245 for (
int i = 0; i < n; ++i)
247 while (k >= 2 &&
cross(polygon.points[k-2], polygon.points[k-1], cluster[i]) <= 0)
251 cluster[i].toPointMsg(polygon.points[k]);
256 for (
int i = n-2, t = k+1; i >= 0; --i)
258 while (k >= t &&
cross(polygon.points[k-2], polygon.points[k-1], cluster[i]) <= 0)
262 cluster[i].toPointMsg(polygon.points[k]);
267 polygon.points.resize(k);
275 for (
int i=0; i < (int) polygon.points.size() - 1; ++i)
277 if ( std::sqrt(std::pow((polygon.points[i].x - polygon.points[i+1].x),2) + std::pow((polygon.points[i].y - polygon.points[i+1].y),2)) <
min_keypoint_separation_ )
278 polygon.points.erase(polygon.points.begin()+i+1);
287 std::vector<KeyPoint> P = cluster;
288 std::vector<geometry_msgs::Point32>& points = polygon.points;
291 for (
int i = 0; i < (int)P.size(); i++)
293 for (
int j = i + 1; j < (int)P.size(); j++)
295 if (P[j].
x < P[i].
x || (P[j].
x == P[i].
x && P[j].
y < P[i].
y))
308 int minmin = 0, minmax;
309 double xmin = P[0].
x;
310 for (i = 1; i < (int)P.size(); i++)
311 if (P[i].
x != xmin)
break;
313 if (minmax == (
int)P.size() - 1)
315 points.push_back(geometry_msgs::Point32());
316 P[minmin].toPointMsg(points.back());
317 if (P[minmax].
y != P[minmin].
y)
319 points.push_back(geometry_msgs::Point32());
320 P[minmax].toPointMsg(points.back());
323 points.push_back(geometry_msgs::Point32());
324 P[minmin].toPointMsg(points.back());
329 int maxmin, maxmax = (int)P.size() - 1;
330 double xmax = P.back().x;
331 for (i = P.size() - 2; i >= 0; i--)
332 if (P[i].
x != xmax)
break;
337 points.push_back(geometry_msgs::Point32());
338 P[minmin].toPointMsg(points.back());
340 while (++i <= maxmin)
343 if (
cross(P[minmin], P[maxmin], P[i]) >= 0 && i < maxmin)
346 while (points.size() > 1)
349 if (
cross(points[points.size() - 2], points.back(), P[i]) > 0)
354 points.push_back(geometry_msgs::Point32());
355 P[i].toPointMsg(points.back());
359 if (maxmax != maxmin)
362 points.push_back(geometry_msgs::Point32());
363 P[maxmax].toPointMsg(points.back());
365 int bot = (int)points.size();
367 while (--i >= minmax)
370 if (
cross( P[maxmax], P[minmax], P[i]) >= 0 && i > minmax)
373 while ((
int)points.size() > bot)
376 if (
cross(points[points.size() - 2], points.back(), P[i]) > 0)
381 points.push_back(geometry_msgs::Point32());
382 P[i].toPointMsg(points.back());
384 if (minmax != minmin)
387 points.push_back(geometry_msgs::Point32());
388 P[minmin].toPointMsg(points.back());
393 for (
int i=0; i < (int) polygon.points.size() - 1; ++i)
395 if ( std::sqrt(std::pow((polygon.points[i].x - polygon.points[i+1].x),2) + std::pow((polygon.points[i].y - polygon.points[i+1].y),2)) <
min_keypoint_separation_ )
396 polygon.points.erase(polygon.points.begin()+i+1);
403 boost::mutex::scoped_lock lock(
mutex_);
410 boost::mutex::scoped_lock lock(
mutex_);
virtual void updateCostmap2D()
Get updated data from the previously set Costmap2D.
void reconfigureCB(CostmapToPolygonsDBSMCCHConfig &config, uint32_t level)
Callback for the dynamic_reconfigure node.
std::vector< KeyPoint > occupied_cells_
List of occupied cells in the current map (updated by updateCostmap2D())
int max_pts_
Parameter for DB_Scan: maximum number of points that define a cluster (to avoid large L- and U-shapes...
static void convertPointToPolygon(const Point &point, geometry_msgs::Polygon &polygon)
Convert a generi point type to a geometry_msgs::Polygon.
void mapToWorld(unsigned int mx, unsigned int my, double &wx, double &wy) const
double max_distance_
Parameter for DB_Scan, maximum distance to neighbors [m].
double min_keypoint_separation_
Clear keypoints of the convex polygon that are close to each other [distance in meters] (0: keep all)...
virtual void compute()
This method performs the actual work (conversion of the costmap to polygons)
PLUGINLIB_EXPORT_CLASS(BAGReader, nodelet::Nodelet)
TFSIMD_FORCE_INLINE const tfScalar & y() const
virtual void setCostmap2D(costmap_2d::Costmap2D *costmap)
Pass a pointer to the costap to the plugin.
unsigned char getCost(unsigned int mx, unsigned int my) const
costmap_2d::Costmap2D * costmap_
Pointer to the costmap2d.
bool param(const std::string ¶m_name, T ¶m_val, const T &default_val) const
This abstract class defines the interface for plugins that convert the costmap into polygon types...
TFSIMD_FORCE_INLINE const tfScalar & x() const
dynamic_reconfigure::Server< CostmapToPolygonsDBSMCCHConfig > * dynamic_recfg_
Dynamic reconfigure server to allow config modifications at runtime.
unsigned int getSizeInCellsY() const
int min_pts_
Parameter for DB_Scan: minimum number of points that define a cluster.
This class converts the costmap_2d into a set of convex polygons (and points)
PolygonContainerPtr polygons_
Current shared container of polygons.
virtual ~CostmapToPolygonsDBSMCCH()
Destructor.
void dbScan(const std::vector< KeyPoint > &occupied_cells, std::vector< std::vector< KeyPoint > > &clusters)
DBSCAN algorithm for clustering.
void convexHull2(std::vector< KeyPoint > &cluster, geometry_msgs::Polygon &polygon)
Compute the convex hull for a single cluster.
unsigned int getSizeInCellsX() const
static const unsigned char LETHAL_OBSTACLE
boost::mutex mutex_
Mutex that keeps track about the ownership of the shared polygon instance.
void regionQuery(const std::vector< KeyPoint > &occupied_cells, int curr_index, std::vector< int > &neighbor_indices)
Helper function for dbScan to search for neighboring points.
bool isXCoordinateSmaller(const CostmapToPolygonsDBSMCCH::KeyPoint &p1, const CostmapToPolygonsDBSMCCH::KeyPoint &p2)
Defines a keypoint in metric coordinates of the map.
void updatePolygonContainer(PolygonContainerPtr polygons)
Thread-safe update of the internal polygon container (that is shared using getPolygons() from outside...
void convexHull(std::vector< KeyPoint > &cluster, geometry_msgs::Polygon &polygon)
Compute the convex hull for a single cluster (monotone chain algorithm)
PolygonContainerConstPtr getPolygons()
Get a shared instance of the current polygon container.
virtual void initialize(ros::NodeHandle nh)
Initialize the plugin.
long double cross(const P1 &O, const P2 &A, const P3 &B)
2D Cross product of two vectors defined by two points and a common origin