Program Listing for File point_cloud2_iterator.hpp

Return to documentation for file (/tmp/ws/src/common_interfaces/sensor_msgs/include/sensor_msgs/impl/point_cloud2_iterator.hpp)

// Copyright (c) 2013, Open Source Robotics Foundation, Inc.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
//    * Redistributions of source code must retain the above copyright
//      notice, this list of conditions and the following disclaimer.
//
//    * Redistributions in binary form must reproduce the above copyright
//      notice, this list of conditions and the following disclaimer in the
//      documentation and/or other materials provided with the distribution.
//
//    * Neither the name of the copyright holder nor the names of its
//      contributors may be used to endorse or promote products derived from
//      this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.

// This file is originally from:
// https://github.com/ros/common_msgs/blob/50ee957/sensor_msgs/include/sensor_msgs/impl/point_cloud2_iterator.h

#ifndef SENSOR_MSGS__IMPL__POINT_CLOUD2_ITERATOR_HPP_
#define SENSOR_MSGS__IMPL__POINT_CLOUD2_ITERATOR_HPP_

#include <sensor_msgs/msg/point_cloud2.hpp>
#include <cstdarg>
#include <sstream>
#include <string>
#include <vector>

namespace
{
inline int sizeOfPointField(int datatype)
{
  if ((datatype == sensor_msgs::msg::PointField::INT8) ||
    (datatype == sensor_msgs::msg::PointField::UINT8))
  {
    return 1;
  } else if ((datatype == sensor_msgs::msg::PointField::INT16) ||  // NOLINT
    (datatype == sensor_msgs::msg::PointField::UINT16))
  {
    return 2;
  } else if ((datatype == sensor_msgs::msg::PointField::INT32) ||  // NOLINT
    (datatype == sensor_msgs::msg::PointField::UINT32) ||
    (datatype == sensor_msgs::msg::PointField::FLOAT32))
  {
    return 4;
  } else if (datatype == sensor_msgs::msg::PointField::FLOAT64) {
    return 8;
  } else {
    std::stringstream err;
    err << "PointField of type " << datatype << " does not exist";
    throw std::runtime_error(err.str());
  }
  return -1;
}

inline int addPointField(
  sensor_msgs::msg::PointCloud2 & cloud_msg,
  const std::string & name, int count, int datatype,
  int offset)
{
  sensor_msgs::msg::PointField point_field;
  point_field.name = name;
  point_field.count = count;
  point_field.datatype = datatype;
  point_field.offset = offset;
  cloud_msg.fields.push_back(point_field);

  // Update the offset
  return offset + point_field.count * sizeOfPointField(datatype);
}
}  // namespace


