30 #include <gtest/gtest.h> 33 #include "sensor_msgs/PointCloud.h" 39 #include "rostest/permuter.h" 41 #define PROJECTION_TEST_RANGE_MIN (0.23) 42 #define PROJECTION_TEST_RANGE_MAX (40.0) 48 double ang_min,
double ang_max,
double ang_increment,
51 if (((ang_max - ang_min) / ang_increment) < 0)
54 sensor_msgs::LaserScan scan;
56 scan.header.frame_id =
"laser_frame";
57 scan.angle_min = ang_min;
58 scan.angle_max = ang_max;
59 scan.angle_increment = ang_increment;
60 scan.scan_time = scan_time.
toSec();
64 for(; ang_min + i * ang_increment < ang_max; i++)
66 scan.ranges.push_back(range);
67 scan.intensities.push_back(intensity);
70 scan.time_increment = scan_time.
toSec()/(double)i;
79 const boost::numeric::ublas::matrix<double>&
getUnitVectors(
double angle_min,
81 double angle_increment,
84 return getUnitVectors_(angle_min, angle_max, angle_increment, length);
88 void test_getUnitVectors(
double angle_min,
double angle_max,
double angle_increment,
unsigned int length)
90 double tolerance = 1e-12;
93 const boost::numeric::ublas::matrix<double> & mat = projector.
getUnitVectors(angle_min, angle_max, angle_increment, length);
97 for (
unsigned int i = 0; i < mat.size2(); i++)
100 angle_min + i * angle_increment),
103 EXPECT_NEAR(1.0, mat(1,i)*mat(1,i) + mat(0,i)*mat(0,i), tolerance);
111 double min_angle = -M_PI/2;
112 double max_angle = M_PI/2;
113 double angle_increment = M_PI/180;
115 std::vector<double> min_angles, max_angles, angle_increments;
117 rostest::Permuter permuter;
118 min_angles.push_back(-M_PI);
119 min_angles.push_back(-M_PI/1.5);
120 min_angles.push_back(-M_PI/2);
121 min_angles.push_back(-M_PI/4);
122 min_angles.push_back(-M_PI/8);
123 min_angles.push_back(M_PI);
124 min_angles.push_back(M_PI/1.5);
125 min_angles.push_back(M_PI/2);
126 min_angles.push_back(M_PI/4);
127 min_angles.push_back(M_PI/8);
128 permuter.addOptionSet(min_angles, &min_angle);
130 max_angles.push_back(M_PI);
131 max_angles.push_back(M_PI/1.5);
132 max_angles.push_back(M_PI/2);
133 max_angles.push_back(M_PI/4);
134 max_angles.push_back(M_PI/8);
135 max_angles.push_back(-M_PI);
136 max_angles.push_back(-M_PI/1.5);
137 max_angles.push_back(-M_PI/2);
138 max_angles.push_back(-M_PI/4);
139 max_angles.push_back(-M_PI/8);
140 permuter.addOptionSet(max_angles, &max_angle);
142 angle_increments.push_back(M_PI/180);
143 angle_increments.push_back(M_PI/360);
144 angle_increments.push_back(M_PI/720);
145 angle_increments.push_back(-M_PI/180);
146 angle_increments.push_back(-M_PI/360);
147 angle_increments.push_back(-M_PI/720);
148 permuter.addOptionSet(angle_increments, &angle_increment);
151 while (permuter.step())
153 if ((max_angle - min_angle) / angle_increment > 0.0)
155 unsigned int length = round((max_angle - min_angle)/ angle_increment);
159 test_getUnitVectors(min_angle, max_angle, angle_increment, (max_angle - min_angle)/ angle_increment);
160 test_getUnitVectors(min_angle, max_angle, angle_increment, (max_angle - min_angle)/ angle_increment + 1);
164 if ((max_angle - min_angle) / angle_increment > 0.0)
176 double tolerance = 1e-12;
179 double min_angle = -M_PI/2;
180 double max_angle = M_PI/2;
181 double angle_increment = M_PI/180;
184 double intensity = 1.0;
190 std::vector<double> ranges, intensities, min_angles, max_angles, angle_increments;
191 std::vector<ros::Duration> increment_times, scan_times;
193 rostest::Permuter permuter;
195 ranges.push_back(-1.0);
196 ranges.push_back(1.0);
197 ranges.push_back(2.0);
198 ranges.push_back(3.0);
199 ranges.push_back(4.0);
200 ranges.push_back(5.0);
201 ranges.push_back(100.0);
202 permuter.addOptionSet(ranges, &range);
204 intensities.push_back(1.0);
205 intensities.push_back(2.0);
206 intensities.push_back(3.0);
207 intensities.push_back(4.0);
208 intensities.push_back(5.0);
209 permuter.addOptionSet(intensities, &intensity);
211 min_angles.push_back(-M_PI);
212 min_angles.push_back(-M_PI/1.5);
213 min_angles.push_back(-M_PI/2);
214 min_angles.push_back(-M_PI/4);
215 min_angles.push_back(-M_PI/8);
216 permuter.addOptionSet(min_angles, &min_angle);
218 max_angles.push_back(M_PI);
219 max_angles.push_back(M_PI/1.5);
220 max_angles.push_back(M_PI/2);
221 max_angles.push_back(M_PI/4);
222 max_angles.push_back(M_PI/8);
223 permuter.addOptionSet(max_angles, &max_angle);
226 angle_increments.push_back(M_PI/180);
227 angle_increments.push_back(M_PI/360);
228 angle_increments.push_back(M_PI/720);
229 permuter.addOptionSet(angle_increments, &angle_increment);
234 permuter.addOptionSet(scan_times, &scan_time);
236 while (permuter.step())
241 sensor_msgs::LaserScan scan =
build_constant_scan(range, intensity, min_angle, max_angle, angle_increment, scan_time);
243 sensor_msgs::PointCloud cloud_out;
245 EXPECT_EQ(cloud_out.channels.size(), (
unsigned int)1);
247 EXPECT_EQ(cloud_out.channels.size(), (
unsigned int)1);
250 EXPECT_EQ(cloud_out.channels.size(), (
unsigned int)2);
252 EXPECT_EQ(cloud_out.channels.size(), (
unsigned int)2);
255 EXPECT_EQ(cloud_out.channels.size(), (
unsigned int)3);
258 EXPECT_EQ(cloud_out.channels.size(), (
unsigned int)4);
260 unsigned int valid_points = 0;
261 for (
unsigned int i = 0; i < scan.ranges.size(); i++)
265 EXPECT_EQ(valid_points, cloud_out.points.size());
267 for (
unsigned int i = 0; i < cloud_out.points.size(); i++)
269 EXPECT_NEAR(cloud_out.points[i].x , (
float)((
double)(scan.ranges[i]) * cos((
double)(scan.angle_min) + i * (
double)(scan.angle_increment))), tolerance);
270 EXPECT_NEAR(cloud_out.points[i].y , (
float)((
double)(scan.ranges[i]) * sin((
double)(scan.angle_min) + i * (
double)(scan.angle_increment))), tolerance);
271 EXPECT_NEAR(cloud_out.points[i].z, 0, tolerance);
272 EXPECT_NEAR(cloud_out.channels[0].values[i], scan.intensities[i], tolerance);
273 EXPECT_NEAR(cloud_out.channels[1].values[i], i, tolerance);
274 EXPECT_NEAR(cloud_out.channels[2].values[i], scan.ranges[i], tolerance);
275 EXPECT_NEAR(cloud_out.channels[3].values[i], (
float)i * scan.time_increment, tolerance);
280 if ((max_angle - min_angle) / angle_increment > 0.0)
291 double tolerance = 1e-12;
294 double min_angle = -M_PI/2;
295 double max_angle = M_PI/2;
296 double angle_increment = M_PI/180;
299 double intensity = 1.0;
305 std::vector<double> ranges, intensities, min_angles, max_angles, angle_increments;
306 std::vector<ros::Duration> increment_times, scan_times;
308 rostest::Permuter permuter;
310 ranges.push_back(-1.0);
311 ranges.push_back(1.0);
312 ranges.push_back(2.0);
313 ranges.push_back(3.0);
314 ranges.push_back(4.0);
315 ranges.push_back(5.0);
316 ranges.push_back(100.0);
317 permuter.addOptionSet(ranges, &range);
319 intensities.push_back(1.0);
320 intensities.push_back(2.0);
321 intensities.push_back(3.0);
322 intensities.push_back(4.0);
323 intensities.push_back(5.0);
324 permuter.addOptionSet(intensities, &intensity);
326 min_angles.push_back(-M_PI);
327 min_angles.push_back(-M_PI/1.5);
328 min_angles.push_back(-M_PI/2);
329 min_angles.push_back(-M_PI/4);
330 min_angles.push_back(-M_PI/8);
331 permuter.addOptionSet(min_angles, &min_angle);
333 max_angles.push_back(M_PI);
334 max_angles.push_back(M_PI/1.5);
335 max_angles.push_back(M_PI/2);
336 max_angles.push_back(M_PI/4);
337 max_angles.push_back(M_PI/8);
338 permuter.addOptionSet(max_angles, &max_angle);
341 angle_increments.push_back(M_PI/180);
342 angle_increments.push_back(M_PI/360);
343 angle_increments.push_back(M_PI/720);
344 permuter.addOptionSet(angle_increments, &angle_increment);
349 permuter.addOptionSet(scan_times, &scan_time);
351 while (permuter.step())
356 sensor_msgs::LaserScan scan =
build_constant_scan(range, intensity, min_angle, max_angle, angle_increment, scan_time);
358 sensor_msgs::PointCloud2 cloud_out;
360 EXPECT_EQ(cloud_out.fields.size(), (
unsigned int)4);
362 EXPECT_EQ(cloud_out.fields.size(), (
unsigned int)4);
365 EXPECT_EQ(cloud_out.fields.size(), (
unsigned int)5);
367 EXPECT_EQ(cloud_out.fields.size(), (
unsigned int)5);
370 EXPECT_EQ(cloud_out.fields.size(), (
unsigned int)6);
373 EXPECT_EQ(cloud_out.fields.size(), (
unsigned int)7);
375 unsigned int valid_points = 0;
376 for (
unsigned int i = 0; i < scan.ranges.size(); i++)
380 EXPECT_EQ(valid_points, cloud_out.width);
382 uint32_t x_offset = 0;
383 uint32_t y_offset = 0;
384 uint32_t z_offset = 0;
385 uint32_t intensity_offset = 0;
386 uint32_t index_offset = 0;
387 uint32_t distance_offset = 0;
388 uint32_t stamps_offset = 0;
389 for (std::vector<sensor_msgs::PointField>::iterator
f = cloud_out.fields.begin();
f != cloud_out.fields.end();
f++)
391 if (
f->name ==
"x") x_offset =
f->offset;
392 if (
f->name ==
"y") y_offset =
f->offset;
393 if (
f->name ==
"z") z_offset =
f->offset;
394 if (
f->name ==
"intensity") intensity_offset =
f->offset;
395 if (
f->name ==
"index") index_offset =
f->offset;
396 if (
f->name ==
"distances") distance_offset =
f->offset;
397 if (
f->name ==
"stamps") stamps_offset =
f->offset;
400 for (
unsigned int i = 0; i < cloud_out.width; i++)
403 EXPECT_NEAR(*(
float*)&cloud_out.data[i*cloud_out.point_step + x_offset] , (
float)((
double)(scan.ranges[i]) * cos((
double)(scan.angle_min) + i * (
double)(scan.angle_increment))), tolerance);
404 EXPECT_NEAR(*(
float*)&cloud_out.data[i*cloud_out.point_step + y_offset] , (
float)((
double)(scan.ranges[i]) * sin((
double)(scan.angle_min) + i * (
double)(scan.angle_increment))), tolerance);
405 EXPECT_NEAR(*(
float*)&cloud_out.data[i*cloud_out.point_step + z_offset] , 0, tolerance);
406 EXPECT_NEAR(*(
float*)&cloud_out.data[i*cloud_out.point_step + intensity_offset] , scan.intensities[i], tolerance);
407 EXPECT_NEAR(*(uint32_t*)&cloud_out.data[i*cloud_out.point_step + index_offset], i, tolerance);
408 EXPECT_NEAR(*(
float*)&cloud_out.data[i*cloud_out.point_step + distance_offset], scan.ranges[i], tolerance);
409 EXPECT_NEAR(*(
float*)&cloud_out.data[i*cloud_out.point_step + stamps_offset], (
float)i * scan.time_increment, tolerance);
414 if ((max_angle - min_angle) / angle_increment > 0.0)
426 double tolerance = 1e-12;
429 double min_angle = -M_PI/2;
430 double max_angle = M_PI/2;
431 double angle_increment = M_PI/180;
434 double intensity = 1.0;
440 std::vector<double> ranges, intensities, min_angles, max_angles, angle_increments;
441 std::vector<ros::Duration> increment_times, scan_times;
443 rostest::Permuter permuter;
445 ranges.push_back(-1.0);
446 ranges.push_back(1.0);
447 ranges.push_back(2.0);
448 ranges.push_back(3.0);
449 ranges.push_back(4.0);
450 ranges.push_back(5.0);
451 ranges.push_back(100.0);
452 permuter.addOptionSet(ranges, &range);
454 intensities.push_back(1.0);
455 intensities.push_back(2.0);
456 intensities.push_back(3.0);
457 intensities.push_back(4.0);
458 intensities.push_back(5.0);
459 permuter.addOptionSet(intensities, &intensity);
461 min_angles.push_back(-M_PI);
462 min_angles.push_back(-M_PI/1.5);
463 min_angles.push_back(-M_PI/2);
464 min_angles.push_back(-M_PI/4);
465 min_angles.push_back(-M_PI/8);
468 max_angles.push_back(M_PI);
469 max_angles.push_back(M_PI/1.5);
470 max_angles.push_back(M_PI/2);
471 max_angles.push_back(M_PI/4);
472 max_angles.push_back(M_PI/8);
474 permuter.addOptionSet(min_angles, &min_angle);
475 permuter.addOptionSet(max_angles, &max_angle);
477 angle_increments.push_back(-M_PI/180);
478 angle_increments.push_back(M_PI/180);
479 angle_increments.push_back(M_PI/360);
480 angle_increments.push_back(M_PI/720);
481 permuter.addOptionSet(angle_increments, &angle_increment);
486 permuter.addOptionSet(scan_times, &scan_time);
488 while (permuter.step())
493 sensor_msgs::LaserScan scan =
build_constant_scan(range, intensity, min_angle, max_angle, angle_increment, scan_time);
494 scan.header.frame_id =
"laser_frame";
496 sensor_msgs::PointCloud cloud_out;
498 EXPECT_EQ(cloud_out.channels.size(), (
unsigned int)1);
500 EXPECT_EQ(cloud_out.channels.size(), (
unsigned int)1);
503 EXPECT_EQ(cloud_out.channels.size(), (
unsigned int)2);
505 EXPECT_EQ(cloud_out.channels.size(), (
unsigned int)2);
508 EXPECT_EQ(cloud_out.channels.size(), (
unsigned int)3);
511 EXPECT_EQ(cloud_out.channels.size(), (
unsigned int)4);
513 unsigned int valid_points = 0;
514 for (
unsigned int i = 0; i < scan.ranges.size(); i++)
517 EXPECT_EQ(valid_points, cloud_out.points.size());
519 for (
unsigned int i = 0; i < cloud_out.points.size(); i++)
521 EXPECT_NEAR(cloud_out.points[i].x , (
float)((
double)(scan.ranges[i]) * cos((
double)(scan.angle_min) + i * (
double)(scan.angle_increment))), tolerance);
522 EXPECT_NEAR(cloud_out.points[i].y , (
float)((
double)(scan.ranges[i]) * sin((
double)(scan.angle_min) + i * (
double)(scan.angle_increment))), tolerance);
523 EXPECT_NEAR(cloud_out.points[i].z, 0, tolerance);
524 EXPECT_NEAR(cloud_out.channels[0].values[i], scan.intensities[i], tolerance);
525 EXPECT_NEAR(cloud_out.channels[1].values[i], i, tolerance);
526 EXPECT_NEAR(cloud_out.channels[2].values[i], scan.ranges[i], tolerance);
527 EXPECT_NEAR(cloud_out.channels[3].values[i], (
float)i * scan.time_increment, tolerance);
532 if ((max_angle - min_angle) / angle_increment > 0.0)
544 double tolerance = 1e-12;
547 double min_angle = -M_PI/2;
548 double max_angle = M_PI/2;
549 double angle_increment = M_PI/180;
552 double intensity = 1.0;
557 std::vector<double> ranges, intensities, min_angles, max_angles, angle_increments;
558 std::vector<ros::Duration> increment_times, scan_times;
560 rostest::Permuter permuter;
562 ranges.push_back(-1.0);
563 ranges.push_back(1.0);
564 ranges.push_back(2.0);
565 ranges.push_back(3.0);
566 ranges.push_back(4.0);
567 ranges.push_back(5.0);
568 ranges.push_back(100.0);
569 permuter.addOptionSet(ranges, &range);
571 intensities.push_back(1.0);
572 intensities.push_back(2.0);
573 intensities.push_back(3.0);
574 intensities.push_back(4.0);
575 intensities.push_back(5.0);
576 permuter.addOptionSet(intensities, &intensity);
578 min_angles.push_back(-M_PI);
579 min_angles.push_back(-M_PI/1.5);
580 min_angles.push_back(-M_PI/2);
581 min_angles.push_back(-M_PI/4);
582 min_angles.push_back(-M_PI/8);
585 max_angles.push_back(M_PI);
586 max_angles.push_back(M_PI/1.5);
587 max_angles.push_back(M_PI/2);
588 max_angles.push_back(M_PI/4);
589 max_angles.push_back(M_PI/8);
591 permuter.addOptionSet(min_angles, &min_angle);
592 permuter.addOptionSet(max_angles, &max_angle);
594 angle_increments.push_back(-M_PI/180);
595 angle_increments.push_back(M_PI/180);
596 angle_increments.push_back(M_PI/360);
597 angle_increments.push_back(M_PI/720);
598 permuter.addOptionSet(angle_increments, &angle_increment);
603 permuter.addOptionSet(scan_times, &scan_time);
605 while (permuter.step())
610 sensor_msgs::LaserScan scan =
build_constant_scan(range, intensity, min_angle, max_angle, angle_increment, scan_time);
611 scan.header.frame_id =
"laser_frame";
613 sensor_msgs::PointCloud2 cloud_out;
615 EXPECT_EQ(cloud_out.fields.size(), (
unsigned int)3);
617 EXPECT_EQ(cloud_out.fields.size(), (
unsigned int)3);
619 EXPECT_EQ(cloud_out.fields.size(), (
unsigned int)4);
621 EXPECT_EQ(cloud_out.fields.size(), (
unsigned int)4);
623 EXPECT_EQ(cloud_out.fields.size(), (
unsigned int)4);
625 EXPECT_EQ(cloud_out.fields.size(), (
unsigned int)4);
628 EXPECT_EQ(cloud_out.fields.size(), (
unsigned int)5);
630 EXPECT_EQ(cloud_out.fields.size(), (
unsigned int)5);
632 EXPECT_EQ(cloud_out.fields.size(), (
unsigned int)5);
634 EXPECT_EQ(cloud_out.fields.size(), (
unsigned int)5);
637 EXPECT_EQ(cloud_out.fields.size(), (
unsigned int)6);
639 EXPECT_EQ(cloud_out.fields.size(), (
unsigned int)6);
642 EXPECT_EQ(cloud_out.fields.size(), (
unsigned int)7);
644 EXPECT_EQ(cloud_out.fields.size(), (
unsigned int)7);
646 EXPECT_EQ(cloud_out.is_dense,
false);
648 unsigned int valid_points = 0;
649 for (
unsigned int i = 0; i < scan.ranges.size(); i++)
652 EXPECT_EQ(valid_points, cloud_out.width);
654 uint32_t x_offset = 0;
655 uint32_t y_offset = 0;
656 uint32_t z_offset = 0;
657 uint32_t intensity_offset = 0;
658 uint32_t index_offset = 0;
659 uint32_t distance_offset = 0;
660 uint32_t stamps_offset = 0;
661 for (std::vector<sensor_msgs::PointField>::iterator
f = cloud_out.fields.begin();
f != cloud_out.fields.end();
f++)
663 if (
f->name ==
"x") x_offset =
f->offset;
664 if (
f->name ==
"y") y_offset =
f->offset;
665 if (
f->name ==
"z") z_offset =
f->offset;
666 if (
f->name ==
"intensity") intensity_offset =
f->offset;
667 if (
f->name ==
"index") index_offset =
f->offset;
668 if (
f->name ==
"distances") distance_offset =
f->offset;
669 if (
f->name ==
"stamps") stamps_offset =
f->offset;
672 for (
unsigned int i = 0; i < cloud_out.width; i++)
674 EXPECT_NEAR(*(
float*)&cloud_out.data[i*cloud_out.point_step + x_offset] , (
float)((
double)(scan.ranges[i]) * cos((
double)(scan.angle_min) + i * (
double)(scan.angle_increment))), tolerance);
675 EXPECT_NEAR(*(
float*)&cloud_out.data[i*cloud_out.point_step + y_offset] , (
float)((
double)(scan.ranges[i]) * sin((
double)(scan.angle_min) + i * (
double)(scan.angle_increment))), tolerance);
676 EXPECT_NEAR(*(
float*)&cloud_out.data[i*cloud_out.point_step + z_offset] , 0, tolerance);
677 EXPECT_NEAR(*(
float*)&cloud_out.data[i*cloud_out.point_step + intensity_offset] , scan.intensities[i], tolerance);
678 EXPECT_NEAR(*(uint32_t*)&cloud_out.data[i*cloud_out.point_step + index_offset], i, tolerance);
679 EXPECT_NEAR(*(
float*)&cloud_out.data[i*cloud_out.point_step + distance_offset], scan.ranges[i], tolerance);
680 EXPECT_NEAR(*(
float*)&cloud_out.data[i*cloud_out.point_step + stamps_offset], (
float)i * scan.time_increment, tolerance);
686 if ((max_angle - min_angle) / angle_increment > 0.0)
694 int main(
int argc,
char **argv){
696 testing::InitGoogleTest(&argc, argv);
697 return RUN_ALL_TESTS();
void projectLaser(const sensor_msgs::LaserScan &scan_in, sensor_msgs::PointCloud &cloud_out, double range_cutoff=-1.0, int channel_options=channel_option::Default)
Project a sensor_msgs::LaserScan into a sensor_msgs::PointCloud.
A Class to Project Laser Scan.
sensor_msgs::LaserScan build_constant_scan(double range, double intensity, double ang_min, double ang_max, double ang_increment, ros::Duration scan_time)
TEST(laser_geometry, projectLaser2)
#define PROJECTION_TEST_RANGE_MIN
#define PROJECTION_TEST_RANGE_MAX
const boost::numeric::ublas::matrix< double > & getUnitVectors(double angle_min, double angle_max, double angle_increment, unsigned int length)
void test_getUnitVectors(double angle_min, double angle_max, double angle_increment, unsigned int length)
Enable "intensities" channel.
TFSIMD_FORCE_INLINE tfScalar length(const Quaternion &q)
Enable "distances" channel.
void transformLaserScanToPointCloud(const std::string &target_frame, const sensor_msgs::LaserScan &scan_in, sensor_msgs::PointCloud &cloud_out, tf::Transformer &tf, double range_cutoff, int channel_options=channel_option::Default)
Transform a sensor_msgs::LaserScan into a sensor_msgs::PointCloud in target frame.
def shortest_angular_distance(from_angle, to_angle)
int main(int argc, char **argv)