Program Listing for File Projection.h

Return to documentation for file (include/lanelet2_io/Projection.h)

#pragma once
#include <lanelet2_core/primitives/GPSPoint.h>
#include <lanelet2_core/primitives/Point.h>

#include <memory>
#include <vector>

namespace lanelet {
struct Origin {
  explicit Origin(const GPSPoint& position) : position{position}, isDefault{false} {}
  Origin() = default;

  static Origin defaultOrigin() { return {}; }
  GPSPoint position;
  bool isDefault{true};
};

class Projector {  // NOLINT
 public:
  using Ptr = std::shared_ptr<Projector>;
  explicit Projector(Origin origin = Origin::defaultOrigin()) : origin_{origin} {}
  Projector(Projector&& rhs) noexcept = default;
  Projector& operator=(Projector&& rhs) noexcept = default;
  Projector(const Projector& rhs) = default;
  Projector& operator=(const Projector& rhs) = default;
  virtual ~Projector() noexcept = default;

  virtual BasicPoint3d forward(const GPSPoint& p) const = 0;

  virtual GPSPoint reverse(const BasicPoint3d& p) const = 0;

  const Origin& origin() const { return origin_; }

 private:
  Origin origin_;
};

namespace projection {
class SphericalMercatorProjector : public Projector {
 public:
  using Projector::Projector;
  BasicPoint3d forward(const GPSPoint& p) const override {
    const auto scale = std::cos(origin().position.lat * M_PI / 180.0);
    const double x{scale * p.lon * M_PI * EarthRadius / 180.0};
    const double y{scale * EarthRadius * std::log(std::tan((90.0 + p.lat) * M_PI / 360.0))};
    return {x, y, p.ele};
  }

  GPSPoint reverse(const BasicPoint3d& p) const override {
    const double scale = std::cos(origin().position.lat * M_PI / 180.0);
    const double lon = p.x() * 180.0 / (M_PI * EarthRadius * scale);
    const double lat = 360.0 * std::atan(std::exp(p.y() / (EarthRadius * scale))) / M_PI - 90.0;
    return {lat, lon, p.z()};
  }

 private:
  static constexpr double EarthRadius{6378137.0};
};
}  // namespace projection

using DefaultProjector = projection::SphericalMercatorProjector;

inline DefaultProjector defaultProjection(Origin origin = Origin::defaultOrigin()) { return DefaultProjector(origin); }
}  // namespace lanelet