12 #ifndef INCLUDED_torres_etal_2016_hpp_ 13 #define INCLUDED_torres_etal_2016_hpp_ 21 #include <unordered_map> 24 #include <boost/range/adaptor/indexed.hpp> 25 #include <boost/range/adaptor/reversed.hpp> 28 #include <std_msgs/Float64.h> 31 #include <geometry_msgs/Point32.h> 32 #include <geometry_msgs/Polygon.h> 35 #include "cpp_uav/Torres16.h" 57 return path.at(0).x < path.at(1).x ?
true :
false;
75 for (std::size_t i = 0; i < convexHull.size(); ++i)
79 ar.at(0) = convexHull.at(i);
83 if (i == convexHull.size() - 1)
85 ar.at(1) = convexHull.at(0);
89 ar.at(1) = convexHull.at(i + 1);
94 double optimalDistance = 0;
98 for (
const auto& edge : edges | boost::adaptors::indexed())
100 double edgeMaxDistance = 0;
103 for (
const geometry_msgs::Point& vertex : convexHull)
109 if (distance > edgeMaxDistance)
111 edgeMaxDistance = distance;
112 opposedVertex = vertex;
116 if ((edgeMaxDistance < optimalDistance) or edge.index() == 0)
118 optimalDistance = edgeMaxDistance;
119 sweepDirection.
baseEdge = edge.value();
124 return sweepDirection;
139 for (
int i = 0; i < std::round(path.size() / 2); ++i)
147 if (path.at(2 * i).x < path.at(2 * i + 1).x)
149 geometry_msgs::Point p1 = path.at(2 * i);
150 geometry_msgs::Point p2 = path.at(2 * i + 1);
157 zigzagPath.push_back(p1);
158 zigzagPath.push_back(p2);
163 geometry_msgs::Point p1 = path.at(2 * i);
164 geometry_msgs::Point p2 = path.at(2 * i + 1);
171 zigzagPath.push_back(p2);
172 zigzagPath.push_back(p1);
176 catch (std::out_of_range& ex)
178 geometry_msgs::Point p = path.at(2 * i);
183 zigzagPath.push_back(p);
189 zigzagPath.push_back(p);
191 ROS_ERROR(
"%s", ex.what());
200 if (path.at(2 * i).x > path.at(2 * i + 1).x)
202 geometry_msgs::Point p1 = path.at(2 * i);
203 geometry_msgs::Point p2 = path.at(2 * i + 1);
210 zigzagPath.push_back(p1);
211 zigzagPath.push_back(p2);
216 geometry_msgs::Point p1 = path.at(2 * i);
217 geometry_msgs::Point p2 = path.at(2 * i + 1);
224 zigzagPath.push_back(p2);
225 zigzagPath.push_back(p1);
229 catch (std::out_of_range& ex)
231 geometry_msgs::Point p = path.at(2 * i);
236 zigzagPath.push_back(p);
242 zigzagPath.push_back(p);
244 ROS_ERROR(
"%s", ex.what());
264 if (polygon.size() < 3)
270 const double padding = footprintWidth/2.0;
277 double minX(0), maxX(0);
278 for (
const auto& vertex : rotatedPolygon)
284 else if (vertex.x > maxX)
290 double stepWidth = footprintWidth * (1 - horizontalOverwrap);
297 rotatedDir.
baseEdge.front() = dir.at(1);
298 rotatedDir.
baseEdge.back() = dir.at(2);
305 for (
int i = 0; i < stepNum; ++i)
308 geometry_msgs::Point p1, p2;
310 p1.y = rotatedDir.
baseEdge.at(0).y + (i * stepWidth) + padding;
312 p2.y = rotatedDir.
baseEdge.at(1).y + (i * stepWidth) + padding;
317 sweepLines.push_back(ar);
325 for (
const auto& sweepLine : sweepLines)
327 int intersectionCount = 0;
328 for (
const auto& edge : rotatedEdges)
337 if (intersectionCount >= 3)
345 std::stable_sort(intersections.begin(), intersections.end(),
346 [](
const geometry_msgs::Point& p1,
const geometry_msgs::Point& p2) {
return p1.y < p2.y; });
387 double pathLength = 0;
388 for (
int i = 0; i < path.size() - 1; ++i)
402 for (
int i = 0; i < std::round(path.size() / 2); ++i)
405 geometry_msgs::Point tmp = path.at(2 * i);
407 path.at(2 * i) = path.at(2 * i + 1);
410 path.at(2 * i + 1) = tmp;
412 catch (std::out_of_range& ex)
414 ROS_ERROR(
"%s", ex.what());
430 for (
int i = path.size() - 1; i >= 0; --i)
432 oppositePath.push_back(path.at(i));
448 const geometry_msgs::Point& start,
const geometry_msgs::Point& end)
451 std::unordered_map<int, std::unordered_map<std::string, geometry_msgs::Point>> coverageAlternatives;
452 std::unordered_map<std::string, geometry_msgs::Point> a1, a2, a3, a4;
458 a1[
"SP"] = pathCW.front();
459 a1[
"EP"] = pathCW.back();
462 a2[
"SP"] = pathCCW.front();
463 a2[
"EP"] = pathCCW.back();
466 a3[
"SP"] = pathCW.back();
467 a3[
"EP"] = pathCW.front();
470 a4[
"SP"] = pathCCW.back();
471 a4[
"EP"] = pathCCW.front();
473 coverageAlternatives[1] = a1;
474 coverageAlternatives[2] = a2;
475 coverageAlternatives[3] = a3;
476 coverageAlternatives[4] = a4;
485 for (
const auto& coverage : coverageAlternatives | boost::adaptors::indexed())
488 if ((hasIntersectionCW and coverage.index() % 2 == 0) or (hasIntersectionCCW and coverage.index() % 2 != 0))
497 if (distance < minDistance or coverage.index() == 0)
499 minDistance = distance;
500 optimalPath = coverage.value().first;
534 const geometry_msgs::Point& start)
550 std::vector<Direction> sweepDirections;
555 for (
const auto& edge : edges)
557 double maxDistance = 0;
560 for (
const auto& vertex : convexHull)
565 if (distance > maxDistance)
567 maxDistance = distance;
571 sweepDirections.push_back(direction);
575 double pathLength = 0;
577 for (
const auto& sweepDirection : sweepDirections)
582 bool isValidPath =
computeConvexCoverage(polygon, footprintWidth, horizontalOverwrap, sweepDirection, p);
592 if (tempPath.size() <= 1)
611 for (
const auto& vertex1 : polygon1)
613 for (
const auto& vertex2 : polygon2)
616 if (vertex1 == vertex2)
635 double horizontalOverwrap,
int adjacencyCriteria = 1)
639 std::vector<int> permutation(subPolygons.size());
640 std::iota(permutation.begin(), permutation.end(), 0);
642 double minPathLength = -1;
645 int numPermutation = 0;
646 int numIntersectSets = 0;
651 if (permutation.front() != 0)
657 int adjacencyCount = 0;
658 for (
auto itr = permutation.begin(); itr != permutation.end() - 1; ++itr)
660 if (
isAdjacent(subPolygons.at(*itr), subPolygons.at(*(itr + 1))) ==
true)
667 if (adjacencyCount < adjacencyCriteria)
672 double pathLength = 0;
673 std::vector<PointVector> candidatePath;
676 for (
auto itr = permutation.begin(); itr != permutation.end(); ++itr)
680 if (itr == permutation.begin())
687 geometry_msgs::Point start = subPolygons.at(*(permutation.end() - 1)).back();
688 geometry_msgs::Point end;
690 if (permutation.size() == 1)
697 end = subPolygons.at(*(itr + 1)).front();
703 hasIntersection =
true;
709 candidatePath.push_back(optimalAlternative);
714 catch (std::out_of_range& ex)
716 ROS_ERROR(
"%s", ex.what());
720 else if (itr == permutation.end() - 1)
727 geometry_msgs::Point start = subPolygons.at(*(itr - 1)).back();
728 geometry_msgs::Point end = subPolygons.at(*permutation.begin()).front();
734 hasIntersection =
true;
740 candidatePath.push_back(optimalAlternative);
745 catch (std::out_of_range& ex)
747 ROS_ERROR(
"%s", ex.what());
758 geometry_msgs::Point start = subPolygons.at(*(itr - 1)).back();
759 geometry_msgs::Point end = subPolygons.at(*(itr + 1)).front();
765 hasIntersection =
true;
771 candidatePath.push_back(optimalAlternative);
776 catch (std::out_of_range& ex)
778 ROS_ERROR(
"%s", ex.what());
788 hasIntersection =
false;
793 if (minPathLength < 0 or pathLength < minPathLength)
795 minPathLength = pathLength;
797 if (not path.empty())
803 for (
const auto& part : candidatePath)
805 path.insert(path.begin(), part.begin(), part.end());
809 }
while (next_permutation(permutation.begin(), permutation.end()));
813 ROS_ERROR(
"Unable to generate path.");
Direction identifyOptimalSweepDir(const PointVector &polygon)
Calculates line sweep direction for given polygon.
bool findSecondOptimalPath(const PointVector &polygon, double footprintWidth, double horizontalOverwrap, PointVector &path)
Find second optimal path.
std::array< geometry_msgs::Point, 2 > LineSegment
double calculateHorizontalAngle(const geometry_msgs::Point &p1, const geometry_msgs::Point &p2)
Calculates angle between segment p1p2 and horizontal line.
geometry_msgs::Point opposedVertex
PointVector identifyOptimalAlternative(const PointVector &polygon, const PointVector &path, const geometry_msgs::Point &start, const geometry_msgs::Point &end)
Identify optimal path from 4 coverage alternatives.
PointVector reshapePath(const PointVector &path, double padding)
Reshape given path.
bool isClockWise(const PointVector &path)
Checks if given path is clockwise (the first turn made to the left) or not.
LineSegmentVector generateEdgeVector(const PointVector &vec, bool isClosed)
Generate Vector of line segment from given PointVector.
std::vector< LineSegment > LineSegmentVector
PointVector computeMultiplePolygonCoverage(std::vector< PointVector > subPolygons, double footprintWidth, double horizontalOverwrap, int adjacencyCriteria=1)
Compute coverage path for multiple convex polygons.
PointVector computeOppositePath(const PointVector &path)
Return opposite path of given path.
double calculateDistance(const geometry_msgs::Point &p1, const geometry_msgs::Point &p2)
Calculates distance between given two points.
PointVector rotatePoints(const PointVector &points, double angle_rad)
Rotate points by given angle around the origin.
std::vector< geometry_msgs::Point > PointVector
PointVector computeConvexHull(PointVector points)
Returns convex hull of given points.
Storage for line sweep direction.
geometry_msgs::Point localizeIntersection(const LineSegment &edge1, const LineSegment &edge2)
Find the location where given edges intersect each other.
bool computeConvexCoverage(const PointVector &polygon, double footprintWidth, double horizontalOverwrap, const Direction &sweepDirection, PointVector &path)
Compute coverage path for convex polygon.
double calculatePathLength(const PointVector &path)
Calculates length of path.
bool hasIntersection(const LineSegment &edge1, const LineSegment &edge2)
Checks if given edges intersect each other.
bool isAdjacent(const PointVector &polygon1, const PointVector &polygon2)
Check if given two polygons are adjacent.
PointVector computeCCWPath(PointVector path)
Return counter clock wise-ed path of given path.