test_grid_utils.cpp
Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2008, Willow Garage, Inc.
00003  * Copyright (c) 2015-2016, Jiri Horner
00004  * All rights reserved.
00005  *
00006  * Redistribution and use in source and binary forms, with or without
00007  * modification, are permitted provided that the following conditions are met:
00008  *
00009  *     * Redistributions of source code must retain the above copyright
00010  *       notice, this list of conditions and the following disclaimer.
00011  *     * Redistributions in binary form must reproduce the above copyright
00012  *       notice, this list of conditions and the following disclaimer in the
00013  *       documentation and/or other materials provided with the distribution.
00014  *     * Neither the name of the Jiri Horner nor the names of its
00015  *       contributors may be used to endorse or promote products derived from
00016  *       this software without specific prior written permission.
00017  *
00018  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00019  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00020  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00021  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
00022  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00023  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
00024  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00025  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00026  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
00027  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00028  * POSSIBILITY OF SUCH DAMAGE.
00029  */
00030 
00031 #include <iostream>
00032 #include <cmath>
00033 
00034 #include <ros/ros.h>
00035 
00036 #include <gtest/gtest.h>
00037 
00038 #include <occupancy_grid_utils/combine_grids.h>
00039 #include <occupancy_grid_utils/coordinate_conversions.h>
00040 
00041 const double PI = 3.14159265;
00042 const double TOL = 1e-6;
00043 
00044 typedef boost::shared_ptr<nav_msgs::OccupancyGrid> GridPtr;
00045 typedef boost::shared_ptr<nav_msgs::OccupancyGrid const> GridConstPtr;
00046 
00047 /* helpers for tests */
00048 
00049 bool approxEqual (const double x, const double y);
00050 int val (const nav_msgs::OccupancyGrid& g, const occupancy_grid_utils::coord_t x, const occupancy_grid_utils::coord_t y);
00051 geometry_msgs::Point makePoint (const double x, const double y);
00052 geometry_msgs::Pose makePose (const double x, const double y, const double theta);
00053 void setVal (nav_msgs::OccupancyGrid* g, const occupancy_grid_utils::coord_t x, const occupancy_grid_utils::coord_t y, const signed char v);
00054 
00055 namespace geometry_msgs {
00056 bool operator== (const Polygon& p1, const Polygon& p2);
00057 
00058 bool operator== (const Polygon& p1, const Polygon& p2)
00059 {
00060   if (p1.points.size() != p2.points.size())
00061     return false;
00062   for (unsigned i=0; i<p1.points.size(); i++) 
00063     if (!approxEqual(p1.points[i].x, p2.points[i].x) ||
00064         !approxEqual(p1.points[i].y, p2.points[i].y) || 
00065         !approxEqual(p1.points[i].z, p2.points[i].z))
00066       return false;
00067   return true;  
00068 }
00069 
00070 } // namespace geometry_msgs
00071 
00072 bool approxEqual (const double x, const double y)
00073 {
00074   return std::abs(x-y)<TOL;
00075 }
00076 
00077 int val (const nav_msgs::OccupancyGrid& g, const occupancy_grid_utils::coord_t x, const occupancy_grid_utils::coord_t y)
00078 {
00079   const occupancy_grid_utils::Cell c(x, y);
00080   ROS_ASSERT (occupancy_grid_utils::withinBounds(g.info, c));
00081   return g.data[cellIndex(g.info, c)];
00082 }
00083 
00084 geometry_msgs::Point makePoint (const double x, const double y)
00085 {
00086   geometry_msgs::Point p;
00087   p.x = x;
00088   p.y = y;
00089   return p;
00090 }
00091 
00092 geometry_msgs::Pose makePose (const double x, const double y, const double theta)
00093 {
00094   geometry_msgs::Pose p;
00095   p.position.x = x;
00096   p.position.y = y;
00097   p.orientation = tf::createQuaternionMsgFromYaw(theta);
00098   return p;
00099 }
00100 
00101 void setVal (nav_msgs::OccupancyGrid* g, const occupancy_grid_utils::coord_t x, const occupancy_grid_utils::coord_t y, const signed char v)
00102 {
00103   const occupancy_grid_utils::Cell c(x, y);
00104   ROS_ASSERT (occupancy_grid_utils::withinBounds(g->info, c));
00105   g->data[cellIndex(g->info, c)]=v;
00106 }
00107 
00108 TEST(GridUtils, CoordinateConversions)
00109 {
00110   // Set up info for a map at (2, -1) that is rotated 45 degrees, with resolution 0.1
00111   nav_msgs::MapMetaData info;
00112   info.resolution = 0.1f;
00113   info.origin = makePose(2, -1, PI/4);
00114   info.height = 50;
00115   info.width = 80;
00116 
00117   // Check conversions
00118   EXPECT_EQ (804u, occupancy_grid_utils::cellIndex(info, occupancy_grid_utils::Cell(4, 10)));
00119   EXPECT_EQ (occupancy_grid_utils::Cell(8, 1), occupancy_grid_utils::pointCell(info, makePoint(2.5, -0.35)));
00120   EXPECT_EQ (88u, occupancy_grid_utils::pointIndex(info, makePoint(2.5, -0.35)));
00121   EXPECT_EQ (occupancy_grid_utils::Cell(-8, 7), occupancy_grid_utils::pointCell(info, makePoint(1, -1)));
00122   EXPECT_THROW (occupancy_grid_utils::pointIndex(info, makePoint(1, -1)), std::out_of_range);
00123   EXPECT_THROW (occupancy_grid_utils::cellIndex(info, occupancy_grid_utils::Cell(100, 100)), std::out_of_range);
00124 
00125   // Cell polygon 
00126   const double side = std::sqrt(2)/2;
00127   geometry_msgs::Polygon expected;
00128   expected.points.resize(4);
00129   expected.points[0].x = static_cast<float>(2 + .1*side);
00130   expected.points[0].y = static_cast<float>(-1 + .3*side);
00131   expected.points[1].x = static_cast<float>(2);
00132   expected.points[1].y = static_cast<float>(-1 + .4*side);
00133   expected.points[2].x = static_cast<float>(2 + .1*side);
00134   expected.points[2].y = static_cast<float>(-1 + .5*side);
00135   expected.points[3].x = static_cast<float>(2 + .2*side);
00136   expected.points[3].y = static_cast<float>(-1 + .4*side);
00137   EXPECT_EQ(expected, cellPolygon(info, occupancy_grid_utils::Cell(2, 1)));
00138 }
00139 
00140 TEST(GridUtils, CombineGrids)
00141 {
00142   GridPtr g1(new nav_msgs::OccupancyGrid());
00143   GridPtr g2(new nav_msgs::OccupancyGrid());
00144   
00145   g1->info.origin = makePose(2, 1, 0);
00146   g2->info.origin = makePose(3, 0, PI/4);
00147   g1->info.resolution = 0.5;
00148   g2->info.resolution = 0.5;
00149   g1->info.height = 4;
00150   g1->info.width = 6;
00151   g2->info.height = 4;
00152   g2->info.width = 4;
00153   g1->data.resize(24);
00154   g2->data.resize(16);
00155 
00156   fill(g1->data.begin(), g1->data.end(), -1);
00157   fill(g2->data.begin(), g2->data.end(), -1);
00158 
00159   setVal(g2.get(), 1, 0, 0);
00160   setVal(g2.get(), 0, 3, 50);
00161   setVal(g2.get(), 2, 0, 42);
00162   setVal(g2.get(), 0, 2, 11);
00163   setVal(g2.get(), 3, 2, 0);
00164   setVal(g2.get(), 3, 0, 110);
00165   
00166   setVal(g1.get(), 5, 3, 100);
00167   setVal(g1.get(), 3, 0, 24);
00168   setVal(g1.get(), 0, 0, 66);
00169   setVal(g1.get(), 4, 0, 90);
00170   
00171   std::vector<GridConstPtr> grids;
00172   grids.push_back(g1);
00173   grids.push_back(g2);
00174   GridPtr combined = occupancy_grid_utils::combineGrids(grids, g1->info.resolution/2.0);
00175   
00176   EXPECT_PRED2(approxEqual, 3-std::sqrt(2), combined->info.origin.position.x);
00177   EXPECT_PRED2(approxEqual, 0, combined->info.origin.position.y);
00178   EXPECT_EQ(0.25, combined->info.resolution);
00179   EXPECT_EQ(std::round((2+std::sqrt(2))/0.25), combined->info.width);
00180   EXPECT_EQ(12u, combined->info.height);
00181 
00182   // Note there are rounding issues that mean that some of the values below
00183   // could theoretically go either way
00184   EXPECT_EQ(-1, val(*combined, 11, 2));
00185   EXPECT_EQ(-1, val(*combined, 2, 0));
00186   EXPECT_EQ(-1, val(*combined, 5, 0));
00187   EXPECT_EQ(0, val(*combined, 7, 2));
00188   EXPECT_EQ(66, val(*combined, 1, 6));
00189   EXPECT_EQ(100, val(*combined, 11, 11));
00190   EXPECT_EQ(-1, val(*combined, 2, 11));
00191   EXPECT_EQ(11, val(*combined, 3, 2));
00192   EXPECT_EQ(42, val(*combined, 7, 4));
00193   EXPECT_EQ(66, val(*combined, 2, 4));
00194   EXPECT_EQ(0, val(*combined, 6, 8));
00195   EXPECT_EQ(90, val(*combined, 10, 5));
00196 }
00197 
00198 int main (int argc, char** argv)
00199 {
00200   ros::Time::init();
00201   testing::InitGoogleTest(&argc, argv);
00202   return RUN_ALL_TESTS();
00203 }


map_merge
Author(s): Jiri Horner
autogenerated on Sun Mar 26 2017 03:48:10