00001 #include <algorithm>
00002 #include <cmath>
00003 #include <cstdlib>
00004 #include <ctime>
00005 #include <fstream>
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>
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
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
00114
00115
00116
00117
00118
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
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
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 }