polygon_filter.cpp
Go to the documentation of this file.
1 /*
2  * Software License Agreement (BSD License)
3  *
4  * Robot Operating System code by Eurotec B.V.
5  * Copyright (c) 2020, Eurotec B.V.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * 1. Redistributions of source code must retain the above
13  * copyright notice, this list of conditions and the following
14  * disclaimer.
15  *
16  * 2. Redistributions in binary form must reproduce the above
17  * copyright notice, this list of conditions and the following
18  * disclaimer in the documentation and/or other materials provided
19  * with the distribution.
20  *
21  * 3. Neither the name of the copyright holder nor the names of its
22  * contributors may be used to endorse or promote products derived
23  * from this software without specific prior written permission.
24  *
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
27  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
30  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
31  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
32  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
33  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
34  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
35  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
36  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37  *
38  *
39  *
40  * polygon_filter.cpp
41  */
42 
44 #include <ros/ros.h>
45 #include <dynamic_reconfigure/server.h>
46 #include <laser_filters/PolygonFilterConfig.h>
47 #include <geometry_msgs/PolygonStamped.h>
48 #include <cstdio> // for EOF
49 #include <string>
50 #include <sstream>
51 #include <vector>
52 
54 inline double sign0(double x)
55 {
56  return x < 0.0 ? -1.0 : (x > 0.0 ? 1.0 : 0.0);
57 }
58 
59 void padPolygon(geometry_msgs::Polygon& polygon, double padding)
60 {
61  // pad polygon in place
62  for (unsigned int i = 0; i < polygon.points.size(); i++)
63  {
64  geometry_msgs::Point32& pt = polygon.points[ i ];
65  pt.x += sign0(pt.x) * padding;
66  pt.y += sign0(pt.y) * padding;
67  }
68 }
69 
70 double getNumberFromXMLRPC(XmlRpc::XmlRpcValue& value, const std::string& full_param_name)
71 {
72  // Make sure that the value we're looking at is either a double or an int.
74  {
75  std::string& value_string = value;
76  ROS_FATAL("Values in the polygon specification (param %s) must be numbers. Found value %s.",
77  full_param_name.c_str(), value_string.c_str());
78  throw std::runtime_error("Values in the polygon specification must be numbers");
79  }
80  return value.getType() == XmlRpc::XmlRpcValue::TypeInt ? (int)(value) : (double)(value);
81 }
82 
83 geometry_msgs::Polygon makePolygonFromXMLRPC(const XmlRpc::XmlRpcValue& polygon_xmlrpc,
84  const std::string& full_param_name)
85 {
86  // Make sure we have an array of at least 3 elements.
87  if (polygon_xmlrpc.getType() != XmlRpc::XmlRpcValue::TypeArray ||
88  polygon_xmlrpc.size() > 0 && polygon_xmlrpc.size() < 3)
89  {
90  ROS_FATAL("The polygon (parameter %s) must be specified as nested list on the parameter server with at least "
91  "3 points eg: [[x1, y1], [x2, y2], ..., [xn, yn]]",
92  full_param_name.c_str());
93 
94  throw std::runtime_error("The polygon must be specified as nested list on the parameter server with at least "
95  "3 points eg: [[x1, y1], [x2, y2], ..., [xn, yn]]");
96  }
97  geometry_msgs::Polygon polygon;
98  geometry_msgs::Point32 pt;
99 
100  for (int i = 0; i < polygon_xmlrpc.size(); ++i)
101  {
102  // Make sure each element of the list is an array of size 2. (x and y coordinates)
103  XmlRpc::XmlRpcValue point = polygon_xmlrpc[i];
104  if (point.getType() != XmlRpc::XmlRpcValue::TypeArray || point.size() != 2)
105  {
106  ROS_FATAL("The polygon (parameter %s) must be specified as list of lists on the parameter server eg: "
107  "[[x1, y1], [x2, y2], ..., [xn, yn]], but this spec is not of that form.",
108  full_param_name.c_str());
109  throw std::runtime_error("The polygon must be specified as list of lists on the parameter server eg: "
110  "[[x1, y1], [x2, y2], ..., [xn, yn]], but this spec is not of that form");
111  }
112 
113  pt.x = getNumberFromXMLRPC(point[0], full_param_name);
114  pt.y = getNumberFromXMLRPC(point[1], full_param_name);
115 
116  polygon.points.push_back(pt);
117  }
118  return polygon;
119 }
120 
121 std::vector<std::vector<float> > parseVVF(const std::string& input, std::string& error_return)
122 { // Source: https://github.com/ros-planning/navigation/blob/melodic-devel/costmap_2d/src/array_parser.cpp
123  std::vector<std::vector<float> > result;
124 
125  std::stringstream input_ss(input);
126  int depth = 0;
127  std::vector<float> current_vector;
128  while (!!input_ss && !input_ss.eof())
129  {
130  switch (input_ss.peek())
131  {
132  case EOF:
133  break;
134  case '[':
135  depth++;
136  if (depth > 2)
137  {
138  error_return = "Array depth greater than 2";
139  return result;
140  }
141  input_ss.get();
142  current_vector.clear();
143  break;
144  case ']':
145  depth--;
146  if (depth < 0)
147  {
148  error_return = "More close ] than open [";
149  return result;
150  }
151  input_ss.get();
152  if (depth == 1)
153  {
154  result.push_back(current_vector);
155  }
156  break;
157  case ',':
158  case ' ':
159  case '\t':
160  input_ss.get();
161  break;
162  default: // All other characters should be part of the numbers.
163  if (depth != 2)
164  {
165  std::stringstream err_ss;
166  err_ss << "Numbers at depth other than 2. Char was '" << char(input_ss.peek()) << "'.";
167  error_return = err_ss.str();
168  return result;
169  }
170  float value;
171  input_ss >> value;
172  if (!!input_ss)
173  {
174  current_vector.push_back(value);
175  }
176  break;
177  }
178  }
179 
180  if (depth != 0)
181  {
182  error_return = "Unterminated vector string.";
183  }
184  else
185  {
186  error_return = "";
187  }
188 
189  return result;
190 }
191 
192 geometry_msgs::Polygon makePolygonFromString(const std::string& polygon_string, const geometry_msgs::Polygon& last_polygon)
193 {
194  std::string error;
195  std::vector<std::vector<float> > vvf = parseVVF(polygon_string, error);
196 
197  if (error != "")
198  {
199  ROS_ERROR("Error parsing polygon parameter: '%s'", error.c_str());
200  ROS_ERROR(" Polygon string was '%s'.", polygon_string.c_str());
201  return last_polygon;
202  }
203 
204  geometry_msgs::Polygon polygon;
205  geometry_msgs::Point32 point;
206 
207  // convert vvf into points.
208  if (vvf.size() < 3 && vvf.size() > 0)
209  {
210  ROS_WARN("You must specify at least three points for the robot polygon");
211  return last_polygon;
212  }
213 
214  for (unsigned int i = 0; i < vvf.size(); i++)
215  {
216  if (vvf[ i ].size() == 2)
217  {
218  point.x = vvf[ i ][ 0 ];
219  point.y = vvf[ i ][ 1 ];
220  point.z = 0;
221  polygon.points.push_back(point);
222  }
223  else
224  {
225  ROS_ERROR("Points in the polygon specification must be pairs of numbers. Found a point with %d numbers.",
226  int(vvf[ i ].size()));
227  return last_polygon;
228  }
229  }
230 
231  return polygon;
232 }
233 
234 std::string polygonToString(geometry_msgs::Polygon polygon)
235 {
236  std::string polygon_string = "[";
237  bool first = true;
238  for (auto point : polygon.points) {
239  if (!first) {
240  polygon_string += ", ";
241  }
242  first = false;
243  polygon_string += "[" + std::to_string(point.x) + ", " + std::to_string(point.y) + "]";
244  }
245  polygon_string += "]";
246  return polygon_string;
247 }
248 
249 namespace laser_filters{
250 
252 {
253  XmlRpc::XmlRpcValue polygon_xmlrpc;
254  std::string polygon_string;
255  PolygonFilterConfig param_config;
256 
257  ros::NodeHandle private_nh("~" + getName());
258  dyn_server_.reset(new dynamic_reconfigure::Server<laser_filters::PolygonFilterConfig>(own_mutex_, private_nh));
259  dynamic_reconfigure::Server<laser_filters::PolygonFilterConfig>::CallbackType f;
260  f = [this](auto& config, auto level){ reconfigureCB(config, level); };
261  dyn_server_->setCallback(f);
262 
263  bool polygon_set = getParam("polygon", polygon_xmlrpc);
264  bool polygon_frame_set = getParam("polygon_frame", polygon_frame_);
265  bool invert_set = getParam("invert", invert_filter_);
266  polygon_ = makePolygonFromXMLRPC(polygon_xmlrpc, "polygon");
267 
268  double polygon_padding = 0;
269  getParam("polygon_padding", polygon_padding);
270 
271  polygon_string = polygonToString(polygon_);
272  param_config.polygon = polygon_string;
273  param_config.polygon_padding = polygon_padding;
274  param_config.invert = invert_filter_;
275  dyn_server_->updateConfig(param_config);
276 
277  polygon_pub_ = private_nh.advertise<geometry_msgs::PolygonStamped>("polygon", 1, true);
278  is_polygon_published_ = false;
279 
280  if (!polygon_frame_set)
281  {
282  ROS_ERROR("polygon_frame is not set!");
283  }
284  if (!polygon_set)
285  {
286  ROS_ERROR("polygon is not set!");
287  }
288  if (!invert_set)
289  {
290  ROS_INFO("invert filter not set, assuming false");
291  invert_filter_ = false;
292  }
293 
294  return polygon_frame_set && polygon_set;
295 }
296 
297 // See https://web.cs.ucdavis.edu/~okreylos/TAship/Spring2000/PointInPolygon.html
299  int i, j;
300  bool c = false;
301 
302  for (i = 0, j = polygon_.points.size() - 1; i < polygon_.points.size(); j = i++)
303  {
304  if ((polygon_.points.at(i).y > point.y() != (polygon_.points.at(j).y > point.y()) &&
305  (point.x() < (polygon_.points[j].x - polygon_.points[i].x) * (point.y() - polygon_.points[i].y) /
306  (polygon_.points[j].y - polygon_.points[i].y) +
307  polygon_.points[i].x)))
308  c = !c;
309  }
310  return c;
311 }
312 
314 {
316  {
317  geometry_msgs::PolygonStamped polygon_stamped;
318  polygon_stamped.header.frame_id = polygon_frame_;
319  polygon_stamped.header.stamp = ros::Time::now();
320  polygon_stamped.polygon = polygon_;
321  polygon_pub_.publish(polygon_stamped);
322  is_polygon_published_ = true;
323  }
324 }
325 
326 void LaserScanPolygonFilterBase::reconfigureCB(laser_filters::PolygonFilterConfig& config, uint32_t level)
327 {
328  invert_filter_ = config.invert;
329  polygon_ = makePolygonFromString(config.polygon, polygon_);
330  padPolygon(polygon_, config.polygon_padding);
331  is_polygon_published_ = false;
332 }
333 
334 bool LaserScanPolygonFilter::update(const sensor_msgs::LaserScan& input_scan,
335  sensor_msgs::LaserScan& output_scan)
336 {
337  boost::recursive_mutex::scoped_lock lock(own_mutex_);
338 
339  publishPolygon();
340 
341  output_scan = input_scan;
342 
343  sensor_msgs::PointCloud2 laser_cloud;
344 
345  std::string error_msg;
346 
347  bool success = tf_.waitForTransform(
348  polygon_frame_, input_scan.header.frame_id,
349  input_scan.header.stamp + ros::Duration().fromSec(input_scan.ranges.size() * input_scan.time_increment),
350  ros::Duration(1.0), ros::Duration(0.01), &error_msg);
351  if (!success)
352  {
353  ROS_WARN("Could not get transform, ignoring laser scan! %s", error_msg.c_str());
354  return false;
355  }
356 
357  try
358  {
359  projector_.transformLaserScanToPointCloud(polygon_frame_, input_scan, laser_cloud, tf_);
360  }
361  catch (tf::TransformException& ex)
362  {
363  ROS_INFO_THROTTLE(.3, "Ignoring Scan: Waiting for TF");
364  return false;
365  }
366  const int i_idx_c = sensor_msgs::getPointCloud2FieldIndex(laser_cloud, "index");
367  const int x_idx_c = sensor_msgs::getPointCloud2FieldIndex(laser_cloud, "x");
368  const int y_idx_c = sensor_msgs::getPointCloud2FieldIndex(laser_cloud, "y");
369  const int z_idx_c = sensor_msgs::getPointCloud2FieldIndex(laser_cloud, "z");
370 
371  if (i_idx_c == -1 || x_idx_c == -1 || y_idx_c == -1 || z_idx_c == -1)
372  {
373  ROS_INFO_THROTTLE(.3, "x, y, z and index fields are required, skipping scan");
374  }
375 
376  const int i_idx_offset = laser_cloud.fields[i_idx_c].offset;
377  const int x_idx_offset = laser_cloud.fields[x_idx_c].offset;
378  const int y_idx_offset = laser_cloud.fields[y_idx_c].offset;
379  const int z_idx_offset = laser_cloud.fields[z_idx_c].offset;
380 
381  const int pstep = laser_cloud.point_step;
382  const long int pcount = laser_cloud.width * laser_cloud.height;
383  const long int limit = pstep * pcount;
384 
385  int i_idx, x_idx, y_idx, z_idx;
386  for (i_idx = i_idx_offset, x_idx = x_idx_offset, y_idx = y_idx_offset, z_idx = z_idx_offset;
387 
388  x_idx < limit;
389 
390  i_idx += pstep, x_idx += pstep, y_idx += pstep, z_idx += pstep)
391  {
392  // TODO works only for float data types and with an index field
393  // I'm working on it, see https://github.com/ros/common_msgs/pull/78
394  float x = *((float*)(&laser_cloud.data[x_idx]));
395  float y = *((float*)(&laser_cloud.data[y_idx]));
396  float z = *((float*)(&laser_cloud.data[z_idx]));
397  int index = *((int*)(&laser_cloud.data[i_idx]));
398 
399  tf::Point point(x, y, z);
400 
401  if (!invert_filter_)
402  {
403  if (inPolygon(point))
404  {
405  output_scan.ranges[index] = std::numeric_limits<float>::quiet_NaN();
406  }
407  }
408  else
409  {
410  if (!inPolygon(point))
411  {
412  output_scan.ranges[index] = std::numeric_limits<float>::quiet_NaN();
413  }
414  }
415  }
416 
417  return true;
418 }
419 
421 {
422  is_polygon_transformed_ = false;
423 
424  transform_timeout_ = 5; // Default
425  getParam("transform_timeout", transform_timeout_);
426 
428 }
429 
430 void StaticLaserScanPolygonFilter::checkCoSineMap(const sensor_msgs::LaserScan& scan_in)
431 {
432  size_t n_pts = scan_in.ranges.size();
433 
434  if (
435  co_sine_map_.rows() != (int)n_pts ||
436  co_sine_map_angle_min_ != scan_in.angle_min ||
437  co_sine_map_angle_max_ != scan_in.angle_max
438  ) {
439  ROS_DEBUG_NAMED("StaticLaserScanPolygonFilter", "No precomputed map given. Computing one.");
440  co_sine_map_ = Eigen::ArrayXXd(n_pts, 2);
441  co_sine_map_angle_min_ = scan_in.angle_min;
442  co_sine_map_angle_max_ = scan_in.angle_max;
443 
444  // Spherical->Cartesian projection
445  for (size_t i = 0; i < n_pts; ++i)
446  {
447  co_sine_map_(i, 0) = cos(scan_in.angle_min + (double) i * scan_in.angle_increment);
448  co_sine_map_(i, 1) = sin(scan_in.angle_min + (double) i * scan_in.angle_increment);
449  }
450  }
451 }
452 
453 // Note: This implementation transforms the polygon relative to the laser.
454 // It does this lazily and only once. This has the advantage that the check if points fall inside the polygon is fast
455 // as the transform is not needed there. Furthermore, it means that the filter chain node
456 // does not need to be continuously subscribed to the transform topic, which significantly reduces CPU load.
457 // A pre-requisite for this to work is that the transform is static, i.e. the position and orientation of the laser with regard to
458 // the base of the robot does not change.
459 bool StaticLaserScanPolygonFilter::update(const sensor_msgs::LaserScan& input_scan,
460  sensor_msgs::LaserScan& output_scan)
461 {
462  boost::recursive_mutex::scoped_lock lock(own_mutex_);
463 
464  publishPolygon();
465 
467  tf::TransformListener transform_listener;
468 
469  std::string error_msg;
471  "StaticLaserScanPolygonFilter", "waitForTransform %s -> %s",
472  polygon_frame_.c_str(), input_scan.header.frame_id.c_str()
473  );
474  bool success = transform_listener.waitForTransform(
475  input_scan.header.frame_id, polygon_frame_,
476  ros::Time(), // No restrictions on transform time. It is static.
478  ros::Duration(0), // This setting has no effect
479  &error_msg
480  );
481 
482  if (!success)
483  {
485  1, "StaticLaserScanPolygonFilter",
486  "Could not get transform, ignoring laser scan! %s", error_msg.c_str()
487  );
488  return false;
489  }
490  else
491  {
492  ROS_INFO_NAMED("StaticLaserScanPolygonFilter", "Obtained transform");
493  }
494 
495  try {
496  // Transform each point of polygon. This includes multiple type convertions because of transformPoint API requiring Stamped<Point>
497  // which does not in turn expose coordinate values
498  for (int i = 0; i < polygon_.points.size(); ++i)
499  {
500  tf::Point point(polygon_.points[i].x, polygon_.points[i].y, 0);
501  tf::Stamped<tf::Point> point_stamped(point, ros::Time(), polygon_frame_);
502  tf::Stamped<tf::Point> point_stamped_new;
503  transform_listener.transformPoint(input_scan.header.frame_id, point_stamped, point_stamped_new);
504  geometry_msgs::PointStamped result_point;
505  tf::pointStampedTFToMsg(point_stamped_new, result_point);
506  polygon_.points[i].x = result_point.point.x;
507  polygon_.points[i].y = result_point.point.y;
508  }
509 
511  }
512  catch (tf::TransformException& ex)
513  {
514  ROS_WARN_THROTTLE_NAMED(1, "StaticLaserScanPolygonFilter", "Exception while transforming polygon");
515  return false;
516  }
517  }
518 
519  output_scan = input_scan;
520  checkCoSineMap(input_scan);
521 
522  size_t i = 0;
523  size_t i_max = input_scan.ranges.size();
524 
525  while (i < i_max)
526  {
527  float range = input_scan.ranges[i];
528 
529  float x = co_sine_map_(i, 0) * range;
530  float y = co_sine_map_(i, 1) * range;
531  tf::Point point(x, y, 0);
532 
533  if (invert_filter_ != inPolygon(point))
534  {
535  output_scan.ranges[i] = std::numeric_limits<float>::quiet_NaN();
536  }
537 
538  ++i;
539  }
540 
541  return true;
542 }
543 
544 void StaticLaserScanPolygonFilter::reconfigureCB(laser_filters::PolygonFilterConfig& config, uint32_t level)
545 {
546  is_polygon_transformed_ = false;
548 }
549 }
laser_filters::LaserScanPolygonFilterBase::publishPolygon
void publishPolygon()
Definition: polygon_filter.cpp:313
XmlRpc::XmlRpcValue::size
int size() const
laser_filters::LaserScanPolygonFilterBase::invert_filter_
bool invert_filter_
Definition: polygon_filter.h:78
sign0
double sign0(double x)
Same as sign(x) but returns 0 if x is 0.
Definition: polygon_filter.cpp:54
DurationBase< Duration >::fromSec
Duration & fromSec(double t)
sensor_msgs::getPointCloud2FieldIndex
static int getPointCloud2FieldIndex(const sensor_msgs::PointCloud2 &cloud, const std::string &field_name)
laser_filters::StaticLaserScanPolygonFilter::co_sine_map_angle_min_
float co_sine_map_angle_min_
Definition: polygon_filter.h:119
tf::pointStampedTFToMsg
static void pointStampedTFToMsg(const Stamped< Point > &bt, geometry_msgs::PointStamped &msg)
parseVVF
std::vector< std::vector< float > > parseVVF(const std::string &input, std::string &error_return)
Definition: polygon_filter.cpp:121
ros.h
laser_filters::StaticLaserScanPolygonFilter::checkCoSineMap
void checkCoSineMap(const sensor_msgs::LaserScan &input_scan)
Definition: polygon_filter.cpp:430
laser_filters::LaserScanPolygonFilterBase::own_mutex_
boost::recursive_mutex own_mutex_
Definition: polygon_filter.h:73
laser_geometry::LaserProjection::transformLaserScanToPointCloud
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)
XmlRpc::XmlRpcValue::TypeInt
TypeInt
tf::TransformListener::transformPoint
void transformPoint(const std::string &target_frame, const geometry_msgs::PointStamped &stamped_in, geometry_msgs::PointStamped &stamped_out) const
laser_filters::LaserScanPolygonFilterBase::dyn_server_
std::shared_ptr< dynamic_reconfigure::Server< laser_filters::PolygonFilterConfig > > dyn_server_
Definition: polygon_filter.h:80
polygonToString
std::string polygonToString(geometry_msgs::Polygon polygon)
Definition: polygon_filter.cpp:234
laser_filters::StaticLaserScanPolygonFilter::is_polygon_transformed_
bool is_polygon_transformed_
Definition: polygon_filter.h:121
ros::Publisher::publish
void publish(const boost::shared_ptr< M > &message) const
ros::NodeHandle::advertise
Publisher advertise(AdvertiseOptions &ops)
laser_filters::LaserScanPolygonFilter::projector_
laser_geometry::LaserProjection projector_
Definition: polygon_filter.h:96
f
f
laser_filters::StaticLaserScanPolygonFilter::co_sine_map_angle_max_
float co_sine_map_angle_max_
Definition: polygon_filter.h:120
laser_filters::StaticLaserScanPolygonFilter::reconfigureCB
void reconfigureCB(laser_filters::PolygonFilterConfig &config, uint32_t level) override
Definition: polygon_filter.cpp:544
tf::Stamped
makePolygonFromString
geometry_msgs::Polygon makePolygonFromString(const std::string &polygon_string, const geometry_msgs::Polygon &last_polygon)
Definition: polygon_filter.cpp:192
filters::FilterBase< sensor_msgs::LaserScan >::getParam
bool getParam(const std::string &name, bool &value) const
XmlRpc::XmlRpcValue::TypeDouble
TypeDouble
tf::Point
tf::Vector3 Point
ROS_INFO_NAMED
#define ROS_INFO_NAMED(name,...)
laser_filters::LaserScanPolygonFilterBase::polygon_pub_
ros::Publisher polygon_pub_
Definition: polygon_filter.h:72
ROS_DEBUG_NAMED
#define ROS_DEBUG_NAMED(name,...)
laser_filters::StaticLaserScanPolygonFilter::update
bool update(const sensor_msgs::LaserScan &input_scan, sensor_msgs::LaserScan &filtered_scan) override
Definition: polygon_filter.cpp:459
ROS_WARN
#define ROS_WARN(...)
makePolygonFromXMLRPC
geometry_msgs::Polygon makePolygonFromXMLRPC(const XmlRpc::XmlRpcValue &polygon_xmlrpc, const std::string &full_param_name)
Definition: polygon_filter.cpp:83
tf::Transformer::waitForTransform
bool waitForTransform(const std::string &target_frame, const ros::Time &target_time, const std::string &source_frame, const ros::Time &source_time, const std::string &fixed_frame, const ros::Duration &timeout, const ros::Duration &polling_sleep_duration=ros::Duration(0.01), std::string *error_msg=NULL) const
laser_filters::LaserScanPolygonFilterBase::polygon_
geometry_msgs::Polygon polygon_
Definition: polygon_filter.h:76
getNumberFromXMLRPC
double getNumberFromXMLRPC(XmlRpc::XmlRpcValue &value, const std::string &full_param_name)
Definition: polygon_filter.cpp:70
laser_filters::LaserScanPolygonFilterBase::configure
virtual bool configure()
Definition: polygon_filter.cpp:251
XmlRpc::XmlRpcValue::getType
const Type & getType() const
ROS_WARN_THROTTLE_NAMED
#define ROS_WARN_THROTTLE_NAMED(period, name,...)
ROS_FATAL
#define ROS_FATAL(...)
padPolygon
void padPolygon(geometry_msgs::Polygon &polygon, double padding)
Definition: polygon_filter.cpp:59
XmlRpc::XmlRpcValue::TypeArray
TypeArray
laser_filters::StaticLaserScanPolygonFilter::transform_timeout_
double transform_timeout_
Definition: polygon_filter.h:116
laser_filters::LaserScanPolygonFilterBase::reconfigureCB
virtual void reconfigureCB(laser_filters::PolygonFilterConfig &config, uint32_t level)
Definition: polygon_filter.cpp:326
filters::FilterBase< sensor_msgs::LaserScan >::getName
const std::string & getName() const
ros::Time
laser_filters::LaserScanPolygonFilter::tf_
tf::TransformListener tf_
Definition: polygon_filter.h:98
ROS_ERROR
#define ROS_ERROR(...)
tf::TransformListener
laser_filters::StaticLaserScanPolygonFilter::configure
bool configure() override
Definition: polygon_filter.cpp:420
laser_filters::LaserScanPolygonFilterBase::is_polygon_published_
bool is_polygon_published_
Definition: polygon_filter.h:79
laser_filters::LaserScanPolygonFilter::update
bool update(const sensor_msgs::LaserScan &input_scan, sensor_msgs::LaserScan &filtered_scan) override
Definition: polygon_filter.cpp:334
tf2::TransformException
ROS_INFO
#define ROS_INFO(...)
laser_filters
LaserScanMaskFilter removes points on directions defined in a mask from a laser scan.
Definition: angular_bounds_filter.h:43
laser_filters::LaserScanPolygonFilterBase::inPolygon
bool inPolygon(tf::Point &point) const
Definition: polygon_filter.cpp:298
ros::Duration
XmlRpc::XmlRpcValue
ros::NodeHandle
ros::Time::now
static Time now()
laser_filters::StaticLaserScanPolygonFilter::co_sine_map_
Eigen::ArrayXXd co_sine_map_
Definition: polygon_filter.h:118
ROS_INFO_THROTTLE
#define ROS_INFO_THROTTLE(period,...)
polygon_filter.h
laser_filters::LaserScanPolygonFilterBase::polygon_frame_
std::string polygon_frame_
Definition: polygon_filter.h:75


laser_filters
Author(s): Tully Foote
autogenerated on Mon Apr 3 2023 02:51:57