test_grid_utils.cpp
Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2008, Willow Garage, Inc.
00003  * All rights reserved.
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions are met:
00007  *
00008  *     * Redistributions of source code must retain the above copyright
00009  *       notice, this list of conditions and the following disclaimer.
00010  *     * Redistributions in binary form must reproduce the above copyright
00011  *       notice, this list of conditions and the following disclaimer in the
00012  *       documentation and/or other materials provided with the distribution.
00013  *     * Neither the name of the Willow Garage, Inc. nor the names of its
00014  *       contributors may be used to endorse or promote products derived from
00015  *       this software without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00018  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00019  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00020  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
00021  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00022  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
00023  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00024  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00025  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
00026  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00027  * POSSIBILITY OF SUCH DAMAGE.
00028  */
00029 
00030 #include <occupancy_grid_utils/ray_tracer.h>
00031 #include <occupancy_grid_utils/exceptions.h>
00032 #include <occupancy_grid_utils/shortest_path.h>
00033 #include <occupancy_grid_utils/combine_grids.h>
00034 #include <gtest/gtest.h>
00035 #include <tf/transform_datatypes.h>
00036 #include <ros/ros.h>
00037 #include <iostream>
00038 #include <boost/foreach.hpp>
00039 #include <boost/bind.hpp>
00040 #include <boost/assign.hpp>
00041 #include <cmath>
00042 
00043 namespace gm=geometry_msgs;
00044 namespace nm=nav_msgs;
00045 namespace gu=occupancy_grid_utils;
00046 
00047 using std::ostream;
00048 using gu::Cell;
00049 using std::abs;
00050 using boost::bind;
00051 using std::vector;
00052 using boost::assign::operator+=;
00053 using std::operator<<;
00054 
00055 const double PI = 3.14159265;
00056 
00057 const double TOL=1e-6;
00058 
00059 
00060 typedef vector<Cell> Path;
00061 typedef boost::shared_ptr<nm::OccupancyGrid> GridPtr;
00062 typedef boost::shared_ptr<nm::OccupancyGrid const> GridConstPtr;
00063 
00064 bool samePath (const Path& p1, const Path& p2)
00065 {
00066   if (p1.size()!=p2.size())
00067     return false;
00068   for (unsigned i=0; i<p1.size(); i++)
00069     if (!(p1[i]==p2[i]))
00070       return false;
00071   return true;
00072 }
00073 
00074 bool approxEqual (const double x, const double y)
00075 {
00076   return abs(x-y)<TOL;
00077 }
00078 
00079 
00080 
00081 namespace geometry_msgs
00082 {
00083 
00084 bool operator== (const Polygon& p1, const Polygon& p2)
00085 {
00086   if (p1.points.size() != p2.points.size())
00087     return false;
00088   for (unsigned i=0; i<p1.points.size(); i++) 
00089     if (!approxEqual(p1.points[i].x, p2.points[i].x) ||
00090         !approxEqual(p1.points[i].y, p2.points[i].y) || 
00091         !approxEqual(p1.points[i].z, p2.points[i].z))
00092       return false;
00093   return true;  
00094 }
00095 
00096 } // namespace geometry_msgs
00097 
00098 
00099 template <class T>
00100 ostream& operator<< (ostream& str, const vector<T>& s)
00101 {
00102   str << "(";
00103   BOOST_FOREACH (const T& x, s) 
00104     str << x << " ";
00105   str << ")";
00106   return str;
00107 }
00108 
00109 
00110 
00111 ostream& operator<< (ostream& str, const gm::Point& p)
00112 {
00113   str << "(" << p.x << ", " << p.y << ")";
00114   return str;
00115 }
00116 
00117 gm::Point makePoint (const double x, const double y)
00118 {
00119   gm::Point p;
00120   p.x = x;
00121   p.y = y;
00122   return p;
00123 }
00124 
00125 gm::Point32 makePoint32 (const double x, const double y)
00126 {
00127   gm::Point32 p;
00128   p.x = x;
00129   p.y = y;
00130   return p;
00131 }
00132 
00133 double norm (const double x, const double y)
00134 {
00135   return sqrt(x*x + y*y);
00136 }
00137 
00138 struct CloseTo
00139 {
00140   CloseTo(double res) : res(res) {}
00141   bool operator() (const gm::Point& p, const gm::Point& p2) 
00142   {
00143     const double dx=p2.x-p.x;
00144     const double dy=p2.y-p.y;
00145     return norm(dx, dy) < res*sqrt(2);
00146   }
00147   const double res;
00148 };
00149 
00150 double angle (const double x1, const double y1, const double x2, const double y2)
00151 {
00152   const double ip = x1*x2 + y1*y2;
00153   return acos(ip/(norm(x1, y1)*norm(x2, y2)));
00154 }
00155 
00156 gm::Pose makePose (const double x, const double y, const double theta)
00157 {
00158   gm::Pose p;
00159   p.position.x = x;
00160   p.position.y = y;
00161   p.orientation = tf::createQuaternionMsgFromYaw(theta);
00162   return p;
00163 }
00164 
00165 
00166   
00167 
00168 TEST(GridUtils, CoordinateConversions)
00169 {
00170   // Set up info for a map at (2, -1) that is rotated 45 degrees, with resolution 0.1
00171   nm::MapMetaData info;
00172   info.resolution = 0.1;
00173   info.origin = makePose(2, -1, PI/4);
00174   info.height = 50;
00175   info.width = 80;
00176 
00177   // Check conversions
00178   EXPECT_EQ (804u, gu::cellIndex(info, Cell(4, 10)));
00179   EXPECT_EQ (Cell(8, 1), gu::pointCell(info, makePoint(2.5, -0.35)));
00180   EXPECT_EQ (88u, gu::pointIndex(info, makePoint(2.5, -0.35)));
00181   EXPECT_EQ (Cell(-8, 7), gu::pointCell(info, makePoint(1, -1)));
00182   EXPECT_THROW (gu::pointIndex(info, makePoint(1, -1)), gu::CellOutOfBoundsException);
00183   EXPECT_THROW (gu::cellIndex(info, Cell(100, 100)), gu::CellOutOfBoundsException);
00184 
00185   // Cell polygon 
00186   const double side=sqrt(2)/2;
00187   gm::Polygon expected;
00188   expected.points.resize(4);
00189   expected.points[0].x = 2 + .1*side;
00190   expected.points[0].y = -1 + .3*side;
00191   expected.points[1].x = 2;
00192   expected.points[1].y = -1 + .4*side;
00193   expected.points[2].x = 2 + .1*side;
00194   expected.points[2].y = -1 + .5*side;
00195   expected.points[3].x = 2 + .2*side;
00196   expected.points[3].y = -1 + .4*side;
00197   EXPECT_EQ(expected, cellPolygon(info, Cell(2, 1)));
00198   
00199   
00200 }
00201 
00202 
00203 gm::Point lastPoint (const nm::MapMetaData& info, const gu::RayTraceIterRange& r)
00204 {
00205   boost::optional<gm::Point> last_point;
00206   BOOST_FOREACH (const Cell& c, r) {
00207     last_point = gu::cellCenter(info, c);
00208   }
00209   ROS_ASSERT(last_point);
00210   return *last_point;
00211 }
00212 
00213 TEST(GridUtils, RayTrace)
00214 {
00215   const double res=0.2;
00216   nm::MapMetaData info;
00217   info.resolution = res;
00218   info.origin = makePose(3, 1, PI/2);
00219   info.height = 100;
00220   info.width = 50;
00221   
00222   gu::RayTraceIterRange r = gu::rayTrace(info, makePoint(1, 2), makePoint(2, 5));
00223   gm::Point last_point = lastPoint(info, r);
00224 
00225   EXPECT_PRED2 (CloseTo(res), makePoint(2, 5), last_point);
00226   EXPECT_PRED2 (CloseTo(res), makePoint(1, 2), gu::cellCenter(info, *(r.first)));
00227   EXPECT_EQ (16, std::distance(r.first, r.second));
00228 
00229   // Try again with x and y flipped
00230   nm::MapMetaData info2=info;
00231   info2.origin = makePose(1, 3, PI/-2);
00232   info.height = 50;
00233   info.width = 100;
00234 
00235   gu::RayTraceIterRange r2 = gu::rayTrace(info2, makePoint(2, 1), makePoint(5, 2));
00236   gm::Point lp2 = lastPoint(info2, r2);
00237   
00238   EXPECT_PRED2 (CloseTo(res), makePoint(5, 2), lp2);
00239   EXPECT_PRED2 (CloseTo(res), makePoint(2, 1), gu::cellCenter(info2, *(r2.first)));
00240   EXPECT_EQ (16, std::distance(r2.first, r2.second));
00241 
00242 
00243   // Out of bounds points
00244   EXPECT_THROW(gu::rayTrace(info, makePoint(1, 2), makePoint(4, 2)), gu::PointOutOfBoundsException);
00245   gu::RayTraceIterRange r3 = gu::rayTrace(info, makePoint(1, 2), makePoint(4, 2), true);
00246   gm::Point lp3 = lastPoint(info, r3);
00247   EXPECT_PRED2 (CloseTo(res), makePoint(3, 2), lp3);
00248   EXPECT_PRED2 (CloseTo(res), makePoint(1, 2), gu::cellCenter(info, *(r.first)));
00249   EXPECT_EQ (10, std::distance(r3.first, r3.second));
00250   EXPECT_THROW(gu::rayTrace(info, makePoint(4, 2), makePoint(1, 2), true), gu::PointOutOfBoundsException);
00251 }
00252 
00253 
00254 TEST(GridUtils, GridOverlay)
00255 {
00256   // Grid at origin with resolution 0.1
00257   const double res=10.0;
00258   nm::MapMetaData info;
00259   info.resolution = res;
00260   info.origin = makePose(0, 0, 0);
00261   info.height = 4;
00262   info.width = 4;
00263   
00264   // Create clouds
00265   typedef vector<gm::Point32> PointVec;
00266   typedef boost::shared_ptr<gu::LocalizedCloud const> CloudConstPtr;
00267   typedef boost::shared_ptr<gu::LocalizedCloud> CloudPtr;
00268 
00269   CloudPtr c1(new gu::LocalizedCloud());
00270   c1->sensor_pose.pose = makePose(.001, .001, 0.0);
00271   c1->sensor_pose.header.frame_id = "foo";
00272   c1->cloud.points = PointVec(1);
00273   CloudPtr c2(new gu::LocalizedCloud());
00274   c2->sensor_pose.pose = makePose(25.0, 5.0, PI/2);
00275   c2->sensor_pose.header.frame_id = "foo";
00276   c2->cloud.points = PointVec(4);
00277   c1->cloud.points[0] = makePoint32(20, 20);
00278   c2->cloud.points[0] = makePoint32(20, 0);
00279   c2->cloud.points[1] = makePoint32(45, 35);
00280   c2->cloud.points[2] = makePoint32(0, 1000);
00281   c2->cloud.points[3] = makePoint32(-1, -1);
00282 
00283   // Overlay two clouds
00284   gu::OverlayClouds o1 = gu::createCloudOverlay(info, "foo", .5, 200);
00285   gu::addCloud(&o1, c1);
00286   gu::addCloud(&o1, c2);
00287   GridConstPtr grid = gu::getGrid(o1);
00288   EXPECT_EQ (gu::UNKNOWN, grid->data[0]);
00289   EXPECT_EQ (gu::UNKNOWN, grid->data[1]);
00290   EXPECT_EQ (gu::UNOCCUPIED, grid->data[2]);
00291   EXPECT_EQ (gu::UNKNOWN, grid->data[3]);
00292   EXPECT_EQ (gu::UNKNOWN, grid->data[4]);
00293   EXPECT_EQ (gu::UNOCCUPIED, grid->data[5]);
00294   EXPECT_EQ (gu::UNKNOWN, grid->data[6]);
00295   EXPECT_EQ (gu::UNKNOWN, grid->data[9]);
00296   EXPECT_EQ (gu::OCCUPIED, grid->data[10]);
00297 
00298   // Vary parameters
00299   gu::OverlayClouds o2 = gu::createCloudOverlay(info, "foo", .1, 2000);
00300   gu::addCloud(&o2, c2);
00301   gu::addCloud(&o2, c1);
00302   GridConstPtr grid2 = gu::getGrid(o2);
00303   EXPECT_EQ (gu::UNOCCUPIED, grid2->data[0]);
00304   EXPECT_EQ (gu::UNKNOWN, grid2->data[1]);
00305   EXPECT_EQ (gu::OCCUPIED, grid2->data[2]);
00306   EXPECT_EQ (gu::UNKNOWN, grid2->data[3]);
00307   EXPECT_EQ (gu::UNKNOWN, grid2->data[4]);
00308   EXPECT_EQ (gu::UNOCCUPIED, grid2->data[5]);
00309   EXPECT_EQ (gu::UNKNOWN, grid2->data[6]);
00310   EXPECT_EQ (gu::UNKNOWN, grid2->data[9]);
00311   EXPECT_EQ (gu::OCCUPIED, grid2->data[10]);
00312   EXPECT_EQ (gu::UNKNOWN, grid2->data[15]);
00313 
00314   // Add another cloud
00315   gu::addCloud(&o1, c1);
00316   GridConstPtr grid3 = gu::getGrid(o1);
00317   EXPECT_EQ (gu::UNOCCUPIED, grid3->data[0]);
00318   EXPECT_EQ (gu::UNKNOWN, grid3->data[1]);
00319   EXPECT_EQ (gu::UNOCCUPIED, grid3->data[2]);
00320 
00321   // Subtract the cloud we just added and check that it's the same as grid 1
00322   gu::removeCloud(&o1, c1);
00323   GridConstPtr grid4 = gu::getGrid(o1);
00324   for (unsigned i=0; i<16; i++)
00325     EXPECT_EQ (grid->data[i], grid4->data[i]);
00326 
00327   // Check header
00328   EXPECT_EQ(grid4->header.frame_id, "foo");
00329 }
00330 
00331 
00332 
00333 
00334 void setOccupied (nm::OccupancyGrid* g, const unsigned x, const unsigned y)
00335 {
00336   g->data[gu::cellIndex(g->info, Cell(x, y))] = gu::OCCUPIED;;
00337 }
00338 
00339 TEST(GridUtils, ShortestPath)
00340 {
00341   nm::MapMetaData info;
00342   info.resolution = 0.1;
00343   info.origin = makePose(0, 0, 0);
00344   info.height = 5;
00345   info.width = 5;
00346 
00347   GridPtr grid(new nm::OccupancyGrid());
00348   grid->info = info;
00349   grid->data.resize(25);
00350   setOccupied(grid.get(), 1, 3);
00351   setOccupied(grid.get(), 2, 2);
00352   setOccupied(grid.get(), 2, 1);
00353   setOccupied(grid.get(), 3, 2);
00354   setOccupied(grid.get(), 3, 3);
00355   setOccupied(grid.get(), 3, 4);
00356   setOccupied(grid.get(), 4, 2);
00357 
00358   Cell c1(0, 1);
00359   Cell c2(1, 4);
00360   Cell c3(2, 3);
00361   Cell c4(3, 1);
00362   Cell c5(4, 2);
00363   Cell c6(4, 3);
00364 
00365   const gu::ResultPtr res=singleSourceShortestPaths(*grid, c1);
00366   
00367   EXPECT_PRED2(approxEqual, 2+sqrt(2), *distance(res, c2));
00368   EXPECT_PRED2(approxEqual, 2*sqrt(2), *distance(res, c3));
00369   EXPECT_PRED2(approxEqual, 1+2*sqrt(2), *distance(res, c4));
00370   EXPECT_TRUE(!distance(res, c5));
00371   EXPECT_TRUE(!distance(res, c6));
00372 
00373   Path p12, p13, p14;
00374   p12 += Cell(0, 1), Cell(0, 2), Cell(0, 3), Cell(1, 4);
00375   p13 += Cell(0, 1), Cell(1, 2), Cell(2, 3);
00376   p14 += Cell(0, 1), Cell(1, 1), Cell(2, 0), Cell(3, 1);
00377   
00378   EXPECT_PRED2(samePath, p12, *extractPath(res, c2));
00379   EXPECT_PRED2(samePath, p13, *extractPath(res, c3));
00380   EXPECT_PRED2(samePath, p14, *extractPath(res, c4));
00381   EXPECT_TRUE(!extractPath(res, c5));
00382   EXPECT_TRUE(!extractPath(res, c6));
00383 
00384   // Conversion to and from ros messages
00385   const gu::NavigationFunction msg = gu::shortestPathResultToMessage(res);
00386   const gu::ResultPtr res2 = gu::shortestPathResultFromMessage(msg);
00387   
00388   EXPECT_PRED2(approxEqual, 2+sqrt(2), *distance(res2, c2));
00389   EXPECT_PRED2(approxEqual, 2*sqrt(2), *distance(res2, c3));
00390   EXPECT_PRED2(approxEqual, 1+2*sqrt(2), *distance(res2, c4));
00391   EXPECT_TRUE(!distance(res2, c5));
00392   EXPECT_TRUE(!distance(res2, c6));
00393 
00394   EXPECT_PRED2(samePath, p12, *extractPath(res2, c2));
00395   EXPECT_PRED2(samePath, p13, *extractPath(res2, c3));
00396   EXPECT_PRED2(samePath, p14, *extractPath(res2, c4));
00397   EXPECT_TRUE(!extractPath(res2, c5));
00398   EXPECT_TRUE(!extractPath(res2, c6));
00399 
00400 
00401   // Termination conditions
00402   const gu::TerminationCondition t1(4);
00403   const gu::ResultPtr res3 = gu::singleSourceShortestPaths(*grid, c4, t1);
00404   EXPECT_PRED2(approxEqual, 1+2*sqrt(2), *distance(res3, c1));
00405   EXPECT_TRUE(!distance(res3, c2));
00406   EXPECT_TRUE(!distance(res3, c3));
00407 
00408   gu::Cells goals;
00409   goals += c3, c6;
00410   const gu::TerminationCondition t2(goals);
00411   const gu::ResultPtr res4 = gu::singleSourceShortestPaths(*grid, c4, t2);
00412   EXPECT_PRED2(approxEqual, 1+3*sqrt(2), *distance(res4, c3));
00413   EXPECT_PRED2(approxEqual, 1+2*sqrt(2), *distance(res4, c1));
00414   EXPECT_TRUE(!distance(res4, c6));
00415 
00416   const gu::TerminationCondition t3(goals, 4);
00417   const gu::ResultPtr res5 = gu::singleSourceShortestPaths(*grid, c4, t3);
00418   EXPECT_PRED2(approxEqual, 1+2*sqrt(2), *distance(res5, c1));
00419   EXPECT_TRUE(!distance(res5, c2));
00420   EXPECT_TRUE(!distance(res5, c3));
00421 
00422 
00423   // A*
00424   boost::optional<gu::AStarResult> res6 = shortestPath(*grid, c1, c4);
00425   EXPECT_EQ (res6->second, 5);
00426 
00427   boost::optional<gu::AStarResult> res7 = shortestPath(*grid, c1, c1);
00428   EXPECT_EQ (res7->second, 0);
00429 
00430   boost::optional<gu::AStarResult> res8 = shortestPath(*grid, c1, c5);
00431   EXPECT_TRUE (!res8);
00432 
00433   boost::optional<gu::AStarResult> res9 = shortestPath(*grid, c1, c6);
00434   EXPECT_TRUE (!res9);
00435   
00436 }
00437 
00438 int val (const nm::OccupancyGrid& g, const gu::coord_t x, const gu::coord_t y)
00439 {
00440   const gu::Cell c(x, y);
00441   ROS_ASSERT (gu::withinBounds(g.info, c));
00442   return g.data[cellIndex(g.info, c)];
00443 }
00444 
00445 void setVal (nm::OccupancyGrid* g, const gu::coord_t x, const gu::coord_t y, const int v)
00446 {
00447   const gu::Cell c(x, y);
00448   ROS_ASSERT (gu::withinBounds(g->info, c));
00449   g->data[cellIndex(g->info, c)]=v;
00450 }
00451 
00452 TEST(GridUtils, InflateObstacles)
00453 {
00454   GridPtr g(new nm::OccupancyGrid());
00455   g->info.origin = makePose(0, 0, 0);
00456   g->info.resolution = 0.5;
00457   g->info.width = 10;
00458   g->info.height = 11;
00459   g->data.resize(g->info.width*g->info.height);
00460   fill(g->data.begin(), g->data.end(), -1);
00461   
00462   setVal(g.get(), 2, 2, 0);
00463   setVal(g.get(), 8, 8, 0);
00464   setVal(g.get(), 3, 6, 50);
00465   setVal(g.get(), 3, 7, 100);
00466   setVal(g.get(), 3, 4, 0);
00467 
00468   GridPtr g2 = gu::inflateObstacles(*g, 1.2);
00469 
00470   EXPECT_EQ (-1, val(*g2, 9, 9));
00471   EXPECT_EQ (0, val(*g2, 8, 8));
00472   EXPECT_EQ (100, val(*g2, 3, 6));
00473   EXPECT_EQ (50, val(*g2, 3, 3));
00474   EXPECT_EQ (100, val(*g2, 3, 4));
00475   EXPECT_EQ (-1, val(*g2, 1, 3));
00476   
00477 
00478 }
00479 
00480 
00481 TEST(GridUtils, CombineGrids)
00482 {
00483   GridPtr g1(new nm::OccupancyGrid());
00484   GridPtr g2(new nm::OccupancyGrid());
00485   
00486   g1->info.origin = makePose(2, 1, 0);
00487   g2->info.origin = makePose(3, 0, PI/4);
00488   g1->info.resolution = 0.5;
00489   g2->info.resolution = 0.5;
00490   g1->info.height = 4;
00491   g1->info.width = 6;
00492   g2->info.height = 4;
00493   g2->info.width = 4;
00494   g1->data.resize(24);
00495   g2->data.resize(16);
00496 
00497   fill(g1->data.begin(), g1->data.end(), -1);
00498   fill(g2->data.begin(), g2->data.end(), -1);
00499 
00500   setVal(g2.get(), 1, 0, 0);
00501   setVal(g2.get(), 0, 3, 50);
00502   setVal(g2.get(), 2, 0, 42);
00503   setVal(g2.get(), 0, 2, 11);
00504   setVal(g2.get(), 3, 2, 0);
00505   setVal(g2.get(), 3, 0, 110);
00506   
00507   setVal(g1.get(), 5, 3, 100);
00508   setVal(g1.get(), 3, 0, 24);
00509   setVal(g1.get(), 0, 0, 66);
00510   setVal(g1.get(), 4, 0, 90);
00511 
00512 
00513   
00514   vector<GridConstPtr> grids;
00515   grids += g1, g2;
00516   GridPtr combined = gu::combineGrids(grids, g1->info.resolution/2.0);
00517   
00518   EXPECT_PRED2(approxEqual, 3-sqrt(2), combined->info.origin.position.x);
00519   EXPECT_PRED2(approxEqual, 0, combined->info.origin.position.y);
00520   EXPECT_EQ(0.25, combined->info.resolution);
00521   EXPECT_EQ(round((2+sqrt(2))/0.25), combined->info.width);
00522   EXPECT_EQ(12u, combined->info.height);
00523 
00524   // Note there are rounding issues that mean that some of the values below
00525   // could theoretically go either way
00526   EXPECT_EQ(-1, val(*combined, 11, 2));
00527   EXPECT_EQ(-1, val(*combined, 2, 0));
00528   EXPECT_EQ(-1, val(*combined, 5, 0));
00529   EXPECT_EQ(0, val(*combined, 7, 2));
00530   EXPECT_EQ(66, val(*combined, 1, 6));
00531   EXPECT_EQ(100, val(*combined, 11, 11));
00532   EXPECT_EQ(-1, val(*combined, 2, 11));
00533   EXPECT_EQ(11, val(*combined, 3, 2));
00534   EXPECT_EQ(42, val(*combined, 7, 4));
00535   EXPECT_EQ(66, val(*combined, 2, 4));
00536   EXPECT_EQ(0, val(*combined, 6, 8));
00537   EXPECT_EQ(90, val(*combined, 10, 5));
00538   
00539   
00540 }
00541 
00542 int main (int argc, char** argv)
00543 {
00544   testing::InitGoogleTest(&argc, argv);
00545   return RUN_ALL_TESTS();
00546 }


occupancy_grid_utils
Author(s): Bhaskara Marthi
autogenerated on Tue Jan 7 2014 11:17:09