Program Listing for File raycasting.hpp

Return to documentation for file (include/beluga/algorithm/raycasting.hpp)

// Copyright 2023 Ekumen, Inc.
//
// 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 BELUGA_ALGORITHM_RAYCASTING_HPP
#define BELUGA_ALGORITHM_RAYCASTING_HPP

#include <algorithm>
#include <optional>
#include <utility>

#include <beluga/algorithm/raycasting/bresenham.hpp>

#include <range/v3/view/all.hpp>
#include <range/v3/view/take_while.hpp>

#include <sophus/se2.hpp>
#include <sophus/so2.hpp>

namespace beluga {


template <class OccupancyGrid, typename Algorithm = Bresenham2i>
class Ray2d {
 public:

  explicit Ray2d(const OccupancyGrid& grid, const Sophus::SE2d& source_pose, double max_range) noexcept
      : Ray2d(grid, Algorithm{}, source_pose, max_range) {}


  explicit Ray2d(
      const OccupancyGrid& grid,
      Algorithm algorithm,
      const Sophus::SE2d& source_pose,
      double max_range) noexcept
      : grid_(grid),
        algorithm_(std::move(algorithm)),
        source_pose_in_local_frame_(grid_.origin().inverse() * source_pose),
        source_cell_(grid_.cell_near(source_pose_in_local_frame_.translation())),
        max_range_(max_range) {}


  [[nodiscard]] auto trace(const Sophus::SO2d& bearing) const {
    // Don't do the multiplication in SE2, it's slower
    const auto& r1 = source_pose_in_local_frame_.so2();
    const auto& t1 = source_pose_in_local_frame_.translation();
    const auto t2 = bearing.unit_complex() * max_range_;
    const auto far_end_pose_in_local_frame = Sophus::SE2d{r1, r1 * t2 + t1};
    const auto far_end_cell = grid_.cell_near(far_end_pose_in_local_frame.translation());
    const auto cell_is_valid = [this](const auto& cell) { return grid_.contains(cell); };
    return algorithm_(source_cell_, far_end_cell) | ranges::views::take_while(cell_is_valid);
  }


  [[nodiscard]] std::optional<double> cast(const Sophus::SO2d& bearing) const {
    for (const auto& cell : trace(bearing)) {
      if (!grid_.free_at(cell)) {
        const auto source_position = grid_.coordinates_at(source_cell_);
        const auto cell_position = grid_.coordinates_at(cell);
        const auto distance = (cell_position - source_position).norm();
        return std::make_optional(std::min(distance, max_range_));
      }
    }
    return std::nullopt;
  }

 private:
  const OccupancyGrid& grid_;
  const Algorithm algorithm_;
  const Sophus::SE2d source_pose_in_local_frame_;
  const Eigen::Vector2i source_cell_;
  const double max_range_;
};

}  // namespace beluga

#endif