utest.cpp
Go to the documentation of this file.
00001 #include <algorithm>
00002 #include <cmath> // std::cos, std::sin
00003 #include <cstdlib> // std::rand
00004 #include <ctime> // std::time
00005 #include <fstream> // std::ofstream
00006 #include <vector>
00007 
00008 #include <geometry_msgs/Point32.h>
00009 #include <geometry_msgs/Polygon.h>
00010 #include <geometry_msgs/Pose.h>
00011 #include <gtest/gtest.h>
00012 #include <place_matcher_msgs/PolygonDissimilarity.h>
00013 #include <ros/ros.h>
00014 #include <tf/tf.h> // for getYaw().
00015 
00016 #include <place_matcher_csm/dissimilarity_getter.h>
00017 
00018 #define FILE_OUTPUT 0
00019 
00020 ros::NodeHandlePtr g_nh_ptr;
00021 
00022 #if FILE_OUTPUT
00023 void saveToFile(const std::string& filename, const geometry_msgs::Polygon& poly)
00024 {
00025   std::ofstream fout(filename.c_str());
00026   if (!fout.is_open())
00027   {
00028     std::cerr << "\"" << filename << "\" cannot be opened for writing";
00029     return;
00030   }
00031   std::vector<geometry_msgs::Point32>::const_iterator it = poly.points.begin();
00032   for (; it < poly.points.end(); ++it)
00033   {
00034     fout << it->x << "," << it->y << "\n";
00035   }
00036 }
00037 #endif
00038 
00039 void transformPoint(const geometry_msgs::Pose& transform, geometry_msgs::Point32& point)
00040 {
00041   const geometry_msgs::Point32 old_point = point;
00042   const double yaw = tf::getYaw(transform.orientation);
00043   const double cos_yaw = std::cos(yaw);
00044   const double sin_yaw = std::sin(yaw);
00045   point.x = transform.position.x + old_point.x * cos_yaw - old_point.y * sin_yaw;
00046   point.y = transform.position.y + old_point.x * sin_yaw + old_point.y * cos_yaw;
00047 }
00048 
00049 void transformPolygon(const geometry_msgs::Pose& transform, geometry_msgs::Polygon& poly)
00050 {
00051   for (size_t i = 0; i < poly.points.size(); ++i)
00052   {
00053     transformPoint(transform, poly.points[i]);
00054   }
00055 }
00056 
00057 geometry_msgs::Polygon getRandPolygon()
00058 {
00059   const double angle_resolution = M_PI / 180;
00060   const double range_min = 2.0;
00061   const double range_max = 5.0;
00062 
00063   geometry_msgs::Polygon poly;
00064   const size_t point_count = (size_t) (2 * M_PI / angle_resolution);
00065   poly.points.reserve(point_count);
00066   for (double theta = - 2 * M_PI + 1e-10; theta < 2 * M_PI; theta += angle_resolution)
00067   {
00068     geometry_msgs::Point32 point;
00069     double r = range_min + (range_max - range_min) * ((double) std::rand()) / RAND_MAX; 
00070     point.x = r * std::cos(theta);
00071     point.y = r * std::sin(theta);
00072     poly.points.push_back(point);
00073   }
00074   return poly;
00075 }
00076 
00077 std::vector<geometry_msgs::Point32> interpolate(const geometry_msgs::Point32& a, const geometry_msgs::Point32 b, double max_distance)
00078 {
00079   std::vector<geometry_msgs::Point32> points;
00080 
00081   const double dx = b.x - a.x;
00082   const double dy = b.y - a.y;
00083 
00084   geometry_msgs::Point32 point;
00085   const double norm = std::sqrt(dx * dx + dy * dy);
00086   if (norm == 0)
00087   {
00088     points.push_back(a);
00089     return points;
00090   }
00091 
00092   // Unit vector from a to b.
00093   const double ux = dx / norm;
00094   const double uy = dy / norm;
00095   for (double s = 0; s <= norm; s += max_distance) 
00096   {
00097     point.x = a.x + s * ux;
00098     point.y = a.y + s * uy;
00099     points.push_back(point);
00100   }
00101   return points;
00102 }
00103 
00104 geometry_msgs::Point32 point(double x, double y)
00105 {
00106   geometry_msgs::Point32 point;
00107   point.x = x;
00108   point.y = y;
00109   return point;
00110 }
00111 
00112 /* 
00113  * Profile:
00114  *     P4 ++++++++++++++++++++++ P3
00115  *       +                      +
00116  *      P0  +                    +
00117  *     +                          + 
00118  * P1 ++++++++++++++++++++++++++++ P2
00119  *
00120  */
00121 geometry_msgs::Polygon getTestPolygon()
00122 {
00123   geometry_msgs::Polygon poly;
00124 
00125   geometry_msgs::Point32 p0 = point(-0.6, 0);
00126   geometry_msgs::Point32 p1 = point(-1, -1);
00127   geometry_msgs::Point32 p2 = point(1, p1.y);
00128   geometry_msgs::Point32 p3 = point(0.8, 0.8);
00129   geometry_msgs::Point32 p4 = point(-0.9, p3.y);
00130 
00131   std::vector<geometry_msgs::Point32> points;
00132   points = interpolate(p0, p1, 0.1);
00133   std::copy(points.begin(), points.end(), std::back_inserter(poly.points));
00134   points = interpolate(p1, p2, 0.1);
00135   std::copy(points.begin(), points.end(), std::back_inserter(poly.points));
00136   points = interpolate(p2, p3, 0.1);
00137   std::copy(points.begin(), points.end(), std::back_inserter(poly.points));
00138   points = interpolate(p3, p4, 0.1);
00139   std::copy(points.begin(), points.end(), std::back_inserter(poly.points));
00140   points = interpolate(p4, p0, 0.1);
00141   std::copy(points.begin(), points.end(), std::back_inserter(poly.points));
00142 
00143   return poly;
00144 }
00145 
00146 TEST(TestSuite, testGetDissimilarity)
00147 {
00148   const geometry_msgs::Polygon poly_ref = getTestPolygon();
00149   double dtheta = 0.4;
00150   geometry_msgs::Pose transform;
00151   transform.position.x = 0.4;
00152   transform.position.y = 0.2;
00153   transform.orientation = tf::createQuaternionMsgFromYaw(dtheta);
00154   geometry_msgs::Polygon poly_sens = poly_ref;
00155   transformPolygon(transform, poly_sens);
00156 
00157 #if FILE_OUTPUT
00158   saveToFile("/tmp/poly_ref.csv", poly_ref);
00159   saveToFile("/tmp/poly_sens.csv", poly_sens);
00160 #endif
00161 
00162   place_matcher_msgs::PolygonDissimilarityRequest req;
00163   place_matcher_msgs::PolygonDissimilarityResponse res;
00164   req.polygon1 = poly_ref;
00165   req.polygon2 = poly_sens;
00166   
00167   EXPECT_EQ(poly_sens.points.size(), req.polygon2.points.size());
00168   ros::ServiceClient client = g_nh_ptr->serviceClient<place_matcher_msgs::PolygonDissimilarity>("/place_matcher_csm/compute_dissimilarity");
00169   while (ros::ok() && !client.waitForExistence(ros::Duration(5)))
00170   {
00171     ROS_INFO_STREAM("Waiting for service " << client.getService());
00172   }
00173   ASSERT_TRUE(client.call(req, res));
00174   EXPECT_NEAR(res.pose.position.x, transform.position.x, 1e-3);
00175   EXPECT_NEAR(res.pose.position.y, transform.position.y, 1e-3);
00176   EXPECT_NEAR(tf::getYaw(res.pose.orientation), dtheta, 1e-4);
00177 
00178   const double dissimilarity_0 = res.raw_dissimilarity;
00179 
00180   dtheta = 1.4;
00181   transform.position.x = -0.4;
00182   transform.position.y = -0.2;
00183   transform.orientation = tf::createQuaternionMsgFromYaw(dtheta);
00184   poly_sens = poly_ref;
00185   transformPolygon(transform, poly_sens);
00186 
00187 #if FILE_OUTPUT
00188   saveToFile("/tmp/poly_ref_2.csv", poly_ref);
00189   saveToFile("/tmp/poly_sens_2.csv", poly_sens);
00190 #endif
00191 
00192   req.polygon1 = poly_ref;
00193   req.polygon2 = poly_sens;
00194   
00195   ASSERT_TRUE(client.call(req, res));
00196   EXPECT_NEAR(res.pose.position.x, transform.position.x, 1e-3);
00197   EXPECT_NEAR(res.pose.position.y, transform.position.y, 1e-3);
00198   EXPECT_NEAR(tf::getYaw(res.pose.orientation), dtheta, 1e-4);
00199 
00200   // Test that the dissimilarity is rotation invariant.
00201   EXPECT_NEAR(res.raw_dissimilarity, dissimilarity_0, 1e-2);
00202 }
00203 
00204 int main(int argc, char *argv[])
00205 {
00206   std::srand(std::time(0));
00207 
00208   // ros::init is needed because DissimilarityGetter uses ros::NodeHandle.
00209   ros::init(argc, argv, "test_cpp_place_matcher_csm");
00210   ros::NodeHandle nh;
00211   g_nh_ptr.reset(&nh);
00212 
00213   testing::InitGoogleTest(&argc, argv);
00214   return RUN_ALL_TESTS();
00215 }


place_matcher_csm
Author(s): Gaƫl Ecorchard
autogenerated on Sat Jun 8 2019 19:52:59