Program Listing for File display.h

Return to documentation for file (include/event_camera_renderer/display.h)

// -*-c++-*---------------------------------------------------------------------------------------
// Copyright 2022 Bernd Pfrommer <bernd.pfrommer@gmail.com>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef EVENT_CAMERA_RENDERER__DISPLAY_H_
#define EVENT_CAMERA_RENDERER__DISPLAY_H_

#include <event_camera_renderer/ros_compat.h>

#include <memory>

namespace event_camera_renderer
{
class Display
{
public:
  virtual ~Display() {}
  //
  // ------------- pure virtual functions
  //
  virtual void initialize(const ros_compat::EventPacket & msg) = 0;

  virtual bool update(
    const ros_compat::EventPacket & msg, uint64_t timeLimit, uint64_t * nextTime) = 0;

  virtual ros_compat::ImgPtr getImage() = 0;

  virtual void setImage(ros_compat::ImgPtr * img) = 0;  // take ownership of pointer and memory

  //
  // ------------- end of pure virtual functions
  //

  inline bool isInitialized() const { return (t0_ != std::numeric_limits<int64_t>::lowest()); }
  inline bool setHeaderTime(const ros_compat::Time & t)
  {
    if (isInitialized() && t < rosHeaderTime_) {
      rosHeaderTime_ = t;
      return (false);
    }
    rosHeaderTime_ = t;
    return (true);
  }
  inline void setIsFirstTimeInPacket(bool b) { isFirstTimeInPacket_ = b; }

  // check if currently building an image
  inline bool hasImage() const { return (img_ != nullptr); }

  // deallocate memory associated with pointer
  inline void resetImagePtr() { img_.reset(); }

  inline uint64_t rosToSensorTime(const rclcpp::Time & t) const { return (t.nanoseconds() - t0_); }
  inline rclcpp::Time sensorToRosTime(uint64_t t) const
  {
    return (rclcpp::Time(t + t0_, RCL_ROS_TIME));
  }

  inline void maybeUpdateRosToSensorTimeOffset(uint64_t sensor_time)
  {
    if (isFirstTimeInPacket_) {
      updateRosToSensorTimeOffset(rosHeaderTime_, static_cast<int64_t>(sensor_time));
      isFirstTimeInPacket_ = false;
    }
  }
  void updateRosToSensorTimeOffset(const ros_compat::Time & t_ros, int64_t t_sens)
  {
    if (t0_ == std::numeric_limits<int64_t>::lowest()) {
      t0_ = static_cast<int64_t>(t_ros.nanoseconds()) - t_sens;
      t0_init_ = t0_;
    } else {
      // to avoid rounding errors, first subtract off the large t0_init_,
      // which contains the time since epoch.
      const double dt_meas = static_cast<double>(
        static_cast<int64_t>(t_ros.nanoseconds()) - t0_init_ - t_sens);  // measured
      const double dt_k = static_cast<double>(t0_ - t0_init_);           // current estimate
      constexpr double alpha = 1.0 / 100.0;
      t0_ = t0_init_ + static_cast<int64_t>(dt_k * (1 - alpha) + dt_meas * alpha);
    }
  }

  void resetTime()
  {
    isFirstTimeInPacket_ = true;
    t0_ = std::numeric_limits<int64_t>::lowest();  // ros to sensor time offset
    t0_init_ = 0;
  }

  // -----------------
  // factory method
  static std::shared_ptr<Display> newInstance(const std::string & type);

protected:
  Display() {}
  ros_compat::ImgPtr img_;
  bool isFirstTimeInPacket_{true};
  ros_compat::Time rosHeaderTime_{0LL, RCL_ROS_TIME};
  int64_t t0_{std::numeric_limits<int64_t>::lowest()};  // ros to sensor time offset
  int64_t t0_init_{0};
};
}  // namespace event_camera_renderer
#endif  // EVENT_CAMERA_RENDERER__DISPLAY_H_