12 m_robot_sites.clear();
13 for (
int rid = 0; rid < m_p_de->m_pose2d.size(); ++rid)
14 m_robot_sites.push_back(
Point_2(m_p_de->m_pose2d[rid].translation().x(), m_p_de->m_pose2d[rid].translation().y()));
20 cv::Mat map_mat = m_p_de->visCellMap();
23 for (
int i = 0; i < binary_mat.rows; i++)
25 for (
int j = 0; j < binary_mat.cols; j++)
27 binary_mat.ptr<
uchar>(i)[j] = 0;
28 if (map_mat.ptr<cv::Vec3b>(i)[j][0] + map_mat.ptr<cv::Vec3b>(i)[j][1] + map_mat.ptr<cv::Vec3b>(i)[j][2] != 0)
29 binary_mat.ptr<
uchar>(i)[j] = 255;
34 for (
int i = 0; i < bd_gray_mat.rows; i++)
36 for (
int j = 0; j < bd_gray_mat.cols; j++)
38 bd_gray_mat.ptr<
uchar>(i)[j] = binary_mat.ptr<
uchar>(i)[j];
41 cv::dilate(bd_gray_mat, bd_gray_mat, cv::getStructuringElement(0, cv::Size(3, 3)));
43 cv::threshold(bd_gray_mat, bd_bin_mat, 0, 255, cv::THRESH_BINARY);
44 cv::dilate(bd_bin_mat, bd_bin_mat, cv::getStructuringElement(0, cv::Size(3, 3)));
45 cv::erode(bd_bin_mat, bd_bin_mat, cv::getStructuringElement(0, cv::Size(3, 3)));
46 cv::erode(bd_bin_mat, bd_bin_mat, cv::getStructuringElement(0, cv::Size(3, 3)));
48 vector<vector<cv::Point>> bd_contours;
49 vector<vector<cv::Point>> dilate_contours_0;
50 cv::findContours(binary_mat, bd_contours, CV_RETR_LIST, CV_CHAIN_APPROX_NONE);
51 cv::findContours(bd_bin_mat, dilate_contours_0, CV_RETR_LIST, CV_CHAIN_APPROX_NONE);
53 int dc_max_size_0 = 0;
54 int dc_max_index_0 = 0;
55 for (
int i = 0; i < dilate_contours_0.size(); i++)
57 if (dilate_contours_0[i].size()>dc_max_size_0)
59 dc_max_size_0 = dilate_contours_0[i].size();
65 m_boundary = dilate_contours_0[dc_max_index_0];
77 for (
int i = 0; i < bd_contours.size(); i++)
79 if (bd_contours[i].size()>c_max_size){
80 c_max_size = bd_contours[i].size();
88 vector<cv::Point> samples_exploration;
89 vector<cv::Point> all_exploration;
94 for (
int contour_id = 0; contour_id < bd_contours.size(); contour_id++)
96 if (bd_contours[contour_id].size() <= 4)
98 for (
int i = 0; i < bd_contours[contour_id].size(); i++)
100 if (m_p_de->m_recon2D.m_cellmap[bd_contours[contour_id][i].y][bd_contours[contour_id][i].x].isScanned && m_p_de->m_recon2D.m_cellmap[bd_contours[contour_id][i].y][bd_contours[contour_id][i].x].isFree)
102 bool is_frontier =
true;
103 for (
int r = -1; r <= 1; r++)
105 for (
int c = -1; c <= 1; c++)
107 if (m_p_de->m_recon2D.m_cellmap[bd_contours[contour_id][i].y + r][bd_contours[contour_id][i].x + c].isScanned && m_p_de->m_recon2D.m_cellmap[bd_contours[contour_id][i].y + r][bd_contours[contour_id][i].x + c].isOccupied)
115 frontier_mat.ptr<
uchar>(bd_contours[contour_id][i].y)[bd_contours[contour_id][i].x] = 255;
122 if (frontier_mat.ptr<
uchar>(r)[c] == 255)
123 all_exploration.push_back(cv::Point(c, r));
124 for (
int i = 0; i < all_exploration.size(); i++)
127 double min_dis = DBL_MAX;
128 for (
int tid = 0; tid < samples_exploration.size(); tid++)
130 Eigen::Vector2f pf(all_exploration[i].x, all_exploration[i].y);
131 Eigen::Vector2f pt(samples_exploration[tid].x, samples_exploration[tid].y);
132 double crt_dis = (pf - pt).norm();
133 if (__isnan(crt_dis) != 0)
135 if (crt_dis < min_dis)
140 samples_exploration.push_back(cv::Point(all_exploration[i].x, all_exploration[i].y));
144 int ft_num = all_exploration.size();
146 m_frontiers = all_exploration;
149 cerr <<
"no frontier." << endl;
157 cv::Mat img = map_mat.clone();
158 for (
int i = 0; i < img.rows; i++)
160 for (
int j = 0; j < img.cols; j++)
162 img.ptr<cv::Vec3b>(i)[j][0] = 0;
163 img.ptr<cv::Vec3b>(i)[j][1] = 0;
166 cv::Mat gray_map(img.rows, img.cols, CV_8UC1);
168 cv::cvtColor(img, gray_map, CV_BGR2GRAY);
169 cv::threshold(gray_map, bin_map, 0, 255, cv::THRESH_BINARY);
171 dilate(bin_map, bin_map, cv::getStructuringElement(0, cv::Size(
offset_size * 2 + 1,
offset_size * 2 + 1)));
180 if (m_p_de->m_recon2D.m_cellmap[mid.y][mid.x].isScanned)
182 if (m_p_de->m_recon2D.m_cellmap[mid.y][mid.x].isOccupied)
192 for (
int r = min_y; r <= max_y; r++)
193 for (
int c = min_x; c <= max_x; c++)
194 bin_map.ptr<
uchar>(r)[c] = 0;
197 cv::imwrite(pth, bin_map);
201 int min_x = mid.x-10,
205 for (
int r = min_y; r <= max_y; r++)
206 for (
int c = min_x; c <= max_x; c++)
207 bin_map.ptr<
uchar>(r)[c] = 0;
210 cv::imwrite(pth, bin_map);
215 cerr<<
"not a occupied voxel. continue?"<<endl;
264 vector<vector<cv::Point>> contours;
265 vector<cv::Vec4i> hierarchy;
266 cv::findContours(bin_map, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_NONE);
269 for (
int i = 0; i < hierarchy.size(); i++)
271 if (hierarchy[i][3] != -1)
272 dlt_idx.push_back(i);
275 if (dlt_idx.size() > 0){
276 for (
int i = dlt_idx.size() - 1; i >= 0; i--)
279 auto it = contours.begin() + dlt_idx[i];
308 vector<int> deleteIndexes;
309 for (
int hid = 0; hid < contours.size(); hid++)
310 if (contours[hid].size() < 3)
311 deleteIndexes.push_back(hid);
312 if (!deleteIndexes.empty())
313 for (
int i = deleteIndexes.size() - 1; i >= 0; i--)
314 contours.erase(contours.begin() + deleteIndexes[i]);
332 cerr <<
"polygon point number = " << poly.size() << endl;
334 vector<Eigen::Vector2d> polygon;
335 for (
int i = 0; i < poly.size(); i++)
339 Eigen::Vector2d lst(polygon.back());
340 Eigen::Vector2d crt(poly[i].x(), poly[i].y());
341 if ((crt - lst).norm() < 0.01)
344 polygon.push_back(Eigen::Vector2d(poly[i].x(), poly[i].y()));
347 vector<int> keyIndexes;
348 for (
int i = 0; i < polygon.size(); i++)
350 int last = (i - 1 + polygon.size()) % polygon.size();
351 int next = (i + 1) % polygon.size();
352 Eigen::Vector2d vec1 = polygon[i] - polygon[last];
354 Eigen::Vector2d vec2 = polygon[next] - polygon[i];
356 double dangle =
acos(vec1.dot(vec2));
358 if (dangle < colinearThresh)
360 keyIndexes.push_back(i);
363 vector<Point_2> newPolygon;
364 for (
int i = 0; i < keyIndexes.size(); i++)
366 newPolygon.push_back(
Point_2(polygon[keyIndexes[i]].x() + (
double)rand() / RAND_MAX / 10, polygon[keyIndexes[i]].y() + (
double)rand() / RAND_MAX / 10));
368 newPolygon.push_back(
Point_2(polygon[keyIndexes[i]].x(), polygon[keyIndexes[i]].y()));
369 if (newPolygon.size() < 3)
371 cerr <<
"simplify error, polygon.size() = " << newPolygon.size() << endl;
374 poly =
Polygon_2(newPolygon.begin(), newPolygon.end());
375 cerr <<
"simplified point number = " << poly.size() << endl;
413 cerr <<
"dsy: polygons difference result = 0" << endl;
415 res.push_back(domain);
450 vector<Point_2> vertexes;
451 for (
int i = 0; i < m_boundary.size(); i++)
452 vertexes.push_back(
Point_2(m_boundary[i].x, -m_boundary[i].y));
453 Polygon_2 boundary(vertexes.begin(), vertexes.end());
454 if (boundary.area() < 0)
455 boundary.reverse_orientation();
457 bool self_intersect =
false;
458 vector<Point_2> points;
459 set<Point_2> test_points;
460 for (
size_t pid = 0; pid < boundary.size(); pid++)
462 if (test_points.find(
Point_2(boundary[pid].x(), boundary[pid].y())) == test_points.end()){
463 test_points.insert(
Point_2(boundary[pid].x(), boundary[pid].y()));
464 points.push_back(
Point_2(boundary[pid].x(), boundary[pid].y()));
467 self_intersect =
true;
469 double vx = boundary[pid].x() - boundary[pid - 1].x();
470 double vy = boundary[pid].y() - boundary[pid - 1].y();
472 vx =
cos(theta)*vx -
sin(theta)*vy;
473 vy =
sin(theta)*vx +
cos(theta)*vy;
474 double x = boundary[pid - 1].x() + vx;
475 double y = boundary[pid - 1].y() + vy;
476 test_points.insert(
Point_2(x, y));
477 points.push_back(
Point_2(x, y));
481 boundary =
Polygon_2(points.begin(), points.end());
482 if (boundary.area() < 0)
483 boundary.reverse_orientation();
485 simplifyPolygon(boundary, 0.2,
false);
494 vector<Polygon_2> holes;
495 origin_holes.clear();
496 vector<cv::Point> bdry;
497 for (
int i = 0; i < boundary.size(); i++)
498 bdry.push_back(cv::Point(
round(boundary[i].x()), -
round(boundary[i].y())));
500 for (
int hid = 0; hid < m_holes.size(); hid++)
503 for (
int vid = 0; vid < m_holes[hid].size(); vid++)
505 p_pass.push_back(
Point_2(m_holes[hid][vid].x, -m_holes[hid][vid].y));
507 origin_holes.push_back(p_pass);
512 for (
int i = 0; i < origin_holes.size(); i++)
514 if (origin_holes[i].area() > 0)
515 origin_holes[i].reverse_orientation();
516 holes.push_back(origin_holes[i]);
519 for (
int hid = 0; hid < holes.size(); hid++)
521 bool self_intersect =
false;
522 vector<Point_2> points;
523 set<Point_2> test_points;
524 for (
int pid = 0; pid < holes[hid].size(); pid++)
526 if (test_points.find(
Point_2(holes[hid][pid].x(), holes[hid][pid].y())) == test_points.end())
528 test_points.insert(
Point_2(holes[hid][pid].x(), holes[hid][pid].y()));
529 points.push_back(
Point_2(holes[hid][pid].x(), holes[hid][pid].y()));
533 self_intersect =
true;
535 double vx = holes[hid][pid].x() - holes[hid][pid - 1].x();
536 double vy = holes[hid][pid].y() - holes[hid][pid - 1].y();
538 vx =
cos(theta)*vx -
sin(theta)*vy;
539 vy =
sin(theta)*vx +
cos(theta)*vy;
540 double x = holes[hid][pid - 1].x() + vx;
541 double y = holes[hid][pid - 1].y() + vy;
542 test_points.insert(
Point_2(x, y));
543 points.push_back(
Point_2(x, y));
547 holes[hid] =
Polygon_2(points.begin(), points.end());
548 if (holes[hid].area() < 0)
549 holes[hid].reverse_orientation();
553 for (
int hid = 0; hid < holes.size(); hid++)
555 simplifyPolygon(holes[hid], 0.1,
true);
566 for (
size_t hid = 0; hid < holes.size(); hid++)
567 if (holes[hid].size() == 0)
568 dlt_idx.push_back(hid);
569 if (!dlt_idx.empty())
571 for (
int id = dlt_idx.size() - 1;
id >= 0;
id--)
573 holes.erase(holes.begin() + dlt_idx[id]);
578 cerr <<
"error, holes empty" << endl;
583 domain.outer_boundary() = boundary;
584 for (
int hid = 0; hid < holes.size(); hid++)
587 results = differenceCGALExactKernel(domain, holes[hid]);
591 if (results.size() != 1
594 for (
auto i = results.begin(); i != results.end(); i++)
595 if (i->outer_boundary().size() > max_size)
596 max_size = i->outer_boundary().size();
597 for (
auto i = results.begin(); i != results.end(); i++)
599 if (i->outer_boundary().size() == max_size)
613 boundary =
Polygon_2(domain.outer_boundary());
615 for (
auto i = domain.holes_begin(); i != domain.holes_end(); i++)
619 vector<Point_2> pass_polygon;
620 for (
int pid = 0; pid < boundary.size(); pid++)
621 pass_polygon.push_back(
Point_2(boundary[pid].x() + (rand() / RAND_MAX) / 10, boundary[pid].y() + (rand() / RAND_MAX) / 10));
622 boundary =
Polygon_2(pass_polygon.begin(), pass_polygon.end());
624 bool self_intersect =
false;
625 vector<Point_2> points;
626 set<Point_2> test_points;
627 for (
size_t pid = 0; pid < boundary.size(); pid++)
629 if (test_points.find(
Point_2(boundary[pid].x(), boundary[pid].y())) == test_points.end())
631 test_points.insert(
Point_2(boundary[pid].x(), boundary[pid].y()));
632 points.push_back(
Point_2(boundary[pid].x(), boundary[pid].y()));
636 self_intersect =
true;
638 double vx = boundary[pid].x() - boundary[pid - 1].x();
639 double vy = boundary[pid].y() - boundary[pid - 1].y();
641 vx =
cos(theta)*vx -
sin(theta)*vy;
642 vy =
sin(theta)*vx +
cos(theta)*vy;
643 double x = boundary[pid - 1].x() + vx;
644 double y = boundary[pid - 1].y() + vy;
645 test_points.insert(
Point_2(x, y));
646 points.push_back(
Point_2(x, y));
650 boundary =
Polygon_2(points.begin(), points.end());
651 if (boundary.area() < 0)
652 boundary.reverse_orientation();
662 boundary = load_and_check_boundary();
664 holes = load_and_check_holes(boundary, origin_holes);
666 correct_boundary_holes(boundary, holes);
674 CDT::Face_handle start,
676 std::list<CDT::Edge>& border)
678 if (start->info().nesting_level != -1){
681 std::list<CDT::Face_handle> queue;
682 queue.push_back(start);
683 while (!queue.empty()){
684 CDT::Face_handle fh = queue.front();
686 if (fh->info().nesting_level == -1){
687 fh->info().nesting_level = index;
688 for (
int i = 0; i < 3; i++){
690 CDT::Face_handle n = fh->neighbor(i);
691 if (n->info().nesting_level == -1){
692 if (ct.is_constrained(e)) border.push_back(e);
693 else queue.push_back(n);
704 for (CDT::All_faces_iterator it = cdt.all_faces_begin(); it != cdt.all_faces_end(); ++it){
705 it->info().nesting_level = -1;
707 std::list<CDT::Edge> border;
709 while (!border.empty()){
710 CDT::Edge e = border.front();
712 CDT::Face_handle n = e.first->neighbor(e.second);
713 if (n->info().nesting_level == -1){
714 mark_domains(cdt, n, e.first->info().nesting_level + 1, border);
722 vector<int> rbt_sites_indexes;
723 vector<Point_2> vertices;
726 vector<Point_2> vertices_all;
727 for (CDT::Finite_vertices_iterator vit = cdt.finite_vertices_begin();
728 vit != cdt.finite_vertices_end(); ++vit){
729 vertices_all.push_back(
Point_2(vit->point().x(), vit->point().y()));
734 int* flag =
new int[60000];
735 for (
size_t i = 0; i < vertices_all.size(); i++)
739 for (CDT::Finite_faces_iterator fit = cdt.finite_faces_begin();
740 fit != cdt.finite_faces_end(); ++fit)
742 if (fit->info().in_domain()) {
743 for (
size_t i = 0; i < 3; i++)
745 for (
size_t j = 0; j < vertices_all.size(); j++)
747 if (fit->vertex(i)->point() == vertices_all[j]){
755 for (
size_t i = 0; i < vertices_all.size(); i++)
758 vertices.push_back(
Point_2(vertices_all[i].x(), vertices_all[i].y()));
768 for (
size_t i = 0; i < vertices.size(); i++)
770 obj_out <<
"v " << vertices[i].x() <<
" " << vertices[i].y() <<
" 0" << endl;
773 for (CDT::Finite_faces_iterator fit = cdt.finite_faces_begin();
774 fit != cdt.finite_faces_end(); ++fit)
776 if (fit->info().in_domain()) {
778 for (
size_t i = 0; i < 3; i++)
780 for (
size_t j = 0; j < vertices.size(); j++)
782 if (fit->vertex(i)->point() == vertices[j]){
783 obj_out << j + 1 <<
" ";
883 cdt.insert_constraint(boundary.vertices_begin(), boundary.vertices_end(),
true);
885 for (
size_t i = 0; i < boundary.size(); i++)
887 tmpSet.insert(
Point_2(boundary[i].x(), boundary[i].y()));
890 for (
size_t id = 0;
id < holes.size();
id++)
891 cdt.insert_constraint(holes[
id].vertices_begin(), holes[id].vertices_end(),
true);
893 for (
size_t i = 0; i < holes.size(); i++)
895 for (
size_t j = 0; j < holes[i].size(); j++)
897 tmpSet.insert(
Point_2(holes[i][j].x(), holes[i][j].y()));
906 for (
size_t i = 0; i < tasks.size(); i++)
908 tmpSet.insert(
Point_2(tasks[i].view.pose.translation().x(), tasks[i].view.pose.translation().y()));
914 for (
size_t i = 0; i < m_robot_sites.size(); i++)
916 for (
size_t j = 0; j < holes.size(); j++)
918 CGAL::Bounded_side bs = CGAL::bounded_side_2(holes[j].vertices_begin(), holes[j].vertices_end(), m_robot_sites[i]);
919 if (bs == CGAL::ON_BOUNDED_SIDE)
922 if (CGAL::bounded_side_2(origin_holes[j].vertices_begin(), origin_holes[j].vertices_end(), m_robot_sites[i]) == CGAL::ON_BOUNDED_SIDE)
924 cerr <<
"error, move into a hole" << endl;
927 double min_dis = DBL_MAX;
929 for (
size_t k = 0; k < holes[j].size(); k++)
932 sqrt((holes[j][k].x() - m_robot_sites[i].x())*(holes[j][k].x() - m_robot_sites[i].x())
933 + (holes[j][k].y() - m_robot_sites[i].y())*(holes[j][k].y() - m_robot_sites[i].y()))
937 min_dis =
sqrt((holes[j][k].x() - m_robot_sites[i].x())*(holes[j][k].x() - m_robot_sites[i].x())
938 + (holes[j][k].y() - m_robot_sites[i].y())*(holes[j][k].y() - m_robot_sites[i].y()));
943 m_robot_sites[i] =
Point_2(holes[j][min_index].x(), holes[j][min_index].y());
951 for (
int i = 0; i < tasks.size(); i++)
952 tmpSet.insert(
Point_2(tasks[i].view.pose.translation().x(), tasks[i].view.pose.translation().y()));
956 for (
size_t i = 0; i < m_robot_sites.size(); i++)
957 tmpSet.insert(
Point_2(m_robot_sites[i].x(), m_robot_sites[i].y()));
959 CGAL::Bbox_2 box = boundary.bbox();
961 double delta_x = (box.xmax() - box.xmin()) / site_num;
962 double delta_y = (box.ymax() - box.ymin()) / site_num;
963 for (
int i = 0; i < site_num; i++)
965 for (
int j = 0; j < site_num; j++)
967 double x = box.xmin() + i*delta_x + (double)(rand() % 10) / 6;
968 double y = box.ymin() + j*delta_y + (double)(rand() % 10) / 6;
972 if (CGAL::bounded_side_2(boundary.vertices_begin(), boundary.vertices_end(), pt) != CGAL::ON_BOUNDED_SIDE)
974 for (
size_t hid = 0; hid < holes.size(); hid++)
975 if (CGAL::bounded_side_2(holes[hid].vertices_begin(), holes[hid].vertices_end(), pt) != CGAL::ON_UNBOUNDED_SIDE)
983 double distanceSquare = FLT_MAX;
984 for (set<Point_2>::const_iterator it = tmpSet.begin(); it != tmpSet.end(); ++it)
986 if ((*it - pt).squared_length() < distanceSquare)
987 distanceSquare = (*it - pt).squared_length();
989 if (distanceSquare > 2e-3 * 2e-3)
998 cdt.insert(tmpSet.begin(), tmpSet.end());
1008 for (
int fid = 0; fid < m_frontiers.size(); ++fid)
1010 m_frontiers_p2.push_back(
Point_2(m_frontiers[fid].x, -m_frontiers[fid].y));
1012 return m_frontiers_p2;
1019 m_frontierList.clear();
1020 vector<int> indexes;
1021 vector<Point_2> tasks;
1022 vector<cv::Point> boundary;
1023 for (
int pid = 0; pid < outer.size(); pid++)
1025 boundary.push_back(cv::Point(
round(outer[pid].x()), -
round(outer[pid].y())));
1027 vector<vector<cv::Point>> holes;
1028 for (
int hid = 0; hid < iner.size(); hid++)
1030 vector<cv::Point> hole;
1031 for (
int pid = 0; pid < iner[hid].size(); pid++)
1033 hole.push_back(cv::Point(
round(iner[hid][pid].x()), -
round(iner[hid][pid].y())));
1035 holes.push_back(hole);
1038 for (
int i = 0; i < m_frontiers_p2.size(); i++)
1041 bool visible =
true;
1045 for (
auto unvisible_task = task_maybe_invalid.begin(); unvisible_task != task_maybe_invalid.end(); unvisible_task++)
1047 if (fabs(m_frontiers_p2[i].x() - unvisible_task->x()) < 1 && fabs(m_frontiers_p2[i].y() - unvisible_task->y()) < 1)
1056 if (cv::pointPolygonTest(boundary, cv::Point(
round(m_frontiers_p2[i].x()), -
round(m_frontiers_p2[i].y())),
false) < 0)
1059 double d = fabs(cv::pointPolygonTest(boundary, cv::Point(
round(m_frontiers_p2[i].x()), -
round(m_frontiers_p2[i].y())),
true));
1063 err =
"out of boundary.";
1068 for (
int hid = 0; hid < holes.size(); hid++)
1070 if (cv::pointPolygonTest(holes[hid], cv::Point(
round(m_frontiers_p2[i].x()), -
round(m_frontiers_p2[i].y())),
false) > 0)
1073 double d = fabs(cv::pointPolygonTest(holes[hid], cv::Point(
round(m_frontiers_p2[i].x()), -
round(m_frontiers_p2[i].y())),
true));
1090 if (cv::pointPolygonTest(
g_scene_boundary, cv::Point(
round(m_frontiers_p2[i].x()), -
round(m_frontiers_p2[i].y())),
false) <= 0)
1093 err =
"out of scene_boundary.";
1095 else if(cv::pointPolygonTest(
g_scene_boundary, cv::Point(
round(m_frontiers_p2[i].x()), -
round(m_frontiers_p2[i].y())),
true) < 2)
1098 err =
"out of scene_boundary. too close to boundary.";
1105 const int delta = 3;
1106 const int thresh = 6;
1107 int unknownCounter = 0;
1108 cv::Point vox(
round(m_frontiers_p2[i].x()), -
round(m_frontiers_p2[i].y()));
1109 int beg_r = vox.y - delta < 0 ? 0 : vox.y - delta;
1111 int beg_c = vox.x - delta < 0 ? 0 : vox.x - delta;
1113 for (
int r = beg_r; r <= end_r; r++)
1114 for (
int c = beg_c; c <= end_c; c++)
1115 if (!m_p_de->m_recon2D.m_cellmap[r][c].isScanned)
1117 if (unknownCounter <= thresh)
1146 cv::Point crt_p(
round(m_frontiers_p2[i].x()), -
round(m_frontiers_p2[i].y()));
1147 bool already_explored =
true;
1149 for (
int dr = -radius; dr <= radius; ++dr)
1151 for (
int dc = -radius; dc <= radius; ++dc)
1153 if (!m_p_de->m_recon2D.m_cellmap[crt_p.y+dr][crt_p.x+dc].isScanned)
1155 already_explored =
false;
1159 if (already_explored)
1162 err =
'already explored.';
1169 tasks.push_back(
Point_2(m_frontiers_p2[i].x(), m_frontiers_p2[i].y()));
1170 indexes.push_back(i);
1172 m_frontierList.push_back(fe);
1184 const int thresh = 30;
1185 const int kernelR = 3;
1187 cv::Mat img = m_p_de->visCellMap();
1189 cv::Mat freeSpaces = cv::Mat::zeros(img.rows, img.cols, CV_8UC1);
1190 for (
int r = 0; r < img.rows; r++)
1192 for (
int c = 0; c < img.cols; c++)
1194 if (img.ptr<cv::Vec3b>(r)[c][1] == 255)
1195 freeSpaces.ptr<
uchar>(r)[c] = 10;
1199 cv::Mat LocationMap = cv::Mat::zeros(img.rows, img.cols, CV_8UC1);
1200 LocationMap += freeSpaces;
1202 for (
int step = 0; step < thresh; step++)
1204 cv::erode(freeSpaces, freeSpaces, cv::getStructuringElement(0, cv::Size(kernelR * 2, kernelR * 2)));
1205 LocationMap += freeSpaces;
1214 const int invalidValue = 255;
1215 cv::Point beg(source);
1216 cv::Point end(target);
1218 for (
int r = 0; r < domain.rows; r++)
1220 for (
int c = 0; c < domain.cols; c++)
1223 if (m_p_de->m_recon2D.m_cellmap[r][c].isScanned && m_p_de->m_recon2D.m_cellmap[r][c].isFree)
1230 domain.ptr<
uchar>(r)[c] = invalidValue;
1235 bool occlusion =
false;
1236 int dx = end.x - beg.x;
1237 int dy = end.y - beg.y;
1240 int beg_y = beg.y < end.y ? beg.y : end.y;
1241 int end_y = beg.y > end.y ? beg.y : end.y;
1242 for (
int y = beg_y; y < end_y; y++)
1243 if (domain.ptr<
uchar>(y)[beg.x] == invalidValue)
1251 int beg_x = beg.x < end.x ? beg.x : end.x;
1252 int end_x = beg.x > end.x ? beg.x : end.x;
1253 for (
int x = beg_x; x < end_x; x++)
1254 if (domain.ptr<
uchar>(beg.y)[x] == invalidValue)
1260 else if (dx == 0 && dy == 0){}
1264 double fXUnitLen = 1.0;
1265 double fYUnitLen = 1.0;
1266 fYUnitLen = (double)(dy) / (double)(MaxStep);
1267 fXUnitLen = (double)(dx) / (double)(MaxStep);
1268 double x = (double)(beg.x);
1269 double y = (double)(beg.y);
1271 for (
long i = 1; i < MaxStep; i++)
1290 Eigen::Vector2d direction(0, 1);
1294 r <<
cos(angle), -
sin(angle),
1296 direction = r*direction;
1301 double scale = (double)m_p_de->scan_max_range / 1000 /
map_cellsize;
1302 scale /=
cos(
PI / 6);
1303 direction = scale*direction;
1307 Eigen::Vector2d vec(direction);
1308 double angle =
PI / 6;
1310 r <<
cos(angle), -
sin(angle),
1313 lp = position + vec;
1319 Eigen::Vector2d vec(direction);
1320 double angle = -
PI / 6;
1322 r <<
cos(angle), -
sin(angle),
1325 rp = position + vec;
1329 cv::Point p_o((
int)
round(position.x()), -(
int)
round(position.y()));
1330 cv::Point p_l((
int)
round(lp.x()), -(
int)
round(lp.y()));
1331 cv::Point p_r((
int)
round(rp.x()), -(
int)
round(rp.y()));
1335 vector<cv::Point> result;
1336 result.push_back(p_o);
1337 result.push_back(p_l);
1338 result.push_back(p_r);
1346 srand((
unsigned)time(NULL));
1348 vector<NextBestView> nbvs;
1349 vector<FrontierElement> frontier_list;
1350 for (
int i = 0; i < m_frontierList.size(); i++)
1354 if ((
double)rand() / RAND_MAX < sampleRate)
1356 frontier_list.push_back(m_frontierList[i]);
1361 frontier_list.push_back(m_frontierList[i]);
1367 cv::Mat statement = m_p_de->visCellMap();
1368 cv::Mat temp = statement.clone();
1370 for (
int fid = 0; fid < m_frontierList.size(); fid++)
1372 int x = m_frontierList[fid].position.x();
1373 int y = -m_frontierList[fid].position.y();
1374 cv::circle(temp, cv::Point(x, y), 0, CV_RGB(255, 255, 255));
1375 cv::circle(temp, cv::Point(x, y), 1, CV_RGB(255, 255, 255));
1376 cv::circle(temp, cv::Point(x, y), 2, CV_RGB(255, 255, 255));
1379 for (
int fid = 0; fid < frontier_list.size(); fid++)
1381 int x = frontier_list[fid].position.x();
1382 int y = -frontier_list[fid].position.y();
1383 cv::circle(temp, cv::Point(x, y), 1, CV_RGB(255, 0, 255));
1386 for (
auto it = task_maybe_invalid.begin(); it != task_maybe_invalid.end(); it++)
1390 cv::circle(temp, cv::Point(x, y), 1, CV_RGB(0, 255, 255));
1399 char output_path[200];
1401 cv::imwrite(output_path, temp);
1404 cv::Mat locaMap = computeLoationMap();
1406 while (!frontier_list.empty())
1409 cv::Point fp(current_frontier.
position.x(), -current_frontier.
position.y());
1410 vector<cv::Point> vps;
1411 const int rangeMIN = 10;
1412 const int rangeMAX = 40;
1413 int delta = rangeMAX;
1414 int beg_r = fp.y - delta < 0 ? 0 : fp.y - delta;
1416 int beg_c = fp.x - delta < 0 ? 0 : fp.x - delta;
1418 for (
int r = beg_r; r <= end_r; r++)
1420 for (
int c = beg_c; c <= end_c; c++)
1423 if (m_p_de->m_recon2D.m_cellmap[r][c].isScanned && m_p_de->m_recon2D.m_cellmap[r][c].isFree)
1425 if ((
double)rand() / RAND_MAX < 0.995)
1427 double eDistance = m_metric.get_euclidean_distance(cv::Point(c, r), fp);
1428 if (eDistance > rangeMIN)
1430 if (checkViewRayValidness(cv::Point(c, r), fp))
1433 vps.push_back(cv::Point(c, r));
1440 const int numMax = 10;
1441 if (vps.size() > numMax)
1443 int num = vps.size() - numMax;
1444 for (
int i = 0; i < num; i++)
1446 int idx = (int)
floor(rand() % (vps.size() - 1));
1447 vps.erase(vps.begin() + idx);
1451 vector<double> scores;
1452 scores.resize(vps.size());
1453 for (
int idx = 0; idx < scores.size(); idx++)
1455 scores[idx] = locaMap.ptr<
uchar>(vps[idx].y)[vps[idx].x];
1457 double max_score = -1;
1458 double max_index = -1;
1459 for (
int idx = 0; idx < vps.size(); idx++)
1461 if (max_score < scores[idx])
1463 max_score = scores[idx];
1468 if (max_index == -1)
1470 task_maybe_invalid.insert(
Point_2(frontier_list.begin()->position.x() + (double)rand() / RAND_MAX / 10, frontier_list.begin()->position.y()));
1471 frontier_list.erase(frontier_list.begin());
1478 cv::Point nbp = vps[max_index];
1479 Eigen::Vector2d base(0.0, 1.0);
1480 Eigen::Vector2d dire(fp.x - nbp.x, -fp.y + nbp.y);
1482 double theta =
acos(base.dot(dire) / (dire.norm() * base.norm()));
1487 nbvs.push_back(nbv);
1492 frontier_list.erase(frontier_list.begin());
1494 vector<int> dlt_indexes;
1495 vector<cv::Point> nbv_frustum = get_frustum_contuor(nbv.pose);
1496 for (
int i = 0; i < frontier_list.size(); i++)
1499 if (cv::pointPolygonTest(nbv_frustum, cv::Point((
int)
round(frontier_list[i].position.x()), -(
int)
round(frontier_list[i].position.y())),
false) > 0)
1502 cv::Point beg((
int)
round(nbv.pose.translation().x()), -(
int)
round(nbv.pose.translation().y()));
1503 cv::Point end((
int)
round(frontier_list[i].position.x()), -(
int)
round(frontier_list[i].position.y()));
1505 if (checkViewRayValidness(beg, end))
1506 dlt_indexes.push_back(i);
1509 if (!dlt_indexes.empty())
1511 for (
int i = dlt_indexes.size() - 1; i >= 0; i--)
1513 frontier_list.erase(frontier_list.begin() + dlt_indexes[i]);
1525 cerr <<
"computing views for frontiers...";
1527 vector<NextBestView> valid_frontier_nbvs;
1529 vector<int> task_index_in_valid_frontier_nbvs;
1531 vector<int> frontier_task_indexes;
1533 preprocess_frontiers(boundary, holes);
1534 for (
int i = 0; i < m_frontierList.size(); i++)
1535 frontier_task_indexes.push_back(i);
1536 frt_num = frontier_task_indexes.size();
1537 vector<NextBestView> frontier_task_nbvs;
1539 vector<NextBestView> nbvs_frt;
1544 nbvs_frt = generateViewsFrontiers(
true, 0.5);
1545 valid_frontier_nbvs = nbvs_frt;
1547 for (
int i = 0; i < nbvs_frt.size(); i++)
1550 for (
int j = 0; j < frontier_task_indexes.size(); j++)
1552 if (nbvs_frt[i].index == frontier_task_indexes[j])
1560 frontier_task_nbvs.push_back(nbvs_frt[i]);
1561 task_index_in_valid_frontier_nbvs.push_back(i);
1564 frt_num = frontier_task_nbvs.size();
1574 cerr<<
"done."<<endl;
1575 return frontier_task_nbvs;
1582 m_valid_object_nbvs.clear();
1583 m_task_index_in_valid_object_nbvs.clear();
1584 vector<NextBestView> object_task_nbvs;
1666 return object_task_nbvs;
1673 vector<NextBestView> frontier_tasks = compute_frontier_tasks(boundary, holes);
1674 int frt_num = frontier_tasks.size();
1675 vector<double> frontier_task_distances(frontier_tasks.size());
1679 vector<Point_2> rbtPoses(m_robot_sites);
1681 for (
int fid = 0; fid < frontier_tasks.size(); fid++)
1684 if (__isnan(frontier_tasks[fid].pose.translation().x()) || __isnan(frontier_tasks[fid].pose.translation().y()))
1686 cerr<<
"frontier_tasks["<<fid<<
"] nan: "<<frontier_tasks[fid].pose.translation().transpose()<<endl;
1687 getchar(); getchar(); getchar();
1691 double min_d = 999999999;
1693 vector<Point_2> targets;
1694 for (
int rid = 0; rid < rbtPoses.size(); rid++)
1695 targets.push_back(rbtPoses[rid]);
1696 Point_2 taskP(frontier_tasks[fid].pose.translation().x(), frontier_tasks[fid].pose.translation().y());
1697 vector<double> distances = m_metric.getGeodesicDistances(taskP, targets);
1698 for (
int rid = 0; rid < distances.size(); rid++)
1699 if (min_d > distances[rid])
1700 min_d = distances[rid];
1702 frontier_task_distances[fid] = min_d;
1708 vector<NextBestView> object_tasks = extractQualityTaskViews(boundary, holes);
1709 int ldmk_num = object_tasks.size();
1720 object_tasks = extractQualityTaskViews(boundary, holes);
1721 ldmk_num = object_tasks.size();
1731 for (
int i = 0; i < frontier_tasks.size(); i++)
1735 if (tasks.size() > m_max_task_num)
1737 int d_num = tasks.size() - m_max_task_num;
1738 for (
int i = 0; i < d_num; i++)
1742 double maxValue = 0;
1744 for (
int index = 0; index < frontier_task_distances.size(); index++)
1746 if (frontier_task_distances[index] > maxValue)
1748 maxValue = frontier_task_distances[index];
1754 cerr <<
"error, ID = -1" << endl; getchar(); getchar(); getchar();
1756 tasks.erase(tasks.begin() + maxID);
1757 frontier_task_distances.erase(frontier_task_distances.begin() + maxID);
1780 if (tasks.size() < m_max_task_num)
1782 for (
int i = 0; i < object_tasks.size(); i++)
1787 if (tasks.size() > m_max_task_num)
1789 int d_num = tasks.size() - m_max_task_num;
1790 for (
int i = 0; i < d_num; i++)
1794 task_num = tasks.size();
1795 cerr << frt_num <<
" views for exploration, " << ldmk_num <<
" views for quality" << endl;
1796 cerr << task_num <<
" task views selected. " << endl;
1806 printf(
"scan finished.\n");
1817 if (points.size() <= 3)
1819 if (points.size() == 1)
1821 result.push_back(0);
1823 else if (points.size() == 2)
1825 result.push_back(0);
1826 result.push_back(1);
1830 result.push_back(0);
1831 if (weights[0][1] < weights[0][2])
1833 result.push_back(1);
1834 result.push_back(2);
1838 result.push_back(2);
1839 result.push_back(1);
1846 vector<Eigen::Vector2d> nodes;
1847 for (
int i = 0; i < points.size(); i++)
1848 nodes.push_back(Eigen::Vector2d(points[i].x(), points[i].y()));
1850 TSP tsp(nodes, weights);
1867 if (n >= 600 && n < 1040)
1869 else if (n >= 1040 && n < 1800)
1871 else if (n >= 1800 && n < 3205)
1873 else if (n >= 3205 && n < 4005)
1875 else if (n >= 4005 && n < 5005)
1877 else if (n >= 5005 && n < 6500)
1886 while (remaining >= increment)
1892 stop_here = remaining / increment;
1894 for (
long t = 0; t < stop_here; t++)
1898 threads[t].
my_id = count;
1899 threads[t].
mytsp = &tsp;
1905 for (
long t = 0; t < stop_here; t++)
1909 remaining -= (stop_here * increment);
1912 for (
long t = 0; t < count; t++) {
1928 bool posetive_sequence =
true;
1930 for (
int i = 0; i < tsp.
circuit.size(); i++)
1935 int ni = (i + 1) % tsp.
circuit.size();
1940 posetive_sequence =
true;
1942 posetive_sequence =
false;
1946 for (
int counter = 0; counter < tsp.
circuit.size(); counter++)
1948 if (posetive_sequence)
1950 int id = (start_id + counter) % tsp.
circuit.size();
1951 result.push_back(tsp.
circuit[
id]);
1955 int id = (start_id - counter + tsp.
circuit.size()) % tsp.
circuit.size();
1956 result.push_back(tsp.
circuit[
id]);
1968 vector<Polygon_2> holes;
1969 vector<Polygon_2> origin_holes;
1971 robotMoveDomainProcess(boundary, holes, origin_holes);
1975 vector<ScanningTask> temp;
1976 generateMoveDomainCDT(boundary, holes, origin_holes, temp, cdt);
1979 m_metric.get_geodesic_distance_fast_initialization();
1986 vector<ScanningTask> tasks;
1987 vector<Point_2> frontiers;
1990 frontiers = load_and_check_frontiers(boundary, holes);
1992 extractTasks(boundary, holes, tasks);
1994 if (tasks.size() == 0)
2001 generateMoveDomainCDT(boundary, holes, origin_holes, tasks, cdt);
2004 m_metric.get_geodesic_distance_fast_initialization();
2010 vector<vector<NextBestView>> assigned_tasks;
2015 generateMoveDomainCDT(boundary, holes, origin_holes, tasks, cdt);
2017 m_metric.get_geodesic_distance_fast_initialization();
2019 vector<Eigen::Vector2d> robots(m_robot_sites.size());
2020 for (
int rid = 0; rid < m_robot_sites.size(); rid++)
2022 robots[rid] = Eigen::Vector2d(m_robot_sites[rid].x(), m_robot_sites[rid].y());
2026 vector<Eigen::Vector2d> task_views(tasks.size());
2027 for (
int vid = 0; vid < tasks.size(); vid++)
2028 task_views[vid] = Eigen::Vector2d(
2029 tasks[vid].view.pose.translation().x(),
2030 tasks[vid].view.pose.translation().y()
2036 vector<vector<int>> assignment = d_solver.
getSolution();
2038 assigned_tasks.resize(assignment.size());
2039 for (
int rid = 0; rid < assignment.size(); rid++)
2041 assigned_tasks[rid].resize(assignment[rid].size());
2042 for (
int tid = 0; tid < assignment[rid].size(); tid++)
2044 int vid = assignment[rid][tid];
2045 assigned_tasks[rid][tid] =
NextBestView(tasks[vid].view);
2053 m_robot_move_views.clear();
2054 m_robot_move_views.resize(
rbt_num);
2055 for (
int rid = 0; rid <
rbt_num; rid++)
2056 m_robot_move_views[rid].clear();
2058 for (
int rid = 0; rid <
rbt_num; rid++)
2061 vector<Point_2> nodes;
2062 nodes.push_back(
Point_2(m_robot_sites[rid].x(), m_robot_sites[rid].y()));
2063 for (
int tid = 0; tid < assigned_tasks[rid].size(); tid++)
2064 nodes.push_back(
Point_2(assigned_tasks[rid][tid].pose.translation().x(), assigned_tasks[rid][tid].pose.translation().y()));
2066 vector<vector<double>> weights;
2067 weights.resize(nodes.size());
2068 for (
int i = 0; i < nodes.size(); i++)
2070 weights[i].resize(nodes.size());
2075 vector<vector<double>> wij(nodes.size());
2076 for (
int i = 0; i < wij.size(); i++)
2077 wij[i].resize(nodes.size());
2078 #pragma omp parallel for num_threads(8) 2080 for (
int i = 0; i < nodes.size() - 1; i++)
2082 vector<Point_2> targets;
2083 for (
int j = i + 1; j < nodes.size(); j++)
2084 targets.push_back(nodes[j]);
2085 vector<double> cDistances = m_metric.getGeodesicDistances(nodes[i], targets);
2086 for (
int tid = 0; tid < targets.size(); tid++)
2088 int j = tid + i + 1;
2089 wij[i][j] = cDistances[tid];
2090 wij[j][i] = cDistances[tid];
2095 for (
int i = 0; i < nodes.size() - 1; i++)
2097 for (
int j = i + 1; j < nodes.size(); j++)
2100 double distance_weight = wij[i][j];
2102 double angle_weight(0);
2108 theta1 = m_p_de->m_pose2d[rid].rotation().angle();
2112 theta1 = assigned_tasks[rid][i - 1].pose.rotation().angle();
2114 if (theta1 < 0) theta1 = 2 *
PI + theta1;
2116 double theta2 = assigned_tasks[rid][j - 1].pose.rotation().angle();
2117 if (theta2 < 0) theta2 = 2 *
PI + theta2;
2118 double delta = fabs(theta1 - theta2) < 2 *
PI - fabs(theta1 - theta2) ? fabs(theta1 - theta2) : 2 *
PI - fabs(theta1 - theta2);
2119 angle_weight = delta /
PI;
2122 if (__isnan(angle_weight))
2124 cerr <<
"angle_weight = " << angle_weight <<
" is nan" << endl;
2125 cerr <<
"theta1 = " << theta1 << endl;
2126 cerr <<
"theta2 = " << theta2 << endl;
2127 cerr <<
"delta = " << delta << endl;
2132 double final_weight =
max(distance_weight, angle_weight);
2133 weights[i][j] = weights[j][i] = final_weight;
2137 for (
int i = 0; i < wij.size(); i++)
2138 vector<double>().swap(wij[i]);
2140 vector<vector<double>>().
swap(wij);
2143 vector<int> point_path;
2144 if (nodes.size() == 1)
2146 point_path.push_back(0);
2150 point_path = TSP_path(nodes, weights);
2153 for (
int i = 0; i < point_path.size(); i++)
2155 if (point_path[i] == 0)
2158 m_robot_move_views[rid].push_back(m_p_de->m_pose2d[rid]);
2163 int tid = point_path[i] - 1;
2164 m_robot_move_views[rid].push_back(
iro::SE2(assigned_tasks[rid][tid].pose.translation().x(), assigned_tasks[rid][tid].pose.translation().y(), assigned_tasks[rid][tid].pose.rotation().angle()));
2168 for (
int i = 0; i < weights.size(); i++)
2169 vector<double>().swap(weights[i]);
2171 vector<vector<double>>().
swap(weights);
2173 if (m_robot_move_views[rid].size() != point_path.size())
2175 cerr <<
"size error: " << m_robot_move_views[rid].size() <<
", " << point_path.size() << endl;
2245 Eigen::Vector2d b(beg.x, beg.y);
2246 Eigen::Vector2d e(end.x, end.y);
2247 if ((b - e).norm() < 1)
2253 cv::threshold(background, bin_map, 0, 255, cv::THRESH_BINARY);
2261 if (bin_map.ptr<
uchar>(r)[c] == 0)
2262 background.ptr<
uchar>(r)[c] = 0;
2264 background.ptr<
uchar>(r)[c] = 255;
2270 bool occlusion =
false;
2271 int dx = end.x - beg.x;
2272 int dy = end.y - beg.y;
2274 int beg_y = beg.y < end.y ? beg.y : end.y;
2275 int end_y = beg.y > end.y ? beg.y : end.y;
2276 for (
int y = beg_y; y < end_y; y++)
2277 if (background.ptr<
uchar>(y)[beg.x] == 255)
2284 int beg_x = beg.x < end.x ? beg.x : end.x;
2285 int end_x = beg.x > end.x ? beg.x : end.x;
2286 for (
int x = beg_x; x < end_x; x++)
2287 if (background.ptr<
uchar>(beg.y)[x] == 255)
2293 else if (dx == 0 && dy == 0){}
2296 double fXUnitLen = 1.0;
2297 double fYUnitLen = 1.0;
2298 fYUnitLen = (double)(dy) / (double)(MaxStep);
2299 fXUnitLen = (double)(dx) / (double)(MaxStep);
2300 double x = (double)(beg.x);
2301 double y = (double)(beg.y);
2303 for (
long i = 1; i < MaxStep; i++)
2322 m_robot_move_nodes.clear();
2323 m_robot_move_nodes.resize(
rbt_num);
2324 m_robot_move_nodes_nbv_sign.clear();
2325 m_robot_move_nodes_nbv_sign.resize(
rbt_num);
2328 for (
int rid = 0; rid <
rbt_num; rid++)
2395 for (
int rid = 0; rid <
rbt_num; rid++)
2398 if (m_robot_move_views[rid].size() == 1)
2400 distances[rid] = 0.0;
2401 m_robot_move_nodes[rid].push_back(m_robot_move_views[rid][0]);
2402 m_robot_move_nodes_nbv_sign[rid].push_back(
false);
2406 for (
int vid = 0; vid < m_robot_move_views[rid].size() - 1; vid++)
2411 Eigen::Vector2d beg(m_robot_move_views[rid][vid].translation().x(), m_robot_move_views[rid][vid].translation().y());
2412 Eigen::Vector2d end(m_robot_move_views[rid][nid].translation().x(), m_robot_move_views[rid][nid].translation().y());
2413 if ((beg - end).norm() < 0.001)
2415 if (m_robot_move_nodes[rid].empty())
2417 m_robot_move_nodes[rid].push_back(
iro::SE2(m_robot_move_views[rid][vid].translation().x(), m_robot_move_views[rid][vid].translation().y(), m_robot_move_views[rid][vid].rotation().angle()));
2418 m_robot_move_nodes_nbv_sign[rid].push_back(
true);
2419 m_robot_move_nodes[rid].push_back(
iro::SE2(m_robot_move_views[rid][nid].translation().x(), m_robot_move_views[rid][nid].translation().y(), m_robot_move_views[rid][nid].rotation().angle()));
2420 m_robot_move_nodes_nbv_sign[rid].push_back(
true);
2424 if (!se2_equal(m_robot_move_nodes[rid].back(), m_robot_move_views[rid][vid]))
2426 m_robot_move_nodes[rid].push_back(
iro::SE2(m_robot_move_views[rid][vid].translation().x(), m_robot_move_views[rid][vid].translation().y(), m_robot_move_views[rid][vid].rotation().angle()));
2427 m_robot_move_nodes_nbv_sign[rid].push_back(
true);
2429 m_robot_move_nodes[rid].push_back(
iro::SE2(m_robot_move_views[rid][nid].translation().x(), m_robot_move_views[rid][nid].translation().y(), m_robot_move_views[rid][nid].rotation().angle()));
2430 m_robot_move_nodes_nbv_sign[rid].push_back(
true);
2437 cv::Point beg(
round(m_robot_move_views[rid][vid].translation().x()), -
round(m_robot_move_views[rid][vid].translation().y()));
2438 cv::Point end(
round(m_robot_move_views[rid][nid].translation().x()), -
round(m_robot_move_views[rid][nid].translation().y()));
2440 for (
int r = 0; r < background.rows; r++)
2442 for (
int c = 0; c < background.cols; c++)
2444 if (m_p_de->m_recon2D.m_cellmap[r][c].isScanned && m_p_de->m_recon2D.m_cellmap[r][c].isFree)
2445 background.ptr<
uchar>(r)[c] = 0;
2447 background.ptr<
uchar>(r)[c] = 255;
2450 vector<Point_2> path;
2451 Point_2 p1(m_robot_move_views[rid][vid].translation().x(), m_robot_move_views[rid][vid].translation().y());
2452 Point_2 p2(m_robot_move_views[rid][nid].translation().x(), m_robot_move_views[rid][nid].translation().y());
2453 if (path_occlusion_check(background, beg, end))
2455 distances[rid] += m_metric.get_geodesic_distance(p1, p2, path);
2460 distances[rid] += m_metric.get_euclidean_distance(p1, p2, path);
2463 for (
int tid = 0; tid < path.size(); tid++)
2465 if (m_robot_move_nodes[rid].empty())
2467 m_robot_move_nodes[rid].push_back(
iro::SE2(path[tid].x(), path[tid].y(), m_robot_move_views[rid][vid].rotation().angle()));
2468 m_robot_move_nodes_nbv_sign[rid].push_back(
false);
2472 if (!points_equal(
Point_2(m_robot_move_nodes[rid].back().translation().x(), m_robot_move_nodes[rid].back().translation().y()), path[tid]))
2476 m_robot_move_nodes[rid].push_back(
iro::SE2(path[tid].x(), path[tid].y(), m_robot_move_views[rid][vid].rotation().angle()));
2477 m_robot_move_nodes_nbv_sign[rid].push_back(
true);
2479 else if (tid == path.size() - 1)
2481 m_robot_move_nodes[rid].push_back(
iro::SE2(path[tid].x(), path[tid].y(), m_robot_move_views[rid][nid].rotation().angle()));
2482 m_robot_move_nodes_nbv_sign[rid].push_back(
true);
2488 m_robot_move_nodes_nbv_sign[rid].push_back(
false);
2495 if (!se2_equal(m_robot_move_nodes[rid].back(), m_robot_move_views[rid].back()))
2498 cerr <<
"error, end point not equal" << endl;
2500 m_robot_move_nodes[rid].push_back(m_robot_move_views[rid].back());
2501 m_robot_move_nodes_nbv_sign[rid].push_back(
true);
2510 Eigen::Vector2d pose1(p1.x(), p1.y());
2511 Eigen::Vector2d pose2(p2.x(), p2.y());
2512 if ((pose1 - pose2).norm() < 0.00001)
2522 if ((pose1 - pose2).norm() < 0.00001)
2531 if (m_robot_move_nodes[robot_id].size() == 1)
2533 vector<iro::SE2> samples;
2534 samples.push_back(m_robot_move_nodes[robot_id].front());
2538 vector<Eigen::Vector2d> curve;
2539 for (
int i = 0; i < m_robot_move_nodes[robot_id].size(); i++)
2540 curve.push_back(Eigen::Vector2d(m_robot_move_nodes[robot_id][i].translation().x(), m_robot_move_nodes[robot_id][i].translation().y()));
2542 vector<double> accLen;
2543 accLen.push_back(.0
f);
2544 for (
int i = 1; i < curve.size(); i++)
2546 auto l = (curve[i - 1] - curve[i]).norm();
2547 accLen.push_back(accLen.back() + l);
2548 if (accLen.back() > length)
2551 int numSamples = (int)
floor(accLen.back() / step) + 1;
2554 if (accLen.back() < 0.001)
2556 vector<iro::SE2> samples;
2557 for (
int i = 0; i < m_robot_move_nodes[robot_id].size(); i++)
2559 samples.push_back(m_robot_move_nodes[robot_id][i]);
2563 numSamples = m_robot_move_nodes[robot_id].size();
2567 vector<iro::SE2> samples;
2568 samples.push_back(m_robot_move_nodes[robot_id].front());
2570 int left = 0, right = 1;
2571 for (
int i = 1; i < numSamples; i++)
2577 while (t >= accLen[right])
2581 if (m_robot_move_nodes_nbv_sign[robot_id][right])
2583 samples.push_back(m_robot_move_nodes[robot_id][right]);
2590 auto a = t - accLen[left];
2591 auto b = accLen[right] - t;
2592 auto s = (a * curve[right] + b * curve[left]) / (a + b);
2599 for (
int i = 0; i < samples.size(); i++)
2601 if ((
int)
round(samples[i].translation().x()) < 10 && -(int)
round(samples[i].translation().y()) < 10)
2604 cerr <<
"error uniform sampled a invalid se2" << endl;
2609 for (
int i = 0; i < m_robot_move_nodes[robot_id].size(); i++)
2611 samples.push_back(m_robot_move_nodes[robot_id][i]);
2618 if (samples.size() == 1 && m_robot_move_nodes[robot_id].size() > 1)
2621 for (
int i = 0; i < m_robot_move_nodes[robot_id].size(); i++)
2623 samples.push_back(m_robot_move_nodes[robot_id][i]);
2634 m_sync_move_paths.clear();
2635 m_sync_move_paths.resize(
rbt_num);
2638 double min_distance = DBL_MAX;
2639 for (
int rid = 0; rid <
rbt_num; rid++)
2641 if (distances[rid] != 0 && min_distance > distances[rid])
2642 min_distance = distances[rid];
2644 for (
int rid = 0; rid <
rbt_num; rid++)
2646 m_sync_move_paths[rid] = uniformSampleWithNBVInfo(rid, distance_step, min_distance);
2650 int start_id = -1, end_id = -1;
2651 for (
int nid = 0; nid < m_sync_move_paths[rid].size(); nid++)
2653 if (fabs(m_sync_move_paths[rid][nid].rotation().angle() -
empty_angle) > 0.01)
2662 if (end_id - start_id > 1)
2666 for (
int tid = start_id; tid <= end_id; tid++)
2667 segment.push_back(m_sync_move_paths[rid][tid]);
2670 cerr <<
"Optimize_Path success " << rtn << endl;
2672 for (
int sid = 0, tid = start_id + 1; tid < end_id; sid++, tid++)
2674 m_sync_move_paths[rid][tid].translation().x() = segment[sid].translation().x();
2675 m_sync_move_paths[rid][tid].translation().y() = segment[sid].translation().y();
2689 vector<iro::SE2> temp_path;
2691 for (
int nid = 0; nid < m_sync_move_paths[rid].size() - 1; nid++)
2694 if (fabs(m_sync_move_paths[rid][nid].rotation().angle() -
empty_angle) < 0.01)
2697 Eigen::Vector2d beg(m_sync_move_paths[rid][nid].translation().x(), m_sync_move_paths[rid][nid].translation().y());
2698 Eigen::Vector2d end(m_sync_move_paths[rid][nid + 1].translation().x(), m_sync_move_paths[rid][nid + 1].translation().y());
2699 Eigen::Vector2d move_vector(end - beg);
2701 Eigen::Vector2d base(0, 1);
2702 Eigen::Vector2d dire(m_sync_move_paths[rid][nid + 1].translation().x() - m_sync_move_paths[rid][nid].translation().x(), m_sync_move_paths[rid][nid + 1].translation().y() - m_sync_move_paths[rid][nid].translation().y());
2704 double d_angle =
acos(base.dot(dire) / (dire.norm() * base.norm()));
2712 double lst_ang = m_sync_move_paths[rid][nid - 1].rotation().angle();
2716 lst_ang = temp_path.back().rotation().angle();
2724 double crt_ang = d_angle;
2731 if (crt_ang - lst_ang < 0)
2735 double l_angle = d_angle + delta_angle;
2738 Eigen::Vector2d p(beg);
2739 temp_path.push_back(
iro::SE2(p.x(), p.y(), l_angle));
2743 Eigen::Vector2d p(beg + 0.33*move_vector);
2744 temp_path.push_back(
iro::SE2(p.x(), p.y(), d_angle));
2748 double r_angle = d_angle - delta_angle;
2751 Eigen::Vector2d p(beg + 0.67*move_vector);
2752 temp_path.push_back(
iro::SE2(p.x(), p.y(), r_angle));
2759 double r_angle = d_angle - delta_angle;
2762 Eigen::Vector2d p(beg);
2763 temp_path.push_back(
iro::SE2(p.x(), p.y(), r_angle));
2767 Eigen::Vector2d p(beg + 0.33*move_vector);
2768 temp_path.push_back(
iro::SE2(p.x(), p.y(), d_angle));
2772 double l_angle = d_angle + delta_angle;
2775 Eigen::Vector2d p(beg + 0.67*move_vector);
2776 temp_path.push_back(
iro::SE2(p.x(), p.y(), l_angle));
2784 double l_angle = d_angle + delta_angle;
2787 Eigen::Vector2d p(beg);
2788 temp_path.push_back(
iro::SE2(p.x(), p.y(), l_angle));
2792 Eigen::Vector2d p(beg + 0.33*move_vector);
2793 temp_path.push_back(
iro::SE2(p.x(), p.y(), d_angle));
2797 double r_angle = d_angle - delta_angle;
2800 Eigen::Vector2d p(beg + 0.67*move_vector);
2801 temp_path.push_back(
iro::SE2(p.x(), p.y(), r_angle));
2812 temp_path.push_back(m_sync_move_paths[rid][nid]);
2817 if (fabs(m_sync_move_paths[rid].back().rotation().angle() -
empty_angle) < 0.01)
2818 m_sync_move_paths[rid].back().rotation().angle() = m_robot_move_views[rid].back().rotation().angle();
2819 temp_path.push_back(m_sync_move_paths[rid].back());
2821 m_sync_move_paths[rid].clear();
2822 for (
int nid = 0; nid < temp_path.size(); nid++)
2823 m_sync_move_paths[rid].push_back(temp_path[nid]);
2833 vector<iro::SE2> result;
2834 for (
int i = 0; i < path.size() - 1; i++)
2837 double nTheta = path[ii].rotation().angle();
2838 if (nTheta < 0) nTheta += 2 *
PI;
2839 double cTheta = path[i].rotation().angle();
2840 if (cTheta < 0) cTheta += 2 *
PI;
2841 double difference = nTheta - cTheta;
2842 if (difference >
PI) difference = difference - 2 *
PI;
2843 if (difference < -PI) difference = difference + 2 *
PI;
2845 result.push_back(path[i]);
2847 if (fabs(difference) > dAngle)
2849 int num =
ceil(fabs(difference) / dAngle) + 1;
2850 Eigen::Vector2d crt(path[i].translation());
2851 Eigen::Vector2d nxt(path[ii].translation());
2852 Eigen::Vector2d dlt = (nxt - crt) / num;
2853 cerr <<
"two end point" << endl << path[i].translation().transpose() <<
" " << path[i].rotation().angle() << endl << path[ii].translation().transpose() <<
" " << path[ii].rotation().angle() << endl;
2855 for (
int id = 1;
id < num;
id++)
2858 Eigen::Vector2d itp_position = crt + dlt*id;
2860 double itp_theta = path[i].rotation().angle() + difference / num * id;
2861 if (itp_theta > PI) itp_theta = itp_theta - 2 *
PI;
2862 if (itp_theta < -PI) itp_theta = itp_theta + 2 *
PI;
2863 result.push_back(
iro::SE2(itp_position.x(), itp_position.y(), itp_theta));
2864 cerr <<
"interpolate " << itp_position.transpose() <<
" " << itp_theta << endl;
2869 result.push_back(path.back());
2872 for (
int i = 0; i < result.size(); i++)
2873 path.push_back(result[i]);
2897 vector<double> distances;
2899 cerr <<
"compute geodesic nodes...";
2900 compute_robot_move_nodes(distances);
2901 cerr <<
"done." << endl;
2925 cerr <<
"path optimization...";
2926 compute_sync_move_paths(distances);
2927 cerr <<
"done." << endl;
2954 for (
int rid = 0; rid < m_sync_move_paths.size(); rid++)
2956 m_sync_move_paths[rid][0] = m_p_de->m_pose2d[rid];
2959 for (
int rid = 0; rid < m_sync_move_paths.size(); rid++)
2961 trajectoryInterpolation(m_sync_move_paths[rid]);
2967 for (
int rid = 0; rid < m_sync_move_paths.size(); rid++)
2969 if (m_sync_move_paths[rid].size() > 1)
2971 Eigen::Vector2d xy(m_sync_move_paths[rid][0].translation().x(), m_sync_move_paths[rid][0].translation().y());
2972 Eigen::Vector2d nxy(m_sync_move_paths[rid][1].translation().x(), m_sync_move_paths[rid][1].translation().y());
2974 Eigen::Vector2d direction(nxy - xy);
2976 if (direction.norm() < 0.1)
continue;
2978 direction.normalize();
2980 Eigen::Vector2d base(0, 1);
2981 double theta =
acos(direction.dot(base));
2983 if (direction.x() > 0)
2985 double angle = theta;
2987 m_sync_move_paths[rid][0].rotation().angle() = angle;
2993 cv::Mat statement = m_p_de->visCellMap();
2995 for (
int rid = 0; rid <
rbt_num; ++rid)
2997 for (
int vid = 0; vid < m_sync_move_paths[rid].size(); ++vid)
3002 cv::Point((
int)m_sync_move_paths[rid][vid].translation().x(), -(
int)m_sync_move_paths[rid][vid].translation().y()),
3003 cv::Point((
int)m_sync_move_paths[rid][vid-1].translation().x(), -(
int)m_sync_move_paths[rid][vid-1].translation().y()),
3004 CV_RGB(255, 0, 255));
3006 cv::circle(statement, cv::Point((
int)m_sync_move_paths[rid][vid].translation().x(), -(
int)m_sync_move_paths[rid][vid].translation().y()), 2, CV_RGB(0, 0, 255));
3013 cv::Mat temp = statement.clone();
3014 for (
int fid = 0; fid < m_frontierList.size(); fid++)
3016 int x = m_frontierList[fid].position.x();
3017 int y = -m_frontierList[fid].position.y();
3020 cv::circle(temp, cv::Point(x, y), 2, CV_RGB(255, 255, 255));
3023 char output_path[200];
3025 cv::imwrite(output_path, temp);
3029 char output_path[200];
3031 cv::imwrite(output_path, statement);
3033 cv::imshow(
"plan sync move paths", statement);
3051 int min_size = INT_MAX;
3052 bool exist_robot_no_task =
false;
3053 vector<bool> robot_no_task_signs(
rbt_num);
3054 for (
int rid = 0; rid <
rbt_num; rid++)
3055 robot_no_task_signs.push_back(
false);
3057 for (
int rid = 0; rid <
rbt_num; rid++)
3059 if (m_sync_move_paths[rid].size() == 1)
3061 exist_robot_no_task =
true;
3062 robot_no_task_signs[rid] =
true;
3065 if (min_size > m_sync_move_paths[rid].size())
3066 min_size = m_sync_move_paths[rid].size();
3068 if (min_size == INT_MAX)
3074 if (exist_robot_no_task)
3077 for (
int vid = 0; vid < min_size; vid++)
3107 vector<vector<double>> pose7s;
3108 for (
int rid = 0; rid <
rbt_num; rid++)
3111 vector<double> pose7;
3112 if (robot_no_task_signs[rid])
3113 pose7 = m_p_de->coord_trans_se22gazebo(m_sync_move_paths[rid][0]);
3115 pose7 = m_p_de->coord_trans_se22gazebo(m_sync_move_paths[rid][vid]);
3116 pose7s.push_back(pose7);
3117 if (robot_no_task_signs[rid])
3128 cerr<<
"socket move to views..."<<endl;
3129 m_p_de->socket_move_to_views(pose7s);
3130 cerr<<
"done."<<endl;
3132 for (
int rid = 0; rid <
rbt_num; rid++)
3134 if (robot_no_task_signs[rid])
3138 g_rbtTrajectories[rid].push_back(
Point_2(m_sync_move_paths[rid][0].translation().x(), m_sync_move_paths[rid][0].translation().y()));
3145 g_rbtTrajectories[rid].push_back(
Point_2(m_sync_move_paths[rid][vid].translation().x(), m_sync_move_paths[rid][vid].translation().y()));
3151 m_p_de->getPoseFromServer();
3152 m_p_de->getRGBDFromServer();
3156 m_p_de->fuseScans2MapAndTree();
3160 m_p_de->projectOctree2Map();
3163 vector<iro::SE2> current_views;
3164 for (
int rid = 0; rid <
rbt_num; rid++)
3166 if (m_sync_move_paths[rid].size() <= vid)
3167 current_views.push_back(m_sync_move_paths[rid].back());
3169 current_views.push_back(m_sync_move_paths[rid][vid]);
3173 visualizeScan(current_views, vid);
3184 for (
int vid = 0; vid < min_size; vid++)
3214 vector<vector<double>> pose7s;
3215 for (
int rid = 0; rid <
rbt_num; rid++)
3217 vector<double> pose7 = m_p_de->coord_trans_se22gazebo(m_sync_move_paths[rid][vid]);
3218 pose7s.push_back(pose7);
3228 cerr<<
"socket move to views..."<<endl;
3229 m_p_de->socket_move_to_views(pose7s);
3230 cerr<<
"done."<<endl;
3232 for (
int rid = 0; rid <
rbt_num; rid++)
3234 g_rbtTrajectories[rid].push_back(
Point_2(m_sync_move_paths[rid][vid].translation().x(), m_sync_move_paths[rid][vid].translation().y()));
3238 m_p_de->getPoseFromServer();
3239 m_p_de->getRGBDFromServer();
3243 m_p_de->fuseScans2MapAndTree();
3247 m_p_de->projectOctree2Map();
3250 vector<iro::SE2> current_views;
3251 for (
int rid = 0; rid <
rbt_num; rid++)
3253 if (m_sync_move_paths[rid].size() <= vid)
3254 current_views.push_back(m_sync_move_paths[rid].back());
3256 current_views.push_back(m_sync_move_paths[rid][vid]);
3260 visualizeScan(current_views, vid);
3275 const double frustumSize = 20;
3277 for (
int vid = 0; vid < views.size(); vid++)
3280 cv::Point p((
int)
round(views[vid].translation().x()), -(
int)
round(views[vid].translation().y()));
3281 cv::circle(input, p, 0, CV_RGB(0, 0, 255), 2, CV_AA);
3282 cv::circle(input, p, 1, CV_RGB(0, 0, 255), 2, CV_AA);
3283 cv::circle(input, p, 2, CV_RGB(0, 0, 255), 2, CV_AA);
3284 cv::circle(input, p, 3, CV_RGB(0, 0, 255), 2, CV_AA);
3285 cv::circle(input, p, 4, CV_RGB(0, 0, 255), 2, CV_AA);
3286 cv::circle(input, p, 5, CV_RGB(0, 0, 255), 2, CV_AA);
3288 Eigen::Vector2d
d(0, frustumSize);
3290 double theta = views[vid].rotation().angle();
3291 m <<
cos(theta), -
sin(theta),
3298 cv::Point l((
int)
round(views[vid].translation().x() + d.x()), -(
int)
round(views[vid].translation().y() + d.y()));
3299 cv::line(input, p, l, CV_RGB(0, 0, 255), 1, CV_AA);
3304 cv::Point r((
int)
round(views[vid].translation().x() + d.x()), -(
int)
round(views[vid].translation().y() + d.y()));
3305 cv::line(input, p, r, CV_RGB(0, 0, 255), 1, CV_AA);
3307 cv::line(input, l, r, CV_RGB(0, 0, 255), 1, CV_AA);
3316 cv::Mat statement = m_p_de->visCellMap();
3318 for (
int i = 0; i < current_views.size(); ++i)
3320 cv::circle(statement, cv::Point((
int)
round(current_views[i].translation().x()), (
int)
round(-current_views[i].translation().y())), 3, CV_RGB(0, 0, 255));
3325 char output_path[200];
3326 sprintf(output_path,
"result/_progressive_%d_%d.png",
g_plan_iteration, vid);
3327 cv::imwrite(output_path, statement);
bool checkViewRayValidness(cv::Point source, cv::Point target)
EIGEN_DEVICE_FUNC const CosReturnType cos() const
bool compute_sync_move_paths(std::vector< double > distances)
std::vector< iro::SE2 > uniformSampleWithNBVInfo(const int robot_id, const double step, const double length)
const int random_site_num
bool Optimize_Path(DataEngine *p_de, vector< iro::SE2 > &path)
bool extractTasks(Polygon_2 boundary, std::vector< Polygon_2 > holes, std::vector< ScanningTask > &tasks)
std::vector< cv::Point > g_scene_boundary
std::vector< std::vector< iro::SE2 > > g_camTrajectories
vector< cv::Point > get_frustum_contuor(iro::SE2 pose)
cv::Mat computeLoationMap()
EIGEN_DEVICE_FUNC const SqrtReturnType sqrt() const
bool simplifyPolygon(Polygon_2 &poly, const double colinearThresh, bool addNoise)
void mark_domains(CDT &ct, CDT::Face_handle start, int index, std::list< CDT::Edge > &border)
bool points_equal(Point_2 p1, Point_2 p2)
Pwh_list_2 differenceCGALExactKernel(Polygon_with_holes_2 domain, Polygon_2 hole)
const Eigen::Rotation2Dd & rotation() const
std::vector< std::vector< int > > getSolution()
const std::string cdt_obj_path
void Trajectory_Optimization()
void processCurrentScene()
CGAL::Polygon_with_holes_2< K > Polygon_with_holes_2
bool visualizeScan(std::vector< iro::SE2 > current_views, int vid)
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const AbsReturnType abs() const
EIGEN_DEVICE_FUNC const FloorReturnType floor() const
std::vector< std::vector< Point_2 > > g_rbtTrajectories
std::vector< Polygon_2 > load_and_check_holes(Polygon_2 boundary, std::vector< Polygon_2 > &origin_holes)
std::vector< int > preprocess_frontiers(Polygon_2 outer, std::vector< Polygon_2 > iner)
std::vector< NextBestView > extractQualityTaskViews(Polygon_2 boundary, std::vector< Polygon_2 > holes)
bool generateMoveDomainCDT(Polygon_2 boundary, std::vector< Polygon_2 > holes, std::vector< Polygon_2 > origin_holes, std::vector< ScanningTask > tasks, CDT &cdt)
std::vector< NextBestView > generateViewsFrontiers(bool enableSampling=false, double sampleRate=0.5)
void correct_boundary_holes(Polygon_2 &boundary, std::vector< Polygon_2 > &holes)
const std::string domainFilePath
EIGEN_DEVICE_FUNC SegmentReturnType segment(Index start, Index n)
This is the const version of segment(Index,Index).
void saveCDT_geodesic(CDT cdt)
bool path_occlusion_check(cv::Mat background, cv::Point beg, cv::Point end)
const std::string poly_diff
void trajectoryInterpolation(std::vector< iro::SE2 > &path, double dAngle=PI/12)
EIGEN_DEVICE_FUNC const AcosReturnType acos() const
const std::string communicateFile
const std::string holeFilePath
bool se2_equal(iro::SE2 p1, iro::SE2 p2)
std::list< Polygon_with_holes_2 > Pwh_list_2
int64_t max(int64_t a, const int b)
const int frontier_exploration_sample_range_pixel
CGAL::Constrained_Delaunay_triangulation_2< K, TDS, Itag > CDT
CGAL::Polygon_2< K > Polygon_2
bool robotMoveDomainProcess(Polygon_2 &boundary, std::vector< Polygon_2 > &holes, std::vector< Polygon_2 > &origin_holes)
const std::string resultFilePath
Polygon_2 load_and_check_boundary()
bool SolveOMT(int mode=0)
EIGEN_DEVICE_FUNC Scalar angle() const
std::vector< int > TSP_path(std::vector< Point_2 > points, std::vector< vector< double >> weights)
bool draw_robot_views(cv::Mat &input, vector< iro::SE2 > views)
EIGEN_DEVICE_FUNC const CeilReturnType ceil() const
bool compute_robot_move_nodes(std::vector< double > &distances)
void swap(scoped_array< T > &a, scoped_array< T > &b)
const Eigen::Vector2d & translation() const
std::vector< Point_2 > load_and_check_frontiers(Polygon_2 &boundary, std::vector< Polygon_2 > &holes)
EIGEN_DEVICE_FUNC const SinReturnType sin() const
std::vector< NextBestView > compute_frontier_tasks(Polygon_2 boundary, std::vector< Polygon_2 > holes)
EIGEN_DEVICE_FUNC const RoundReturnType round() const