├── CMakeLists.txt
├── LICENSE
├── README.md
├── action
└── manda_coverage.action
├── package.xml
└── src
├── PathPlan.cpp
├── PathPlan.h
├── RecordSwath.cpp
├── RecordSwath.h
├── SurveyPath.cpp
├── SurveyPath.h
├── SurveyPath_Info.cpp
├── SurveyPath_Info.h
├── lib_geometry
├── AngleUtils.cpp
├── AngleUtils.h
├── GeomUtils.cpp
├── GeomUtils.h
├── XYFormatUtilsSegl.cpp
├── XYFormatUtilsSegl.h
├── XYObject.cpp
├── XYObject.h
├── XYPatternBlock.cpp
├── XYPatternBlock.h
├── XYPoint.cpp
├── XYPoint.h
├── XYPolygon.cpp
├── XYPolygon.h
├── XYSegList.cpp
├── XYSegList.h
├── XYVector.cpp
└── XYVector.h
├── lib_mbutil
├── ColorPack.cpp
├── ColorPack.h
├── ColorParse.cpp
├── ColorParse.h
├── MBUtils.cpp
├── MBUtils.h
├── ReleaseInfo.cpp
└── ReleaseInfo.h
└── main.cpp
/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 2.8.3)
2 | project(manda_coverage)
3 |
4 | set(CMAKE_CXX_STANDARD 14)
5 |
6 | find_package(catkin REQUIRED COMPONENTS
7 | actionlib
8 | actionlib_msgs
9 | genmsg
10 | nav_msgs
11 | project11
12 | project11_nav_msgs
13 | roscpp
14 | sensor_msgs
15 | visualization_msgs
16 | )
17 |
18 | find_path(EIGEN_INCLUDES Eigen/Core /usr/include/eigen3)
19 |
20 | add_action_files(DIRECTORY action FILES manda_coverage.action)
21 | generate_messages(DEPENDENCIES actionlib_msgs geometry_msgs nav_msgs)
22 |
23 |
24 | catkin_package(
25 | # INCLUDE_DIRS include
26 | # LIBRARIES asv_helm
27 | CATKIN_DEPENDS roscpp project11 visualization_msgs
28 | # DEPENDS system_lib
29 | )
30 |
31 | include_directories(
32 | # include
33 | src/lib_geometry/
34 | src/lib_mbutil/
35 | ${catkin_INCLUDE_DIRS}
36 | ${EIGEN_INCLUDES}
37 | )
38 |
39 | set(NODE_SOURCES
40 | src/main.cpp
41 | src/PathPlan.cpp
42 | src/RecordSwath.cpp
43 | src/SurveyPath.cpp
44 | src/SurveyPath_Info.cpp
45 | src/lib_mbutil/MBUtils.cpp
46 | src/lib_mbutil/ColorParse.cpp
47 | src/lib_mbutil/ColorPack.cpp
48 | src/lib_mbutil/ReleaseInfo.cpp
49 | src/lib_geometry/XYObject.cpp
50 | src/lib_geometry/XYPoint.cpp
51 | src/lib_geometry/XYSegList.cpp
52 | src/lib_geometry/XYPolygon.cpp
53 | src/lib_geometry/XYVector.cpp
54 | src/lib_geometry/GeomUtils.cpp
55 | src/lib_geometry/AngleUtils.cpp
56 | src/lib_geometry/XYFormatUtilsSegl.cpp
57 | src/lib_geometry/XYPatternBlock.cpp
58 | )
59 |
60 | add_executable(${PROJECT_NAME}_node ${NODE_SOURCES})
61 |
62 | add_dependencies(${PROJECT_NAME}_node ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})
63 |
64 | target_link_libraries(${PROJECT_NAME}_node
65 | ${catkin_LIBRARIES}
66 | )
67 |
68 | install(TARGETS ${PROJECT_NAME}_node
69 | ARCHIVE DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION}
70 | LIBRARY DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION}
71 | RUNTIME DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
72 | )
73 |
74 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | BSD 2-Clause License
2 |
3 | Copyright (c) 2016-2020, Roland Arsenault
4 | All rights reserved.
5 |
6 | Redistribution and use in source and binary forms, with or without
7 | modification, are permitted provided that the following conditions are met:
8 |
9 | 1. Redistributions of source code must retain the above copyright notice, this
10 | list of conditions and the following disclaimer.
11 |
12 | 2. Redistributions in binary form must reproduce the above copyright notice,
13 | this list of conditions and the following disclaimer in the documentation
14 | and/or other materials provided with the distribution.
15 |
16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
20 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
23 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # manda_coverage
2 | ROS port of Damian Manda's MOOS based sonar coverage based path planner. https://github.com/mandad/moos-ivp-manda
3 |
4 | Manda’s MS thesis can be found here: http://ccom.unh.edu/sites/default/files/publications/manda-damian-thesis.pdf
5 |
--------------------------------------------------------------------------------
/action/manda_coverage.action:
--------------------------------------------------------------------------------
1 | # goal
2 |
3 | geometry_msgs/PolygonStamped survey_area
4 | ---
5 | # result
6 |
7 | bool success # true if completed succefully
8 | string status # more details if necessary
9 |
10 | ---
11 | # feedback
12 |
13 | nav_msgs/Path current_line
14 | float32 percent_complete
15 |
16 |
--------------------------------------------------------------------------------
/package.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | manda_coverage
4 | 0.0.0
5 | The manda_coverage package
6 |
7 | Damien Manada
8 |
9 | Roland Arsenault
10 |
11 | MIT
12 |
13 | catkin
14 | actionlib
15 | actionlib_msgs
16 | nav_msgs
17 | project11
18 | project11_nav_msgs
19 | roscpp
20 | sensor_msgs
21 | visualization_msgs
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/src/PathPlan.h:
--------------------------------------------------------------------------------
1 | /**
2 | * @file PathPlan.h
3 | * @brief Plans a path for surveying based on a recorded path and swath.
4 | * @details Paths are offset and processed to give a valid vehicle path
5 | * @author Damian Manda
6 | * @date 25 Feb 2016
7 | * @copyright MIT License
8 | */
9 |
10 | #ifndef SurveyPath_PathPlan_HEADER
11 | #define SurveyPath_PathPlan_HEADER
12 |
13 | #include "RecordSwath.h"
14 | #include "XYSegList.h"
15 | #include "XYPolygon.h"
16 | #include
17 | #include
18 | #include
19 | #include
20 | #include
21 | #include
22 | #include
23 |
24 | // To get a single point EPointList.col(i)
25 | typedef Eigen::Matrix EPointList;
26 | typedef Eigen::Vector2d EPoint;
27 | typedef std::valarray SegIndex;
28 | typedef std::list PathList;
29 | typedef boost::geometry::model::d2::point_xy BPoint;
30 | typedef boost::geometry::model::polygon BPolygon;
31 | typedef boost::geometry::model::linestring BLinestring;
32 | typedef boost::geometry::model::ring BRing;
33 |
34 | /**
35 | * @struct XYPt
36 | * @brief Defines a simple point, for better memory use in lists
37 | */
38 | struct XYPt {
39 | double x;
40 | double y;
41 | };
42 |
43 | /**
44 | * @class PathPlan
45 | * @brief Plans a subsequent survey path offset from existing coverage.
46 | */
47 | class PathPlan
48 | {
49 | public:
50 | PathPlan(const RecordSwath &last_swath, BoatSide side, BPolygon op_region,
51 | double margin=0.2, double max_bend_angle=60, bool restrict_to_region = true);
52 | ~PathPlan() {};
53 | /**
54 | * Generates an offset path
55 | * @return The path in MOOS XYSegList format;
56 | */
57 | XYSegList GenerateNextPath();
58 |
59 | public:
60 | /**
61 | * The Damian
62 | * @param process Likes The Damian
63 | * @details Repeats a process until it makes no more changes to the path
64 | * Currently does not make a copy of the passed input, may want to
65 | * reconsider this
66 | */
67 | void RemoveAll(std::function&)> process,
68 | std::list &path_points);
69 |
70 | /**
71 | * Removes intersecting segments from a line.
72 | * @details Removes the points between the first point of an intersecting
73 | * segment and the last point of the final segment it intersects in the
74 | * line.
75 | * @param path_pts The line from which to remove intersecting segments.
76 | */
77 | static void RemoveIntersects(std::list &path_pts);
78 |
79 | /**
80 | * Check for drastic angles between segments
81 | * @param path_pts Note that this goes to the last point being checked
82 | */
83 | void RemoveBends(std::list &path_pts);
84 |
85 | /**
86 | * Restricts a path to the region by simply eliminating points outside the
87 | * region specified by m_op_region.
88 | * @param path_pts The path to process, passed by reference
89 | */
90 | void RestrictToRegion(std::list &path_pts);
91 |
92 | /**
93 | * Clips a path to the region, eliminating points outside
94 | * @param path_pts The path to clip, passed by reference
95 | * @return A pair with whether the was clipped.
96 | * If false, means the path was already inside the polygon.
97 | */
98 | std::pair ClipToRegion(std::list &path_pts);
99 |
100 | std::pair ClipToRegion2(std::list &path_pts);
101 |
102 | /**
103 | * Extends a path to meet the edges of a region if it does not already.
104 | * Adds to the last segment, extending it as a ray from the end. Can
105 | * extend either the beginning or the end of the path.
106 | * @param path_pts The path to process
107 | * @param begin True to process the beginning, false to process the end
108 | */
109 | void ExtendToEdge(std::list &path_pts, bool begin);
110 |
111 | /**
112 | * Finds the closest intersection of a ray with a polygon
113 | *
114 | * @param ray_vec EPoint(dx,dy)
115 | * @param start_pt EPoint(x,y)
116 | * @param poly BPolygon([(x1,y1), (x2,y2), ...])
117 | */
118 | std::pair FindNearestIntersect(EPoint ray_vec,
119 | EPoint starting_pt, BPolygon& poly);
120 |
121 | /**
122 | * Finds the intersection point of a ray with a segment, if it exists.
123 | * Derived from:
124 | * http://stackoverflow.com/questions/563198/how-do-you-detect-where-two-line-segments-intersect/565282#565282
125 | * @param ray_vector The vector describing the direction of the ray
126 | * @param start_pt Starting location of the ray
127 | * @param segment Segment to test for intersection
128 | * @return
129 | */
130 | std::pair IntersectRaySegment(EPoint ray_vector, EPoint start_pt,
131 | std::pair segment);
132 |
133 | /**
134 | * Replicates the functionality of 2d cross product from numpy. This is the
135 | * z component of a cross product (which does not require a z input).
136 | * @return The z component of the cross product
137 | */
138 | double Cross2d(EPoint vec1, EPoint vec2);
139 |
140 | EPoint EPointFromBPoint(BPoint boost_point);
141 |
142 | std::vector SegmentRingIntersect(BPoint seg_pt1, BPoint seg_pt2, BRing ring);
143 |
144 | /**
145 | * Determines whether segments are counter clockwise in smalles angle with
146 | * respect to each other.
147 | * @param A First point (end point)
148 | * @param B Middle point
149 | * @param C Last point (end point)
150 | * @return True if rotate CCW from AB to BC.
151 | */
152 | static bool CCW(EPoint A, EPoint B, EPoint C);
153 |
154 | /**
155 | * Determines if the segment AB intersects CD
156 | * @param A First point of first segment
157 | * @param B Second point of first segment
158 | * @param C First point of second segment
159 | * @param D Second point of second segment
160 | * @return True if the segments intersect
161 | */
162 | static bool Intersect(EPoint A, EPoint B, EPoint C, EPoint D);
163 |
164 | /**
165 | * Determines the angle between two vectors
166 | * @details tan(ang) = |(axb)|/(a.b)
167 | * cos(ang) = (a.b)/(||a||*||b||)
168 | * @param vector1 First vector
169 | * @param vector2 Second vector
170 | * @return Angle between the vectors in degrees
171 | */
172 | static double VectorAngle(EPoint vector1, EPoint vector2);
173 |
174 | /**
175 | * Determines a vector (segment) from points at the indicies provided
176 | * by the second argument.
177 | * @param points The list from which to select points for the segment
178 | * @param segment The beginning and end of the segment.
179 | * @return A segment vector between the selected points.
180 | */
181 | EPoint VectorFromSegment(const std::vector& points,
182 | SegIndex segment);
183 |
184 | /**
185 | * Converts an XYSeglist to a std::list of simple points (XYPt).
186 | */
187 | std::list SegListToXYPt(const XYSegList &to_convert);
188 |
189 | /**
190 | * Converts a std::list of simple points (XYPt) to a MOOS XYSegList.
191 | */
192 | XYSegList XYPtToSegList(const std::list &to_convert);
193 |
194 | /**
195 | * Converts a std::list of Eigen points (vectors) to a MOOS XYSegList.
196 | */
197 | XYSegList VectorListToSegList(const std::list &to_convert);
198 |
199 | BPolygon XYPolygonToBoostPolygon(XYPolygon& poly);
200 |
201 | XYSegList GetRawPath() { return m_raw_path; }
202 |
203 | /**
204 | * @brief Selects specific elements from a list by index.
205 | * @details Replicates the select by index functionality of numpy or
206 | * armadillo or dyND.
207 | */
208 | template
209 | static void SelectIndicies(std::list& select_from,
210 | std::list to_select) {
211 | // Make sure the indicies are well behaved
212 | to_select.sort();
213 | to_select.unique();
214 | if (to_select.back() >= select_from.size()) {
215 | throw std::out_of_range("Indices to select exceed list size.");
216 | }
217 |
218 | auto list_it = select_from.begin();
219 | std::size_t i = 0;
220 | for (auto select_it = to_select.begin();
221 | select_it != to_select.end(); select_it++) {
222 | while (*select_it != i) {
223 | // This advances list_it by one
224 | list_it = select_from.erase(list_it);
225 | i++;
226 | }
227 | if (list_it != select_from.end()) {
228 | list_it++;
229 | i++;
230 | }
231 | }
232 | if (list_it != select_from.end()) {
233 | select_from.erase(list_it, select_from.end());
234 | }
235 | }
236 |
237 | private:
238 |
239 | // Configuration variables
240 | bool m_restrict_asv_to_region;
241 | double m_max_bend_angle;
242 | double m_margin;
243 | BPolygon m_op_region;
244 | //XYPolygon m_op_region_moos;
245 |
246 | // State variables
247 | RecordSwath m_last_line;
248 | BoatSide m_planning_side;
249 | // PointList m_next_path_pts;
250 | std::list m_next_path_pts;
251 | XYSegList m_raw_path;
252 | };
253 |
254 | #endif
255 |
--------------------------------------------------------------------------------
/src/RecordSwath.cpp:
--------------------------------------------------------------------------------
1 | /************************************************************/
2 | /* NAME: Damian Manda */
3 | /* ORGN: UNH */
4 | /* FILE: RecordSwath.cpp */
5 | /* DATE: 23 Feb 2016 */
6 | /************************************************************/
7 |
8 | #include "RecordSwath.h"
9 | #include
10 | #include
11 | #include "AngleUtils.h"
12 | #include "GeomUtils.h"
13 |
14 | #define TURN_THRESHOLD 20
15 | //---------------------------------------------------------
16 | // Constructor
17 |
18 | RecordSwath::RecordSwath(double interval) : m_min_allowable_swath(0),
19 | m_has_records(false), m_acc_dist(0),
20 | m_interval(interval), m_output_side(BoatSide::Unknown),
21 | m_previous_record{0, 0, 0, 0, 0, 0}
22 | {
23 | // Initialize the point records
24 | m_interval_swath[BoatSide::Port] = std::vector();
25 | m_interval_swath[BoatSide::Stbd] = std::vector();
26 | }
27 |
28 | bool RecordSwath::AddRecord(double swath_stbd, double swath_port, double loc_x,
29 | double loc_y, double heading, double depth)
30 | {
31 | // Dont add records at duplicate location
32 | if (loc_x == m_previous_record.loc_x && loc_y == m_previous_record.loc_y
33 | && heading == m_previous_record.heading)
34 | return false;
35 |
36 | SwathRecord record = {loc_x, loc_y, heading, swath_stbd, swath_port, depth};
37 | m_interval_record.push_back(record);
38 | m_interval_swath[BoatSide::Stbd].push_back(swath_stbd);
39 | m_interval_swath[BoatSide::Port].push_back(swath_port);
40 |
41 | if (m_has_records)
42 | {
43 | m_acc_dist += distPointToPoint(m_last_x, m_last_y, loc_x, loc_y);
44 | //std::cout << "Accumulated distance: " + std::to_string(m_acc_dist) + "\n";
45 |
46 | if (m_acc_dist >= m_interval)
47 | {
48 | //std::cout << "Running MinInterval()\n";
49 | m_acc_dist = 0;
50 | MinInterval();
51 | }
52 | else
53 | {
54 | //Override the min interval on turns to the outside
55 | double turn = angle180(angle180(heading) - angle180(m_min_record.back().heading));
56 | if ((turn > TURN_THRESHOLD && m_output_side == BoatSide::Port)
57 | || (turn < -TURN_THRESHOLD && m_output_side == BoatSide::Stbd))
58 | {
59 | //std::cout << "Adding Turn Based Point\n";
60 | m_min_record.push_back(record);
61 | m_interval_record.clear();
62 | m_interval_swath.clear();
63 | }
64 | }
65 | }
66 |
67 | m_last_x = loc_x;
68 | m_last_y = loc_y;
69 | m_has_records = true;
70 | m_previous_record = record;
71 |
72 | // Add progressively to the coverage model
73 | return AddToCoverage(record);
74 | }
75 |
76 | bool RecordSwath::AddToCoverage(SwathRecord record)
77 | {
78 | // Tackle this later
79 | return true;
80 | }
81 |
82 | void RecordSwath::MinInterval()
83 | {
84 | // Get the record from the side we are offsetting
85 | if (m_output_side == BoatSide::Unknown)
86 | {
87 | throw std::runtime_error("Cannot find swath minimum without output side.");
88 | return;
89 | }
90 | std::vector* side_record = &m_interval_swath[m_output_side];
91 |
92 | std::size_t min_index = 0;
93 | if (side_record->size() > 0)
94 | {
95 | min_index = std::min_element(side_record->begin(), side_record->end()) - side_record->begin();
96 | }
97 |
98 | if (m_interval_record.size() > min_index)
99 | {
100 | // Add the first point if this is the first interval in the record
101 | if (m_min_record.size() == 0 && min_index != 0)
102 | {
103 | //std::cout << "Saving First record of line\n";
104 | m_min_record.push_back(m_interval_record[0]);
105 | }
106 | m_min_record.push_back(m_interval_record[min_index]);
107 | // These are always cleared in the python version
108 | m_interval_record.clear();
109 | m_interval_swath.clear();
110 | }
111 | }
112 |
113 | bool RecordSwath::SaveLast()
114 | {
115 | if (m_min_record.size() > 0 && m_interval_record.size() > 0)
116 | {
117 | SwathRecord last_min = m_min_record.back();
118 | SwathRecord last_rec = m_interval_record.back();
119 | if (last_min.loc_x != last_rec.loc_x || last_min.loc_y != last_rec.loc_y)
120 | {
121 | //std::cout << "Saving last record of line, (" << last_rec.loc_x << ", " << last_rec.loc_y << ")\n";
122 | m_min_record.push_back(last_rec);
123 | }
124 | return true;
125 | }
126 | return false;
127 | }
128 |
129 | void RecordSwath::ResetLine()
130 | {
131 | m_interval_record.clear();
132 | m_min_record.clear();
133 | m_interval_swath[BoatSide::Stbd].clear();
134 | m_interval_swath[BoatSide::Port].clear();
135 | m_acc_dist = 0;
136 | m_has_records = false;
137 | }
138 |
139 | XYSegList RecordSwath::SwathOuterPts(BoatSide side)
140 | {
141 | XYSegList points;
142 | std::list::iterator record;
143 | for (record = m_min_record.begin(); record != m_min_record.end(); record++)
144 | {
145 | // std::cout << "Getting swath outer point for " << record->loc_x
146 | // << ", " << record->loc_y << "\n";
147 | XYPoint outer_pt = OuterPoint(*record, side);
148 | points.add_vertex(outer_pt);
149 | }
150 | return points;
151 | }
152 |
153 | // list RecordSwath::SwathOuterPts(BoatSide side) {
154 | // list points;
155 | // std::list::iterator record;
156 | // for (record = m_min_record.begin(); record != m_min_record.end(); record++) {
157 | // XYPoint outer_pt = OuterPoint(*record, m_output_side);
158 | // XYPt outer_pt_simple = {outer_point.x(), outer_point.y()}
159 | // points.add_vertex(outer_pt);
160 | // }
161 | // return points;
162 | // }
163 |
164 | XYPoint RecordSwath::OuterPoint(const SwathRecord &record, BoatSide side)
165 | {
166 | // Could have SwathRecord be a class with functions to return representation
167 | // as a vector or point.
168 | double swath_width = 0;
169 | double rotate_degs = 0;
170 | if (side == BoatSide::Stbd)
171 | {
172 | swath_width = record.swath_stbd;
173 | rotate_degs = 90;
174 | }
175 | else if (side == BoatSide::Port)
176 | {
177 | swath_width = record.swath_port;
178 | rotate_degs = -90;
179 | }
180 | XYVector swath_vector(record.loc_x, record.loc_y, swath_width, record.heading);
181 | swath_vector.augAngle(rotate_degs);
182 | return XYPoint(swath_vector.xpos() + swath_vector.xdot(), swath_vector.ypos() + swath_vector.ydot());
183 | }
184 |
185 | std::pair RecordSwath::LastOuterPoints()
186 | {
187 | if (m_has_records)
188 | {
189 | XYPoint port_point = OuterPoint(m_previous_record, BoatSide::Port);
190 | XYPoint stbd_point = OuterPoint(m_previous_record, BoatSide::Stbd);
191 | return std::make_pair(port_point, stbd_point);
192 | }
193 | return std::make_pair(XYPoint(), XYPoint());
194 | }
195 |
196 | double RecordSwath::SwathWidth(BoatSide side, unsigned int index)
197 | {
198 | if (m_min_record.size() > index)
199 | {
200 | std::list::iterator list_record = std::next(m_min_record.begin(), index);
201 | if (side == BoatSide::Stbd)
202 | {
203 | return list_record->swath_stbd;
204 | }
205 | else if (side == BoatSide::Port)
206 | {
207 | return list_record->swath_port;
208 | }
209 | }
210 | return 0;
211 | }
212 |
213 | std::vector RecordSwath::AllSwathWidths(BoatSide side)
214 | {
215 | std::vector widths;
216 | widths.reserve(m_min_record.size());
217 | std::list::iterator list_record;
218 | for (list_record = m_min_record.begin(); list_record != m_min_record.end(); list_record++)
219 | {
220 | if (side == BoatSide::Stbd)
221 | {
222 | widths.push_back(list_record->swath_stbd);
223 | }
224 | else if (side == BoatSide::Port)
225 | {
226 | widths.push_back(list_record->swath_port);
227 | }
228 | }
229 | return widths;
230 | }
231 |
232 | XYPoint RecordSwath::SwathLocation(unsigned int index)
233 | {
234 | if (m_min_record.size() > index)
235 | {
236 | std::list::iterator list_record = std::next(m_min_record.begin(), index);
237 | return XYPoint(list_record->loc_x, list_record->loc_y);
238 | }
239 | throw std::out_of_range("Swath index out of range.");
240 | return XYPoint();
241 | }
242 |
243 | bool RecordSwath::ValidRecord()
244 | {
245 | return (m_min_record.size() > 1);
246 | }
247 |
--------------------------------------------------------------------------------
/src/RecordSwath.h:
--------------------------------------------------------------------------------
1 | /**
2 | * @file RecordSwath.h
3 | * @brief Records a swath history from a sonar on a moving vehicle.
4 | * @details Also gives the outer points at the edge of the swath along a track.
5 | * @author Damian Manda
6 | * @date 23 Feb 2016
7 | * @copyright MIT License
8 | */
9 |
10 | #ifndef SurveyPath_RecordSwath_HEADER
11 | #define SurveyPath_RecordSwath_HEADER
12 |
13 | //MOOS Headers
14 | #include "XYPoint.h"
15 | #include "XYSegList.h"
16 | #include "XYVector.h"
17 |
18 | #include
19 | #include
20 | #include