13 geometry_msgs::Point
wp;
17 int current = 2 * round(wp.y /
map.info.resolution) * 2*
map.info.width + 2 * round(wp.x /
map.info.resolution);
20 unordered_set<int> removed;
30 movement.push_back(2*
map.info.width);
31 movement.push_back(-1);
32 movement.push_back(-2*
map.info.width);
33 movement.push_back(1);
39 for (
int idx=0; idx<movement.size(); idx++) {
40 if (
nodes[current].count(current + movement[idx]) > 0) {
41 previous = current + movement[idx];
56 removed.insert(current);
59 offset = distance(movement.begin(), find(movement.begin(), movement.end(), previous-current));
64 for (
int idx=0; idx<movement.size(); idx++){
65 if (
nodes[previous].count(previous + movement[(idx+offset) % movement.size()]) > 0 &&
66 removed.count(previous + movement[(idx+offset) % movement.size()]) <= 0) {
67 current = previous + movement[(idx+offset) % movement.size()];
77 nodes[current].erase(previous);
78 nodes[previous].erase(current);
81 wp.x = (current % (2*
map.info.width)) / 2.0 *
map.info.resolution;
82 wp.y = (current / (2*
map.info.width)) / 2.0 *
map.info.resolution;
85 double width_path = (round(
width /
map.info.resolution) * 2 - 1) / 2.0 *
map.info.resolution;
86 double height_path = (round(
height /
map.info.resolution) * 2 - 1) / 2.0 *
map.info.resolution;
87 wp.x += (
width - width_path) / 2.0;
88 wp.y += (
height - height_path) / 2.0;
103 nav_msgs::Path nav_path;
104 vector<geometry_msgs::PoseStamped> poses;
105 geometry_msgs::PoseStamped pose;
106 for (
auto p :
path) {
112 pose.pose.position.x +=
origin.x;
113 pose.pose.position.y +=
origin.y;
115 poses.push_back(pose);
117 nav_path.poses = poses;
118 nav_path.header.stamp = Time::now();
119 nav_path.header.frame_id =
"local_origin_ned";
125 ROS_DEBUG(
"Check if distance between (%.2f,%.2f) and (%.2f,%.2f) < %.2f", position.x, position.y,
get_wp().x,
get_wp().y, tolerance);
141 ROS_DEBUG(
"Gridmap size %dx%d origin (%.2f,%.2f)", gridmap.info.width, gridmap.info.height, gridmap.info.origin.position.x, gridmap.info.origin.position.y);
147 int rows = gridmap.info.height;
148 int cols = gridmap.info.width;
150 nodes.resize(2*rows*2*cols);
155 valarray<bool> inflated(2*rows*2*cols);
156 for (
int i=0; i<2*rows; i++) {
157 for (
int j=0; j<2*cols; j++) {
158 inflated[i*2*cols + j] = (gridmap.data[(i/2)*cols + j/2] == 0);
163 for (
int i=0; i<2*rows; i++) {
164 for (
int j=0; j<2*cols; j++) {
166 if (inflated[2*i*cols+j]) {
168 if (i>0 && inflated[(i-1)*2*cols+j]) {
169 add_edge(i*2*cols+j, (i-1)*2*cols+j, 1);
171 if (i<2*rows-1 && inflated[(i+1)*2*cols+j]) {
172 add_edge(i*2*cols+j, (i+1)*2*cols+j, 1);
174 if (j>0 && inflated[i*2*cols+j-1]) {
175 add_edge(i*2*cols+j, i*2*cols+j-1, 1);
177 if (j<2*cols-1 && inflated[i*2*cols+j+1]) {
178 add_edge(i*2*cols+j, i*2*cols+j+1, 1);
183 if (i>0 && j>0 && inflated[(i-1)*2*cols+j-1]) {
184 add_edge(i*2*cols+j, (i-1)*2*cols+j-1, 1);
186 if (i<2*rows-1 && j<2*cols-1 && inflated[(i+1)*2*cols+j+1]) {
187 add_edge(i*2*cols+j, (i+1)*2*cols+j+1, 1);
189 if (i<2*rows-1 && j>0 && inflated[(i+1)*2*cols+j-1]) {
190 add_edge(i*2*cols+j, (i+1)*2*cols+j-1, 1);
192 if (i>0 && j<2*cols-1 && inflated[(i-1)*2*cols+j+1]) {
193 add_edge(i*2*cols+j, (i-1)*2*cols+j+1, 1);
213 ROS_DEBUG(
"Area size %.2fx%.2f origin (%.2f,%.2f)", width, height, origin.x, origin.y);
219 int cols =
map.info.width;
220 int alpha, vmax, vmin;
221 for (
int i=0; i<mst.size(); i++) {
222 vmax = max(mst[i].from, mst[i].to);
223 vmin = min(mst[i].from, mst[i].to);
225 if (vmax - vmin == 1) {
226 alpha = (4*vmin + 3) - 2 * (vmax % cols);
234 alpha = (4*vmin + 2*cols) - 2 * (vmax % cols);
246 if (
path.size() > 2) {
247 for (
auto it =
path.begin()+1; it !=
path.end()-1; ) {
249 double dx1 = it->x - (it-1)->x;
250 double dy1 = it->y - (it-1)->y;
251 double dx2 = (it+1)->x - it->x;
252 double dy2 = (it+1)->y - it->y;
255 if (atan2(dy1,dx1) == atan2(dy2,dx2))
276 nodes[from].insert(to);
277 nodes[to].insert(from);
282 return hypot(p1.x - p2.x, p1.y - p2.y);
287 geometry_msgs::Point waypoint;
289 if (0 <=
wp+offset &&
wp+offset <
path.size()) {
304 if (
edges.count(e) > 0) {
void initialize_map(geometry_msgs::Point origin, double rotation, double width, double height)
Initialize properties of the area to be covered.
double rotation
The rotation of the map.
void reduce()
Remove waypoints that are within straight line segments of the path. Only keep turning points of the ...
int wp
The current way point.
double height
Height of the area to cover.
geometry_msgs::Point get_waypoint(geometry_msgs::Point position, double tolerance)
Get the current waypoint and possibly select next waypoint, if close enough.
geometry_msgs::Point get_wp(int offset=0)
Get the current way point.
int to
The ending vertex of the edge.
A class for representing edges.
int from
The starting vertex of the edge.
void add_edge(int from, int to, int cost)
Add an edge to the tree graph.
double width
Width of the area to cover.
vector< unordered_set< int > > nodes
The sets of connected vertices.
nav_msgs::OccupancyGrid map
The grid map that needs to be covered by the MST path.
deque< geometry_msgs::Point > path
The boustrophedon path.
double dist(geometry_msgs::Point p1, geometry_msgs::Point p2)
Calculate the distance between two points.
void remove_edge(edge e)
Remove an edge from the tree graph.
void initialize_graph(nav_msgs::OccupancyGrid gridmap, bool vertical=false, bool connect4=true)
Initialize the internal graph structure that represents the area division.
bool valid()
Check whether the current waypoint index is valid.
void initialize_tree(vector< edge > mst)
Remove edges of the graph that overlap with the tree.
geometry_msgs::Point origin
Coordinate of the bottom left bounding point of the area.
bool vertical
Whether the sweeping pattern is vertical or horizontal.
unordered_set< edge, hash_edge > edges
Priority queue of edge objects sorted by cost.
nav_msgs::Path get_path()
Get the complete path.
bool generate_path(geometry_msgs::Point start)
Generate all way points for the path.