39 #include <nav_msgs/OccupancyGrid.h> 41 #include <gtest/gtest.h> 44 "<value><array><data>" 45 " <value><array><data>" 46 " <value><double>1.5</double></value>" 47 " <value><double>0.0</double></value>" 48 " </data></array></value>" 49 " <value><array><data>" 50 " <value><double>-0.5</double></value>" 51 " <value><double>-0.5</double></value>" 52 " </data></array></value>" 53 " <value><array><data>" 54 " <value><double>-0.5</double></value>" 55 " <value><double>0.5</double></value>" 56 " </data></array></value>" 57 "</data></array></value>");
71 TEST(Costmap3dLayerFootprint, CSpaceTemplate)
81 int footprint_offset = 0;
88 ASSERT_EQ(3u + 1u, polygon.
v.size());
89 ASSERT_EQ(1.5, polygon.
v[0][0]);
90 ASSERT_EQ(0.0, polygon.
v[0][1]);
91 ASSERT_EQ(-0.5, polygon.
v[1][0]);
92 ASSERT_EQ(-0.5, polygon.
v[1][1]);
93 ASSERT_EQ(-0.5, polygon.
v[2][0]);
94 ASSERT_EQ(0.5, polygon.
v[2][1]);
96 ASSERT_EQ(1.5, polygon.
v[3][0]);
97 ASSERT_EQ(0.0, polygon.
v[3][1]);
101 costmap_cspace_msgs::MapMetaData3D map_info;
105 map_info.linear_resolution = 1.0;
106 map_info.angular_resolution = M_PI / 2.0;
107 map_info.origin.orientation.w = 1.0;
111 ASSERT_EQ(static_cast<int>(std::ceil(1.5 / 1.0)), cm.
getRangeMax());
117 temp.getSize(x, y, a);
118 temp.getCenter(cx, cy, ca);
119 ASSERT_EQ(2 * 2 + 1, x);
120 ASSERT_EQ(2 * 2 + 1, y);
127 for (
int k = -ca; k < a - ca; ++k)
129 for (
int j = -cy; j < y - cy; ++j)
131 for (
int i = -cx; i < x - cx; ++i)
133 if (i == 0 && j == 0)
135 ASSERT_EQ(100, temp.e(i, j, k));
139 ASSERT_EQ(100, temp.e(i, j, k));
143 ASSERT_EQ(0, temp.e(i, j, k));
150 TEST(Costmap3dLayerPlain, CSpaceTemplate)
160 costmap_cspace_msgs::MapMetaData3D map_info;
164 map_info.linear_resolution = 1.0;
165 map_info.angular_resolution = M_PI / 2.0;
166 map_info.origin.orientation.w = 1.0;
176 temp.getSize(x, y, a);
177 temp.getCenter(cx, cy, ca);
186 for (
int k = -ca; k < a - ca; ++k)
188 ASSERT_EQ(100, temp.e(0, 0, k));
192 TEST(Costmap3dLayerFootprint, CSpaceGenerate)
197 int footprint_offset = 0;
208 nav_msgs::OccupancyGrid::Ptr map(
new nav_msgs::OccupancyGrid);
210 map->info.height = 7;
211 map->info.resolution = 1.0;
212 map->info.origin.orientation.w = 1.0;
213 map->data.resize(map->info.width * map->info.height);
220 for (
size_t j = 0; j < map->info.height; ++j)
222 for (
size_t i = 0; i < map->info.width; ++i)
231 for (
auto& g : map->data)
238 for (
size_t j = 0; j < map->info.height; ++j)
240 for (
size_t i = 0; i < map->info.width; ++i)
244 ASSERT_EQ(100, cost);
250 for (
auto& g : map->data)
254 for (
size_t i = map->info.width / 2 - 2; i < map->info.width / 2 + 2; ++i)
256 map->data[i + (map->info.height / 2 - 2) * map->info.width] = 100;
257 map->data[i + (map->info.height / 2 + 2) * map->info.width] = 100;
259 for (
size_t i = map->info.height / 2 - 2; i < map->info.height / 2 + 2; ++i)
261 map->data[(map->info.width / 2 - 2) + i * map->info.width] = 100;
266 for (
size_t j = 0; j < map->info.height; ++j)
268 for (
size_t i = 0; i < map->info.width; ++i)
274 const int i_offset =
static_cast<int>(i) -
temp_dir[k][0];
275 const int j_offset =
static_cast<int>(j) -
temp_dir[k][1];
276 if (static_cast<size_t>(i_offset) < map->info.width &&
277 static_cast<size_t>(j_offset) < map->info.height)
279 cost_offset = map->data[i_offset + j_offset * map->info.width];
281 if (map->data[i + j * map->info.width] == 100 || cost_offset == 100)
283 ASSERT_EQ(100, cost);
294 TEST(Costmap3dLayerFootprint, CSpaceExpandSpread)
299 int footprint_offset = 0;
305 const float expand = 1.0;
306 const float spread = 2.0;
312 nav_msgs::OccupancyGrid::Ptr map(
new nav_msgs::OccupancyGrid);
314 map->info.height = 9;
315 map->info.resolution = 1.0;
316 map->info.origin.orientation.w = 1.0;
317 map->data.resize(map->info.width * map->info.height);
319 const int max_cost = 80;
320 map->data[map->info.width / 2 + (map->info.height / 2) * map->info.width] = max_cost;
321 map->data[map->info.width / 2 + 1 + (map->info.height / 2) * map->info.width] = -1;
326 const int i_center = map->info.width / 2;
327 const int j_center = map->info.height / 2;
328 const int i_center2 = map->info.width / 2 +
temp_dir[k][0];
329 const int j_center2 = map->info.height / 2 +
temp_dir[k][1];
331 for (
size_t j = 0; j < map->info.height; ++j)
333 for (
size_t i = 0; i < map->info.width; ++i)
336 const float dist1 = std::hypot(static_cast<int>(i) - i_center, static_cast<int>(j) - j_center);
337 const float dist2 = std::hypot(static_cast<int>(i) - i_center2, static_cast<int>(j) - j_center2);
338 const float dist = std::min(dist1, dist2);
340 if (i == static_cast<size_t>(i_center + 1) &&
341 j == static_cast<size_t>(j_center))
346 else if (dist <= expand)
349 EXPECT_EQ(max_cost, cost);
351 else if (dist <= expand + spread)
355 EXPECT_NE(100, cost);
357 else if (dist > expand + spread + 1)
369 TEST(Costmap3dLayerFootprint, CSpaceOverwrite)
375 int footprint_offset = 0;
386 cm->setFootprint(footprint);
390 cm_over->setFootprint(footprint);
401 nav_msgs::OccupancyGrid::Ptr map(
new nav_msgs::OccupancyGrid);
403 map->info.height = 9;
404 map->info.resolution = 1.0;
405 map->info.origin.orientation.w = 1.0;
406 map->data.resize(map->info.width * map->info.height);
408 nav_msgs::OccupancyGrid::Ptr map2(
new nav_msgs::OccupancyGrid);
411 const int num_points_base_map = 2;
412 const int points_base_map[num_points_base_map][2] =
417 for (
int i = 0; i < num_points_base_map; ++i)
419 map->data[points_base_map[i][0] + points_base_map[i][1] * map->info.width] = 100;
422 const int num_points_local_map = 3;
423 const int points_local_map[num_points_local_map][2] =
429 for (
int i = 0; i < num_points_local_map; ++i)
431 map2->data[points_local_map[i][0] + points_local_map[i][1] * map->info.width] = 100;
438 costmap_cspace_msgs::CSpace3DUpdate::Ptr updated(
new costmap_cspace_msgs::CSpace3DUpdate);
439 auto cb = [&updated](
441 const costmap_cspace_msgs::CSpace3DUpdate::Ptr&
update) ->
bool 446 cm_output->setHandler(cb);
447 cm_over->processMapOverlay(map2);
450 ASSERT_EQ(0u, updated->x);
451 ASSERT_EQ(0u, updated->y);
452 ASSERT_EQ(0u, updated->yaw);
453 ASSERT_EQ(map->info.width, updated->width);
454 ASSERT_EQ(map->info.height, updated->height);
455 ASSERT_EQ(static_cast<size_t>(cm_over->getAngularGrid()), updated->angle);
463 for (
int k = 0; k < cm_over->getAngularGrid(); ++k)
465 for (
size_t j = cm_over->getRangeMax(); j < map->info.height - cm_over->getRangeMax(); ++j)
467 for (
size_t i = cm_over->getRangeMax(); i < map->info.width - cm_over->getRangeMax(); ++i)
469 const size_t addr = ((k * map->info.height + j) * map->info.width) + i;
471 const int cost = updated->data[addr];
472 const int cost_ref = cm_ref.
getMapOverlay()->getCost(i, j, k);
474 ASSERT_EQ(cost_ref, cost);
479 cm_over->setAngleResolution(4);
480 cm_over->setExpansion(0.0, 0.0);
482 costmap_cspace_msgs::CSpace3DUpdate::Ptr updated_max(
new costmap_cspace_msgs::CSpace3DUpdate);
483 auto cb_max = [&updated_max](
485 const costmap_cspace_msgs::CSpace3DUpdate::Ptr&
update) ->
bool 490 cm_output->setHandler(cb_max);
491 cm_over->processMapOverlay(map2);
493 ASSERT_EQ(0u, updated_max->x);
494 ASSERT_EQ(0u, updated_max->y);
495 ASSERT_EQ(0u, updated_max->yaw);
496 ASSERT_EQ(map->info.width, updated_max->width);
497 ASSERT_EQ(map->info.height, updated_max->height);
498 ASSERT_EQ(static_cast<size_t>(cm_over->getAngularGrid()), updated_max->angle);
500 for (
int k = 0; k < cm_over->getAngularGrid(); ++k)
502 for (
int j = cm_over->getRangeMax(); j < static_cast<int>(map->info.height) - cm_over->getRangeMax(); ++j)
504 for (
int i = cm_over->getRangeMax(); i < static_cast<int>(map->info.width) - cm_over->getRangeMax(); ++i)
506 const size_t addr = ((k * map->info.height + j) * map->info.width) + i;
508 const int cost = updated_max->data[addr];
509 const int cost_ref = cm_ref.
getMapOverlay()->getCost(i, j, k);
510 const int cost_base = cm_base.
getMapOverlay()->getCost(i, j, k);
511 const int cost_max = std::max(cost_ref, cost_base);
513 ASSERT_EQ(cost_max, cost);
519 TEST(Costmap3dLayerFootprint, CSpaceOverlayMove)
522 int footprint_offset = 0;
531 cm->setFootprint(footprint);
535 cm_over->setFootprint(footprint);
538 nav_msgs::OccupancyGrid::Ptr map(
new nav_msgs::OccupancyGrid);
540 map->info.height = 5;
541 map->info.resolution = 1.0;
542 map->info.origin.orientation.w = 1.0;
543 map->data.resize(map->info.width * map->info.height);
545 const int max_cost = 100;
546 map->data[map->info.width / 2 + (map->info.height / 2) * map->info.width] = max_cost;
550 nav_msgs::OccupancyGrid::Ptr map2(
new nav_msgs::OccupancyGrid);
553 for (
int xp = -1; xp <= 1; ++xp)
555 for (
int yp = -1; yp <= 1; ++yp)
557 map2->info.origin.position.x = map2->info.resolution * xp;
558 map2->info.origin.position.y = map2->info.resolution * yp;
559 cm_over->processMapOverlay(map2);
560 for (
int k = 0; k < cm_over->getAngularGrid(); ++k)
562 const size_t i_center = map->info.width / 2;
563 const size_t j_center = map->info.height / 2;
564 const size_t i_center2 = map->info.width / 2 +
temp_dir[k][0];
565 const size_t j_center2 = map->info.height / 2 +
temp_dir[k][1];
567 for (
size_t j = 0; j < map->info.height; ++j)
569 for (
size_t i = 0; i < map->info.width; ++i)
571 const int cost = cm_over->getMapOverlay()->getCost(i, j, k);
573 if ((i == i_center && j == j_center) ||
574 (i == i_center2 && j == j_center2) ||
575 (i == i_center + xp && j == j_center + yp) ||
576 (i == i_center2 + xp && j == j_center2 + yp))
578 ASSERT_EQ(max_cost, cost);
591 TEST(Costmap3dLayerOutput, CSpaceOutOfBoundary)
614 const TestData dataset[] =
616 {
"inside0", { 0.0, 0.0 },
true, { 0u, 0u, 0u, 2u, 2u, 4u } },
617 {
"inside1", { 1.0, 0.0 },
true, { 1u, 0u, 0u, 2u, 2u, 4u } },
618 {
"half-outside x0", { -1.0, 0.0 },
true, { 0u, 0u, 0u, 1u, 2u, 4u } },
619 {
"half-outside x1", { 3.0, 0.0 },
true, { 3u, 0u, 0u, 1u, 2u, 4u } },
620 {
"half-outside y0", { 0.0, -1.0 },
true, { 0u, 0u, 0u, 2u, 1u, 4u } },
621 {
"half-outside y1", { 0.0, 3.0 },
true, { 0u, 3u, 0u, 2u, 1u, 4u } },
622 {
"half-outside xy0", { -1.0, -1.0 },
true, { 0u, 0u, 0u, 1u, 1u, 4u } },
623 {
"half-outside xy1", { 3.0, -1.0 },
true, { 3u, 0u, 0u, 1u, 1u, 4u } },
624 {
"half-outside xy2", { 3.0, 3.0 },
true, { 3u, 3u, 0u, 1u, 1u, 4u } },
625 {
"half-outside xy3", { -1.0, 3.0 },
true, { 0u, 3u, 0u, 1u, 1u, 4u } },
626 {
"boundary x0", { -2.0, 0.0 },
false },
627 {
"boundary x1", { 4, 0.0 },
false },
628 {
"boundary y0", { 0, -2.0 },
false },
629 {
"boundary y1", { 0, 4.0 },
false },
630 {
"boundary xy0", { -2.0, -2.0 },
false },
631 {
"boundary xy1", { 4.0, -2.0 },
false },
632 {
"boundary xy2", { 4.0, 4.0 },
false },
633 {
"boundary xy3", { -2.0, 4.0 },
false },
634 {
"outside x0", { -3.0, 0.0 },
false },
635 {
"outside x1", { 5, 0.0 },
false },
636 {
"outside y0", { 0, -3.0 },
false },
637 {
"outside y1", { 0, 5.0 },
false },
638 {
"outside xy0", { -3.0, -3.0 },
false },
639 {
"outside xy1", { 5.0, -3.0 },
false },
640 {
"outside xy2", { 5.0, 5.0 },
false },
641 {
"outside xy3", { -3.0, 5.0 },
false },
644 for (
auto&
d : dataset)
646 const std::string test_name =
"Case [" +
d.name +
"]";
656 nav_msgs::OccupancyGrid::Ptr map(
new nav_msgs::OccupancyGrid);
658 map->info.height = 4;
659 map->info.resolution = 1.0;
660 map->info.origin.orientation.w = 1.0;
661 map->data.resize(map->info.width * map->info.height);
663 nav_msgs::OccupancyGrid::Ptr map2(
new nav_msgs::OccupancyGrid);
664 map2->info.width = 2;
665 map2->info.height = 2;
666 map2->info.resolution = 1.0;
667 map2->info.origin.orientation.w = 1.0;
668 map2->info.origin.position.x =
d.input.x;
669 map2->info.origin.position.y =
d.input.y;
670 map2->data.resize(map->info.width * map->info.height);
676 costmap_cspace_msgs::CSpace3DUpdate::Ptr updated;
677 auto cb = [&updated](
679 const costmap_cspace_msgs::CSpace3DUpdate::Ptr&
update) ->
bool 684 cm_output->setHandler(cb);
690 ASSERT_TRUE(static_cast<bool>(updated)) << test_name;
691 EXPECT_EQ(0u, updated->x) << test_name;
692 EXPECT_EQ(0u, updated->y) << test_name;
693 EXPECT_EQ(0u, updated->yaw) << test_name;
694 EXPECT_EQ(map->info.width, updated->width) << test_name;
695 EXPECT_EQ(map->info.height, updated->height) << test_name;
696 EXPECT_EQ(4u, updated->angle) << test_name;
700 EXPECT_FALSE(static_cast<bool>(updated)) << test_name;
708 ASSERT_TRUE(static_cast<bool>(updated)) << test_name;
709 EXPECT_EQ(
d.expected.x, updated->x) << test_name;
710 EXPECT_EQ(
d.expected.y, updated->y) << test_name;
711 EXPECT_EQ(
d.expected.yaw, updated->yaw) << test_name;
712 EXPECT_EQ(
d.expected.width, updated->width) << test_name;
713 EXPECT_EQ(
d.expected.height, updated->height) << test_name;
714 EXPECT_EQ(
d.expected.angle, updated->angle) << test_name;
718 EXPECT_FALSE(static_cast<bool>(updated)) << test_name;
723 TEST(Costmap3dLayerFootprint, CSpaceKeepUnknown)
726 int footprint_offset = 0;
731 const size_t unknown_x = 3;
732 const size_t unknown_y = 4;
733 const size_t width = 6;
734 const size_t height = 5;
735 nav_msgs::OccupancyGrid::Ptr map(
new nav_msgs::OccupancyGrid);
736 map->info.width = width;
737 map->info.height = height;
738 map->info.resolution = 1.0;
739 map->info.origin.orientation.w = 1.0;
740 map->data = std::vector<int8_t>(width * height, 0);
741 map->data[2 + width * 3] = 100;
742 map->data[3 + width * 3] = -1;
744 nav_msgs::OccupancyGrid::Ptr map_overlay(
new nav_msgs::OccupancyGrid);
745 map_overlay->info.width = width;
746 map_overlay->info.height = height;
747 map_overlay->info.resolution = 1.0;
748 map_overlay->info.origin.orientation.w = 1.0;
749 map_overlay->data = std::vector<int8_t>(width * height, 0);
750 map_overlay->data[2 + width * 4] = 100;
751 map_overlay->data[4 + width * 4] = -1;
753 map->data[unknown_x + width * unknown_y] = -1;
754 map_overlay->data[unknown_x + width * unknown_y] = -1;
759 cm_base1->setFootprint(footprint);
763 cm_normal->setFootprint(footprint);
764 cm_normal->setKeepUnknown(
false);
765 cm_base1->setBaseMap(map);
766 cm_normal->processMapOverlay(map_overlay);
771 cm_base2->setFootprint(footprint);
775 cm_keep_uknown->setFootprint(footprint);
776 cm_keep_uknown->setKeepUnknown(
true);
777 cm_base2->setBaseMap(map);
778 cm_keep_uknown->processMapOverlay(map_overlay);
782 for (
size_t yaw = 0; yaw < normal_result->info.angle; ++yaw)
784 for (
size_t y = 0;
y < normal_result->info.height; ++
y)
786 for (
size_t x = 0;
x < normal_result->info.width; ++
x)
788 if ((
x == unknown_x) && (
y == unknown_y))
790 EXPECT_GT(normal_result->getCost(
x,
y, yaw), 0);
791 EXPECT_EQ(static_cast<int>(keep_unknown_result->getCost(
x,
y, yaw)), -1);
795 EXPECT_EQ(normal_result->getCost(
x,
y, yaw), keep_unknown_result->getCost(
x,
y, yaw))
796 <<
" x:" <<
x <<
" y:" <<
y <<
" yaw:" << yaw;
803 TEST(Costmap3dLayerFootprint, Costmap3dLayerPlain)
806 footprint.
v.resize(3);
807 for (
auto& p : footprint.
v)
812 const size_t unknown_x = 3;
813 const size_t unknown_y = 4;
814 const size_t width = 6;
815 const size_t height = 5;
816 nav_msgs::OccupancyGrid::Ptr map(
new nav_msgs::OccupancyGrid);
817 map->info.width = width;
818 map->info.height = height;
819 map->info.resolution = 1.0;
820 map->info.origin.orientation.w = 1.0;
821 map->data = std::vector<int8_t>(width * height, 0);
822 map->data[2 + width * 3] = 100;
823 map->data[3 + width * 3] = -1;
825 nav_msgs::OccupancyGrid::Ptr map_overlay(
new nav_msgs::OccupancyGrid);
826 map_overlay->info.width = width;
827 map_overlay->info.height = height;
828 map_overlay->info.resolution = 1.0;
829 map_overlay->info.origin.orientation.w = 1.0;
830 map_overlay->data = std::vector<int8_t>(width * height, 0);
831 map_overlay->data[2 + width * 4] = 100;
832 map_overlay->data[4 + width * 4] = -1;
834 map->data[unknown_x + width * unknown_y] = -1;
835 map_overlay->data[unknown_x + width * unknown_y] = -1;
840 cm_base1->setFootprint(footprint);
844 cm_normal->setFootprint(footprint);
845 cm_normal->setKeepUnknown(
false);
846 cm_base1->setBaseMap(map);
847 cm_normal->processMapOverlay(map_overlay);
855 cm_plain->setKeepUnknown(
false);
856 cm_base2->setBaseMap(map);
857 cm_plain->processMapOverlay(map_overlay);
861 for (
size_t yaw = 0; yaw < normal_result->info.angle; ++yaw)
863 for (
size_t y = 0;
y < normal_result->info.height; ++
y)
865 for (
size_t x = 0;
x < normal_result->info.width; ++
x)
867 EXPECT_EQ(normal_result->getCost(
x,
y, yaw), plain_result->getCost(
x,
y, yaw))
868 <<
" x:" <<
x <<
" y:" <<
y <<
" yaw:" << yaw;
869 EXPECT_EQ(plain_result->getCost(
x,
y, yaw), plain_result->getCost(
x,
y, 0))
870 <<
" x:" <<
x <<
" y:" <<
y <<
" yaw:" << yaw;
875 int main(
int argc,
char** argv)
877 testing::InitGoogleTest(&argc, argv);
879 return RUN_ALL_TESTS();
const char temp_dir[4][2]
const std::string footprint_str("<value><array><data>"" <value><array><data>"" <value><double>1.5</double></value>"" <value><double>0.0</double></value>"" </data></array></value>"" <value><array><data>"" <value><double>-0.5</double></value>"" <value><double>-0.5</double></value>"" </data></array></value>"" <value><array><data>"" <value><double>-0.5</double></value>"" <value><double>0.5</double></value>"" </data></array></value>""</data></array></value>")
void setOverlayMode(const MapOverlayMode overlay_mode)
TFSIMD_FORCE_INLINE const tfScalar & y() const
TFSIMD_FORCE_INLINE tfScalar angle(const Quaternion &q1, const Quaternion &q2)
void update(const std::string &key, const XmlRpc::XmlRpcValue &v)
void setBaseMap(const nav_msgs::OccupancyGrid::ConstPtr &base_map)
T::Ptr addLayer(const MapOverlayMode overlay_mode=MapOverlayMode::MAX)
TFSIMD_FORCE_INLINE const tfScalar & x() const
void setAngleResolution(const int ang_resolution)
void processMapOverlay(const nav_msgs::OccupancyGrid::ConstPtr &msg)
int main(int argc, char **argv)
bool fromXml(std::string const &valueXml, int *offset)
std::shared_ptr< CSpace3DMsg > Ptr
TEST(Costmap3dLayerFootprint, CSpaceTemplate)
int getAngularGrid() const
CSpace3DMsg::Ptr getMapOverlay()