pcdfilter_pa_ros_filter.cpp
Go to the documentation of this file.
1 /******************************************************************************
2 * *
3 * pcdfilter_pa_ros_filter.cpp *
4 * =========================== *
5 * *
6 *******************************************************************************
7 * *
8 * github repository *
9 * https://github.com/TUC-ProAut/ros_pcdfilter *
10 * *
11 * Chair of Automation Technology, Technische Universität Chemnitz *
12 * https://www.tu-chemnitz.de/etit/proaut *
13 * *
14 *******************************************************************************
15 * *
16 * New BSD License *
17 * *
18 * Copyright (c) 2015-2018, Peter Weissig, Technische Universität Chemnitz *
19 * All rights reserved. *
20 * *
21 * Redistribution and use in source and binary forms, with or without *
22 * modification, are permitted provided that the following conditions are met: *
23 * * Redistributions of source code must retain the above copyright *
24 * notice, this list of conditions and the following disclaimer. *
25 * * Redistributions in binary form must reproduce the above copyright *
26 * notice, this list of conditions and the following disclaimer in the *
27 * documentation and/or other materials provided with the distribution. *
28 * * Neither the name of the Technische Universität Chemnitz nor the *
29 * names of its contributors may be used to endorse or promote products *
30 * derived from this software without specific prior written permission. *
31 * *
32 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" *
33 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE *
34 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE *
35 * ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY *
36 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES *
37 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR *
38 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER *
39 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT *
40 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY *
41 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH *
42 * DAMAGE. *
43 * *
44 ******************************************************************************/
45 
46 // local headers
48 
49 // standard headers
50 #include <sstream>
51 
52 //********************************************************************************
53 //**************************[cPcdFilterPaRosFilter]*******************************
54 //********************************************************************************
55 
56 //**************************[cPcdFilterPaRosFilter]*******************************
58 
59  reset();
60 }
61 
62 //**************************[cPcdFilterPaRosFilter]*******************************
64  const cPcdFilterPaRosFilter &other) {
65 
66  *this = other;
67 }
68 
69 //**************************[operator = ]**************************************
71  const cPcdFilterPaRosFilter &other) {
72 
73  inverse_ = other.inverse_ ;
74  type_ = other.type_ ;
75  required_ = other.required_ ;
76 
77  for (int i = 0; i < COUNT_PARAMETER; i++) {
78  parameter_[i] = other.parameter_[i];
79  }
80 
81  for (int i = 0; i < COUNT_FRAME; i++) {
82  frame_[i] = other.frame_[i] ;
83  offset_[i] = other.offset_[i] ;
84  }
85 
86  comment_ = other.comment_ ;
87 
88  return *this;
89 }
90 
91 
92 //**************************[fromString]***************************************
93 bool cPcdFilterPaRosFilter::fromString(const std::string &filter) {
94 
95  reset();
96 
97  int pos = 0;
98  std::string s;
99 
100  _skipWhitespace(filter, pos);
101  inverse_ = _checkSymbol(filter,pos,'!');
102 
103  _skipWhitespace(filter,pos);
104  s = _getValue(filter, pos);
105  if (s == "cube") {
106  type_ = ftCUBE;
107  } else if (s == "sphere") {
108  type_ = ftSPHERE;
109  } else if (s == "block") {
110  type_ = ftBLOCK;
111  } else if (s == "cylinder") {
112  type_ = ftCYLINDER;
113  } else if (s == "link") {
114  type_ = ftLINK;
115  } else if (s == "cone") {
116  type_ = ftCONE;
117  } else {
118  return false;
119  }
120 
121  _skipWhitespace(filter,pos);
122  if (_checkSymbol(filter,pos,':')) {
123  required_ = true;
124  } else if (_checkSymbol(filter,pos,'?')) {
125  required_ = false;
126  } else {
127  return false;
128  }
129 
130 
131  for (int i = 0; ; i++) {
132  _skipWhitespace(filter,pos);
133  s = _getValue(filter, pos);
134  if (s == "") {
135  return false;
136  }
137  if (i >= COUNT_PARAMETER) { break;}
138  if (! _StrToFloat(s, parameter_[i])) { break;}
139  }
140 
141  for (int i = 0; i < COUNT_FRAME; i++) {
142  double d;
143  if (_StrToFloat(s, d)) {
144  return false;
145  }
146  frame_[i] = s;
147  _skipWhitespace(filter, pos);
148  s = _getValue(filter, pos);
149 
151  for (int j = 0; ; j++) {
152  if (! _StrToFloat(s, d)) {
153  if (j > 3) {
154  if (j < 7) {
155  q.setW(0);
156  }
157  q.normalize();
158  offset_[i].setRotation(q);
159  }
160  offset_[i] = offset_[i].inverse();
161  break;
162  }
163  if (j >= 7) {
164  q.normalize();
165  offset_[i].setRotation(q);
166  offset_[i] = offset_[i].inverse();
167  return false;
168  } else {
169  _skipWhitespace(filter, pos);
170  s = _getValue(filter, pos);
171  }
172  switch (j) {
173  case 0: offset_[i].getOrigin().setX(d); break;
174  case 1: offset_[i].getOrigin().setY(d); break;
175  case 2: offset_[i].getOrigin().setZ(d); break;
176 
177  case 3: q.setX(d); break;
178  case 4: q.setY(d); break;
179  case 5: q.setZ(d); break;
180  case 6: q.setW(d); break;
181  }
182  }
183  if (s == "") {
184  break;
185  }
186  }
187 
188  comment_ = _getComment(filter);
189 
190  return isValid();
191 }
192 
193 //**************************[toString]*****************************************
194 std::string cPcdFilterPaRosFilter::toString() const {
195 
196  std::stringstream result;
197 
198  if (inverse_) {result << '!';}
199 
200  int param_count = 1;
201  int tf_count = 1;
202  switch (type_) {
203  case ftCUBE:
204  result << "cube";
205  break;
206  case ftSPHERE:
207  result << "sphere";
208  break;
209  case ftBLOCK:
210  result << "block";
211  param_count = 3;
212  break;
213  case ftCYLINDER:
214  result << "cylinder";
215  param_count = 2;
216  break;
217  case ftLINK:
218  result << "link";
219  param_count = 2;
220  tf_count = 2;
221  break;
222  case ftCONE:
223  result << "cone";
224  param_count = 2;
225  break;
226  case ftNONE:
227  result << "-";
228  param_count = 0;
229  tf_count = 0;
230  break;
231  default:
232  result << "error";
233  param_count = 0;
234  tf_count = 0;
235  break;
236  }
237 
238  if (required_) {
239  result << ':';
240  } else {
241  result << "?";
242  }
243 
244  if (param_count > COUNT_PARAMETER) { param_count = COUNT_PARAMETER;}
245  for (int i = 0; i < param_count; i++) {
246  result << ' ' << parameter_[i];
247  }
248 
249  if (tf_count > COUNT_FRAME) { tf_count = COUNT_FRAME;}
250  for (int i = 0; i < tf_count; i++) {
251  tf::Transform temp_offset = offset_[i].inverse();
252  result << ' ' << frame_[i];
253 
254  bool _x = false;
255  bool _y = false;
256  bool _z = false;
257  bool _q = false;
258  if (temp_offset.getOrigin().x() != 0) {
259  _x = true;
260  }
261  if (temp_offset.getOrigin().y() != 0) {
262  _x = _y = true;
263  }
264  if (temp_offset.getOrigin().z() != 0) {
265  _x = _y = _z = true;
266  }
267  if ((temp_offset.getRotation().x() != 0) ||
268  (temp_offset.getRotation().y() != 0) ||
269  (temp_offset.getRotation().z() != 0) ||
270  (temp_offset.getRotation().w() != 1)) {
271  _x = _y = _z = _q = true;
272  }
273 
274  if (_x) {
275  result << ' ' << _floatToStr(temp_offset.getOrigin().x());
276  }
277  if (_y) {
278  result << ' ' << _floatToStr(temp_offset.getOrigin().y());
279  }
280  if (_z) {
281  result << ' ' << _floatToStr(temp_offset.getOrigin().z());
282  }
283  if (_q) {
284  result << ' ' << _floatToStr(temp_offset.getRotation().x());
285  result << ' ' << _floatToStr(temp_offset.getRotation().y());
286  result << ' ' << _floatToStr(temp_offset.getRotation().z());
287  result << ' ' << _floatToStr(temp_offset.getRotation().w());
288  }
289  }
290 
291  if (comment_ != "") {
292  result << " #" << comment_;
293  }
294 
295  return result.str();
296 }
297 
298 //**************************[reset]********************************************
300 
301  inverse_ = false;
302  type_ = ftNONE;
303  required_ = true;
304  for (int i = 0; i < COUNT_FRAME; i++) {
305  frame_[i] = "";
306  offset_[i].setIdentity();
307  }
308  for (int i = 0; i < COUNT_PARAMETER; i++) {
309  parameter_[i] = 0;
310  }
311  comment_ = "";
312 }
313 
314 //**************************[isValid]******************************************
316 
317  return true;
318 }
319 
320 //**************************[_skipWhitespace]**********************************
321 bool cPcdFilterPaRosFilter::_skipWhitespace(const std::string &str, int &pos)
322  const {
323 
324  if (pos >= str.size()) {
325  return false;
326  }
327 
328  char c = str[pos];
329  if ((c != ' ') && (c != '\t')) {
330  return false;
331  }
332 
333  while (1) {
334  pos++;
335  if (pos >= str.size()) {
336  return false;
337  }
338 
339  char c = str[pos];
340  if ((c != ' ') && (c != '\t')) {
341  break;
342  }
343  }
344 
345  return true;
346 }
347 
348 //**************************[_checkSymbol]*************************************
349 bool cPcdFilterPaRosFilter::_checkSymbol(const std::string &str, int &pos,
350  const char symbol) const {
351 
352  if (pos >= str.size()) {
353  return false;
354  }
355 
356  if (str[pos] == symbol) {
357  pos++;
358  return true;
359  }
360 
361  return false;
362 }
363 
364 //**************************[_getValue]****************************************
365 std::string cPcdFilterPaRosFilter::_getValue(const std::string &str, int &pos)
366  const {
367 
368  int start = pos;
369 
370  while (1) {
371  if (pos >= str.size()) {
372  break;
373  }
374 
375  char c = str[pos];
376  if ((c == ' ') || (c == '\t') || (c == '#') || (c == ':') ||
377  (c == '?')) {
378  break;
379  }
380  pos++;
381  }
382 
383  if (pos <= start) {
384  return "";
385  } else {
386  return str.substr(start, pos - start);
387  }
388 }
389 
390 //**************************[_getComment]**************************************
391 std::string cPcdFilterPaRosFilter::_getComment(const std::string &str)
392  const {
393 
394  int pos = (int)str.find('#');
395  if (pos <= 0) {
396  return "";
397  }
398 
399  return str.substr(pos + 1);
400 }
401 
402 //**************************[_floatToStr]**************************************
403 std::string cPcdFilterPaRosFilter::_floatToStr(const double &value) const {
404 
405  std::stringstream ss;
406 
407  ss << value;
408  return ss.str();
409 }
410 
411 //**************************[_StrToFloat]**************************************
412 bool cPcdFilterPaRosFilter::_StrToFloat(const std::string &str,
413  double &value) const {
414 
415  std::stringstream ss;
416 
417  ss << str;
418  try {
419  ss >> value;
420  } catch (std::runtime_error &e) {
421  return false;
422  }
423  return ! ss.fail();
424 }
425 
426 //*****************************************************************************
427 //**************************[cPcdFilterPaRosFilters]***************************
428 //*****************************************************************************
429 
430 //**************************[cPcdFilterPaRosFilters]***************************
432 
433  tf_lookup_time_ = 0.2;
434 }
435 
436 //**************************[add]**********************************************
437 bool cPcdFilterPaRosFilters::add(std::string filter) {
438 
440 
441  bool result = f.fromString(filter);
442  last_filter_ = f;
443  if (result) {
444  filters_.push_back(f);
445  }
446 
447  return result;
448 }
449 
450 //**************************[clear]********************************************
452 
453  filters_.clear();
454 }
455 
456 //**************************[get]**********************************************
457 std::vector<std::string> cPcdFilterPaRosFilters::get() const {
458 
459  std::vector<std::string> result;
460  for (int i = 0; i < filters_.size(); i++) {
461  result.push_back(filters_[i].toString());
462  }
463  return result;
464 }
465 
466 //**************************[update]*******************************************
468  const tf::TransformListener &tf_listener,
469  const std::string base_frame, const ros::Time time,
470  std::vector<cPcdFilterPaFilter> &result) const {
471 
472  result.clear();
473 
474  // buffer for frame_id/tf pairs (to increase speed)
475  std::vector<std::pair<std::string, tf::Transform > > frames;
476 
477  ros::Time start_time = ros::Time::now();
478  // iterate over all filters
479  for (int i_filter = 0; i_filter < filters_.size(); i_filter++) {
480 
481  // check number of tfs (always 1 - except for "ftLink")
482  int tf_count = 0;
483  switch (filters_[i_filter].type_) {
488  tf_count = 1;
489  break;
491  tf_count = 2;
492  break;
494  tf_count = 2;
495  break;
497  continue;
498  default :
499  return false;
500  }
501 
502  // lookup tf based on frame id
503  bool skip_filter = false;
505  for (int i_tf = 0; i_tf < tf_count; i_tf++) {
506  std::string frame_temp = filters_[i_filter].frame_[i_tf];
507 
508  // check buffer first
509  int i_frames = 0;
510  for (; i_frames < frames.size(); i_frames++) {
511  if (frames[i_frames].first == frame_temp) {
512  tf_temp[i_tf] = frames[i_frames].second;
513 
514  if (tf_temp[i_tf].getBasis()[0][0] < -2) {
515  skip_filter = true;
516  }
517  break;
518  }
519  }
520 
521  // look up is necessary
522  if (i_frames >= frames.size()) {
523  tf::StampedTransform stf_temp;
524  std::string error_msg;
525  try {
526  bool check_transform = true;
527 
528  // wait for transform
529  if (tf_lookup_time_ > 0) {
530  ros::Duration current_duration = ros::Time::now() - start_time;
531  if (current_duration < ros::Duration(tf_lookup_time_)) {
532  ros::Duration max_duration = ros::Duration(tf_lookup_time_) - current_duration;
533  if (tf_listener.waitForTransform(frame_temp,
534  base_frame, time, max_duration,
535  ros::Duration(0.01), &error_msg)) {
536  check_transform = false;
537  } else {
538  skip_filter = true;
539  }
540  }
541  }
542 
543  // check if transform is possible
544  if ((! skip_filter) && check_transform) {
545  if(! tf_listener.canTransform(frame_temp,
546  base_frame, time, &error_msg)) {
547  skip_filter = true;
548  }
549  }
550 
551  // get transform
552  if (! skip_filter) {
553  tf_listener.lookupTransform(frame_temp, base_frame,
554  time, stf_temp);
555  }
556  } catch (tf::TransformException &ex){
557  skip_filter = true;
558  error_msg = ex.what();
559  }
560 
561  // error handling
562  if (skip_filter) {
563  if (filters_[i_filter].required_) {
564  ROS_DEBUG("%s",error_msg.data());
565  }
566 
567  // save a invalid tf (rot[0,0] < -2)
568  tf_temp[i_tf].getBasis()[0][0] = -10;
569  frames.push_back(std::pair<std::string, tf::Transform>
570  (frame_temp, tf_temp[i_tf]));
571  } else {
572  // save current tf
573  tf_temp[i_tf] = stf_temp;
574  frames.push_back(std::pair<std::string, tf::Transform>
575  (frame_temp, tf_temp[i_tf]));
576  }
577  }
578 
579  if (skip_filter) {
580  if (filters_[i_filter].required_) {
581  return false;
582  }
583  break;
584  }
585 
586  tf_temp[i_tf] = filters_[i_filter].offset_[i_tf] * tf_temp[i_tf];
587  }
588 
589  // create final filters
590  cPcdFilterPaFilter filter_temp;
591  if (skip_filter) {
592  filter_temp.type_ = cPcdFilterPaFilter::ftNONE;
593  result.push_back(filter_temp);
594  continue;
595  }
596 
597  switch (filters_[i_filter].type_) {
599  filter_temp.type_ = cPcdFilterPaFilter::ftCUBE;
600  filter_temp.parameter_[0] =
601  filters_[i_filter].parameter_[0] / 2;
602  break;
604  filter_temp.type_ = cPcdFilterPaFilter::ftSPHERE;
605  filter_temp.parameter_[0] = filters_[i_filter].parameter_[0] *
606  filters_[i_filter].parameter_[0];
607  break;
609  filter_temp.type_ = cPcdFilterPaFilter::ftBLOCK;
610  for (int i = 0; i < 3; i++) {
611  filter_temp.parameter_[i] =
612  filters_[i_filter].parameter_[i] / 2;
613  }
614  break;
617  filter_temp.parameter_[0] = filters_[i_filter].parameter_[0] *
618  filters_[i_filter].parameter_[0];
619  filter_temp.parameter_[1] =
620  filters_[i_filter].parameter_[1] / 2;
621  break;
623  {
625 
626  double d = update_transform(tf_temp[0], tf_temp[1],
627  tf_temp[0], 0.5);
628  if (d < 0) {
629  filter_temp.type_ = cPcdFilterPaFilter::ftNONE;
630  break;
631  }
632 
633  filter_temp.parameter_[0] =
634  filters_[i_filter].parameter_[0] *
635  filters_[i_filter].parameter_[0];
636  filter_temp.parameter_[1] = d / 2 +
637  filters_[i_filter].parameter_[1];
638  }
639 
640  break;
642  filter_temp.type_ = cPcdFilterPaFilter::ftCONE;
643 
644  if (update_transform(tf_temp[0], tf_temp[1], tf_temp[0], 0.5) < 0) {
645  filter_temp.type_ = cPcdFilterPaFilter::ftNONE;
646  break;
647  }
648 
649  filter_temp.parameter_[0] = filters_[i_filter].parameter_[0];
650  filter_temp.parameter_[1] = filters_[i_filter].parameter_[1] * filters_[i_filter].parameter_[1];
651  break;
652  }
653 
654  filter_temp.inverse_ = filters_[i_filter].inverse_;
655  filter_temp.translation_[0] = tf_temp[0].getOrigin().x();
656  filter_temp.translation_[1] = tf_temp[0].getOrigin().y();
657  filter_temp.translation_[2] = tf_temp[0].getOrigin().z();
658 
659  for (int y = 0; y < 3; y++) {
660  for (int x = 0; x < 3; x++) {
661  filter_temp.rotation_(y,x) = tf_temp[0].getBasis()[y][x];
662  }
663  }
664 
665  result.push_back(filter_temp);
666  }
667 
668  return true;
669 }
670 
671 //**************************[getLast]******************************************
672 std::string cPcdFilterPaRosFilters::getLast() const {
673 
674  return last_filter_.toString();
675 }
676 
677 //**************************[size]*********************************************
679  return filters_.size();
680 }
681 
682 //**************************[operator]*****************************************
684  return filters_[i];
685 }
686 
687 //**************************[operator]*****************************************
689  return filters_[i];
690 }
691 //**************************[operator]*****************************************
693  const tf::Transform &goal, tf::Transform &result, const double relative_pos) const {
694 
695  tf::Vector3 v = (start * goal.inverse()).getOrigin();
696  double d = v.length();
697 
698  if (v.fuzzyZero()) {
699  return -1;
700  }
701  tf::Vector3 axis = v;
702  v.normalize();
703  axis = tf::Vector3 (1,0,0).cross(v);
704 
705  tf::Transform tf_shift;
706  if (! axis.fuzzyZero()) {
707  tf::Quaternion q(axis.normalized(),tfAsin(axis.length()));
708  q = q.inverse();
709  tf_shift.setRotation(q);
710  } else {
711  tf_shift.setRotation(tf::Quaternion().getIdentity());
712  }
713  tf_shift.setOrigin(tf::Vector3(d * relative_pos,0,0));
714 
715  result = tf_shift * start;
716  return d;
717 }
718 
std::string toString(void) const
returning string equivalent of filter
d
cPcdFilterPaRosFilter & operator[](int i)
void reset(void)
reseting this filter
TFSIMD_FORCE_INLINE void setRotation(const Quaternion &q)
std::string _floatToStr(const double &value) const
helper function for converting a double
std::string getLast(void) const
bool inverse_
inverted filter
TFSIMD_FORCE_INLINE void setX(tfScalar x)
TFSIMD_FORCE_INLINE bool fuzzyZero() const
eFiltertype type_
filter type
f
TFSIMD_FORCE_INLINE void setY(tfScalar y)
std::string frame_[COUNT_FRAME]
frame id(s)
bool fromString(const std::string &filter)
setting filter from string
TFSIMD_FORCE_INLINE Matrix3x3 & getBasis()
cPcdFilterPaRosFilter & operator=(const cPcdFilterPaRosFilter &other)
XmlRpcServer s
TFSIMD_FORCE_INLINE void setZ(tfScalar z)
bool isValid(void) const
returning if filter is valid
std::string _getValue(const std::string &str, int &pos) const
helper function for returning the next value
Quaternion & normalize()
TFSIMD_FORCE_INLINE const tfScalar & y() const
bool _StrToFloat(const std::string &str, double &value) const
helper function for converting a double
bool canTransform(const std::string &target_frame, const std::string &source_frame, const ros::Time &time, std::string *error_msg=NULL) const
TFSIMD_FORCE_INLINE Vector3 cross(const Vector3 &v) const
void setIdentity()
bool waitForTransform(const std::string &target_frame, const std::string &source_frame, const ros::Time &time, const ros::Duration &timeout, const ros::Duration &polling_sleep_duration=ros::Duration(0.01), std::string *error_msg=NULL) const
TFSIMD_FORCE_INLINE const tfScalar & x() const
bool inverse_
inverted filter
TFSIMD_FORCE_INLINE const tfScalar & z() const
static const Quaternion & getIdentity()
TFSIMD_FORCE_INLINE Vector3 normalized() const
TFSIMD_FORCE_INLINE const tfScalar & y() const
bool _skipWhitespace(const std::string &str, int &pos) const
helper function for skipping whitespace
TFSIMD_FORCE_INLINE const tfScalar & x() const
Transform inverse() const
std::string comment_
comment to filter
eFiltertype type_
filter type
TFSIMD_FORCE_INLINE Vector3 & getOrigin()
void lookupTransform(const std::string &target_frame, const std::string &source_frame, const ros::Time &time, StampedTransform &transform) const
Quaternion inverse() const
TFSIMD_FORCE_INLINE Vector3 & normalize()
std::string _getComment(const std::string &str) const
helper function for returning the comment
bool add(std::string filter)
Quaternion getRotation() const
bool update(const tf::TransformListener &tf_listener, const std::string base_frame, const ros::Time time, std::vector< cPcdFilterPaFilter > &result) const
TFSIMD_FORCE_INLINE tfScalar tfAsin(tfScalar x)
bool _checkSymbol(const std::string &str, int &pos, const char symbol) const
helper function for checking a certain symbol
tf::Transform offset_[COUNT_FRAME]
static Time now()
bool required_
required filter
double update_transform(const tf::Transform &start, const tf::Transform &goal, tf::Transform &result, const double relative_pos=0.0) const
TFSIMD_FORCE_INLINE void setOrigin(const Vector3 &origin)
std::vector< std::string > get(void) const
TFSIMD_FORCE_INLINE tfScalar length() const
double parameter_[COUNT_PARAMETER]
single parameter of filter
#define ROS_DEBUG(...)


pcdfilter_pa
Author(s):
autogenerated on Fri Jun 7 2019 21:53:31