namespace sensor_msgs
{

inline PointCloud2Modifier::PointCloud2Modifier(
  sensor_msgs::msg::PointCloud2 & cloud_msg)
: cloud_msg_(cloud_msg)
{
}

inline size_t PointCloud2Modifier::size() const
{
  return cloud_msg_.data.size() / cloud_msg_.point_step;
}

inline void PointCloud2Modifier::reserve(size_t size)
{
  cloud_msg_.data.reserve(size * cloud_msg_.point_step);
}

inline void PointCloud2Modifier::resize(size_t size)
{
  cloud_msg_.data.resize(size * cloud_msg_.point_step);

  // Update height/width
  if (cloud_msg_.height == 1) {
    cloud_msg_.width = static_cast<uint32_t>(size);
    cloud_msg_.row_step = static_cast<uint32_t>(size * cloud_msg_.point_step);
  } else {
    if (cloud_msg_.width == 1) {
      cloud_msg_.height = static_cast<uint32_t>(size);
    } else {
      cloud_msg_.height = 1;
      cloud_msg_.width = static_cast<uint32_t>(size);
      cloud_msg_.row_step = static_cast<uint32_t>(size * cloud_msg_.point_step);
    }
  }
}

inline void PointCloud2Modifier::clear()
{
  cloud_msg_.data.clear();

  // Update height/width
  if (cloud_msg_.height == 1) {
    cloud_msg_.row_step = cloud_msg_.width = 0;
  } else {
    if (cloud_msg_.width == 1) {
      cloud_msg_.height = 0;
    } else {
      cloud_msg_.row_step = cloud_msg_.width = cloud_msg_.height = 0;
    }
  }
}


inline void PointCloud2Modifier::setPointCloud2Fields(int n_fields, ...)
{
  cloud_msg_.fields.clear();
  cloud_msg_.fields.reserve(n_fields);
  va_list vl;
  va_start(vl, n_fields);
  int offset = 0;
  for (int i = 0; i < n_fields; ++i) {
    // Create the corresponding PointField
    std::string name(va_arg(vl, char *));
    int count(va_arg(vl, int));
    int datatype(va_arg(vl, int));
    offset = addPointField(cloud_msg_, name, count, datatype, offset);
  }
  va_end(vl);

  // Resize the point cloud accordingly
  cloud_msg_.point_step = offset;
  cloud_msg_.row_step = cloud_msg_.width * cloud_msg_.point_step;
  cloud_msg_.data.resize(cloud_msg_.height * cloud_msg_.row_step);
}

inline void PointCloud2Modifier::setPointCloud2FieldsByString(int n_fields, ...)
{
  cloud_msg_.fields.clear();
  cloud_msg_.fields.reserve(n_fields);
  va_list vl;
  va_start(vl, n_fields);
  int offset = 0;
  for (int i = 0; i < n_fields; ++i) {
    // Create the corresponding PointFields
    std::string
      field_name = std::string(va_arg(vl, char *));
    if (field_name == "xyz") {
      sensor_msgs::msg::PointField point_field;
      // Do x, y and z
      offset = addPointField(
        cloud_msg_, "x", 1, sensor_msgs::msg::PointField::FLOAT32, offset);
      offset = addPointField(
        cloud_msg_, "y", 1, sensor_msgs::msg::PointField::FLOAT32, offset);
      offset = addPointField(
        cloud_msg_, "z", 1, sensor_msgs::msg::PointField::FLOAT32, offset);
      offset += sizeOfPointField(sensor_msgs::msg::PointField::FLOAT32);
    } else {
      if ((field_name == "rgb") || (field_name == "rgba")) {
        offset = addPointField(
          cloud_msg_, field_name, 1, sensor_msgs::msg::PointField::FLOAT32,
          offset);
        offset += 3 * sizeOfPointField(sensor_msgs::msg::PointField::FLOAT32);
      } else {
        va_end(vl);
        throw std::runtime_error("Field " + field_name + " does not exist");
      }
    }
  }
  va_end(vl);

  // Resize the point cloud accordingly
  cloud_msg_.point_step = offset;
  cloud_msg_.row_step = cloud_msg_.width * cloud_msg_.point_step;
  cloud_msg_.data.resize(cloud_msg_.height * cloud_msg_.row_step);
}


namespace impl
{

template<typename T, typename TT, typename U, typename C, template<typename> class V>
PointCloud2IteratorBase<T, TT, U, C, V>::PointCloud2IteratorBase()
: data_char_(0), data_(0), data_end_(0)
{
}

template<typename T, typename TT, typename U, typename C, template<typename> class V>
PointCloud2IteratorBase<T, TT, U, C, V>::PointCloud2IteratorBase(
  C & cloud_msg, const std::string & field_name)
{
  int offset = set_field(cloud_msg, field_name);

  data_char_ = &(cloud_msg.data.front()) + offset;
  data_ = reinterpret_cast<TT *>(data_char_);
  data_end_ = reinterpret_cast<TT *>(&(cloud_msg.data.back()) + 1 + offset);
}

template<typename T, typename TT, typename U, typename C, template<typename> class V>
V<T> & PointCloud2IteratorBase<T, TT, U, C, V>::operator=(const V<T> & iter)
{
  if (this != &iter) {
    point_step_ = iter.point_step_;
    data_char_ = iter.data_char_;
    data_ = iter.data_;
    data_end_ = iter.data_end_;
    is_bigendian_ = iter.is_bigendian_;
  }

  return *this;
}

template<typename T, typename TT, typename U, typename C, template<typename> class V>
TT & PointCloud2IteratorBase<T, TT, U, C, V>::operator[](size_t i) const
{
  return *(data_ + i);
}

template<typename T, typename TT, typename U, typename C, template<typename> class V>
TT & PointCloud2IteratorBase<T, TT, U, C, V>::operator*() const
{
  return *data_;
}

template<typename T, typename TT, typename U, typename C, template<typename> class V>
V<T> & PointCloud2IteratorBase<T, TT, U, C, V>::operator++()
{
  data_char_ += point_step_;
  data_ = reinterpret_cast<TT *>(data_char_);
  return *static_cast<V<T> *>(this);
}

template<typename T, typename TT, typename U, typename C, template<typename> class V>
V<T> PointCloud2IteratorBase<T, TT, U, C, V>::operator+(int i)
{
  V<T> res = *static_cast<V<T> *>(this);

  res.data_char_ += i * point_step_;
  res.data_ = reinterpret_cast<TT *>(res.data_char_);

  return res;
}

template<typename T, typename TT, typename U, typename C, template<typename> class V>
V<T> & PointCloud2IteratorBase<T, TT, U, C, V>::operator+=(int i)
{
  data_char_ += i * point_step_;
  data_ = reinterpret_cast<TT *>(data_char_);
  return *static_cast<V<T> *>(this);
}

template<typename T, typename TT, typename U, typename C, template<typename> class V>
bool PointCloud2IteratorBase<T, TT, U, C, V>::operator!=(const V<T> & iter) const
{
  return iter.data_ != data_;
}

template<typename T, typename TT, typename U, typename C, template<typename> class V>
V<T> PointCloud2IteratorBase<T, TT, U, C, V>::end() const
{
  V<T> res = *static_cast<const V<T> *>(this);
  res.data_ = data_end_;
  return res;
}

template<typename T, typename TT, typename U, typename C, template<typename> class V>
int PointCloud2IteratorBase<T, TT, U, C, V>::set_field(
  const sensor_msgs::msg::PointCloud2 & cloud_msg, const std::string & field_name)
{
  is_bigendian_ = cloud_msg.is_bigendian;
  point_step_ = cloud_msg.point_step;
  // make sure the channel is valid
  std::vector<sensor_msgs::msg::PointField>::const_iterator field_iter = cloud_msg.fields.begin(),
    field_end =
    cloud_msg.fields.end();
  while ((field_iter != field_end) && (field_iter->name != field_name)) {
    ++field_iter;
  }

  if (field_iter == field_end) {
    // Handle the special case of r,g,b,a (we assume they are understood as the
    // channels of an rgb or rgba field)
    if ((field_name == "r") || (field_name == "g") || (field_name == "b") || (field_name == "a")) {
      // Check that rgb or rgba is present
      field_iter = cloud_msg.fields.begin();
      while ((field_iter != field_end) && (field_iter->name != "rgb") &&
        (field_iter->name != "rgba"))
      {
        ++field_iter;
      }
      if (field_iter == field_end) {
        throw std::runtime_error("Field " + field_name + " does not exist");
      }
      if (field_name == "r") {
        if (is_bigendian_) {
          return field_iter->offset + 1;
        } else {
          return field_iter->offset + 2;
        }
      }
      if (field_name == "g") {
        if (is_bigendian_) {
          return field_iter->offset + 2;
        } else {
          return field_iter->offset + 1;
        }
      }
      if (field_name == "b") {
        if (is_bigendian_) {
          return field_iter->offset + 3;
        } else {
          return field_iter->offset + 0;
        }
      }
      if (field_name == "a") {
        if (is_bigendian_) {
          return field_iter->offset + 0;
        } else {
          return field_iter->offset + 3;
        }
      }
    } else {
      throw std::runtime_error("Field " + field_name + " does not exist");
    }
  }

  return field_iter->offset;
}

}  // namespace impl
}  // namespace sensor_msgs

#endif  // SENSOR_MSGS__IMPL__POINT_CLOUD2_ITERATOR_HPP_