geometry.h 5.89 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146
#ifndef AIRMAP_GEOMETRY_H_
#define AIRMAP_GEOMETRY_H_

#include <airmap/optional.h>

#include <vector>

namespace airmap {

/// Geometry bundles up different types of geometries.
class Geometry {
 public:
  /// Type enumerates all known geometry types.
  enum class Type {
    invalid,             ///< Marks an invalid geometry.
    point,               ///< Geometry contains a Point.
    multi_point,         ///< Geometry contains a MultiPoint.
    line_string,         ///< Geometry contains a LineString.
    multi_line_string,   ///< Geometry contains a MultiLineString.
    polygon,             ///< Geometry contains a Polygon.
    multi_polygon,       ///< Geometry contains a MultiPolygon.
    geometry_collection  ///< Geometry is a GemetryCollection.
  };

  /// Coordinate marks a point in 3-dimensional space.
  struct Coordinate {
    double latitude;            /// The latitude component of this coordinate in [°].
    double longitude;           /// The longitude component of this coordinate in [°].
    Optional<double> altitude;  /// The altitude component of this coordinate in [m].
    Optional<double> elevation;
  };

  /// CoordinateVector is a collection of points in 3-dimensional space.
  template <Type tag>
  struct CoordinateVector {
    std::vector<Coordinate> coordinates;  ///< The individual coordinates.
  };

  using Point           = Coordinate;
  using MultiPoint      = CoordinateVector<Type::multi_point>;
  using LineString      = CoordinateVector<Type::line_string>;
  using MultiLineString = std::vector<LineString>;
  /// Polygon follows the GeoJSON standard, citing from https://tools.ietf.org/html/rfc7946:
  ///   * For type "Polygon", the "coordinates" member MUST be an array of
  ///     linear ring coordinate arrays.
  ///   * For Polygons with more than one of these rings, the first MUST be
  ///     the exterior ring, and any others MUST be interior rings.  The
  ///     exterior ring bounds the surface, and the interior rings (if
  ///     present) bound holes within the surface.
  struct Polygon {
    CoordinateVector<Type::polygon> outer_ring;
    std::vector<CoordinateVector<Type::polygon>> inner_rings;
  };
  using MultiPolygon       = std::vector<Polygon>;
  using GeometryCollection = std::vector<Geometry>;

  /// point returns a Geometry instance with Type::point at the given coordinate (lat, lon).
  static Geometry point(double lat, double lon);
  /// polygon returns a Geometry instance with Type::polygon with the given 'coordinates'.
  static Geometry polygon(const std::vector<Coordinate>& coordinates);

  /// Initializes a new instance with Type::invalid.
  Geometry();
  /// Geometry initializes a new instance with the given Point.
  explicit Geometry(const Point& other);
  /// Geometry initializes a new instance with the given MultiPoint.
  explicit Geometry(const MultiPoint& other);
  /// Geometry initializes a new instance with the given LineString.
  explicit Geometry(const LineString& other);
  /// Geometry initializes a new instance with the given MultiLineString.
  explicit Geometry(const MultiLineString& other);
  /// Geometry initializes a new instance with the given Polyon.
  explicit Geometry(const Polygon& other);
  /// Geometry initializes a new instance with the given MultiPolygon.
  explicit Geometry(const MultiPolygon& other);
  /// Geometry initializes a new instance with the given GeometryCollection.
  explicit Geometry(const GeometryCollection& other);
  /// @cond
  Geometry(const Geometry& other);
  ~Geometry();
  Geometry& operator=(const Geometry& rhs);
  bool operator==(const Geometry& rhs) const;
  /// @endcond

  /// type returns the Type of the geometry.
  Type type() const;
  /// details_for_point returns an immutable instance to the contained Point instance.
  const Point& details_for_point() const;
  /// details_for_multi_point returns an immutable instance to the contained MultiPoint instance.
  const MultiPoint& details_for_multi_point() const;
  /// details_for_line_string returns an immutable instance to the contained LineString instance.
  const LineString& details_for_line_string() const;
  /// details_for_multi_line_string returns an immutable instance to the contained MultiLineString instance.
  const MultiLineString& details_for_multi_line_string() const;
  /// details_for_polygon returns an immutable instance to the contained Polygon instance.
  const Polygon& details_for_polygon() const;
  /// details_for_multi_polygon returns an immutable instance to the contained MultiPolygon instance.
  const MultiPolygon& details_for_multi_polygon() const;
  /// details_for_geometry_collection returns an immutable instance to the contained GeometryCollection instance.
  const GeometryCollection details_for_geometry_collection() const;

 private:
  struct Invalid {};

  union Data {
    Data();
    ~Data();

    Invalid invalid;
    Point point;
    MultiPoint multi_point;
    LineString line_string;
    MultiLineString multi_line_string;
    Polygon polygon;
    MultiPolygon multi_polygon;
    GeometryCollection geometry_collection;
  };

  Geometry& reset();
  void set_point(const Point& point);
  void set_multi_point(const MultiPoint& multi_point);
  void set_line_string(const LineString& line_string);
  void set_multi_line_string(const MultiLineString& multi_line_string);
  void set_polygon(const Polygon& polygon);
  void set_multi_polygon(const MultiPolygon& multi_polygon);
  void set_geometry_collection(const GeometryCollection& geometry_collection);
  Geometry& set_geometry(const Geometry& other);

  Type type_;
  Data data_;
};

/// @cond
bool operator==(const Geometry::Coordinate& lhs, const Geometry::Coordinate& rhs);

bool operator==(const Geometry::Polygon& lhs, const Geometry::Polygon& rhs);

template <Geometry::Type tag>
bool operator==(const Geometry::CoordinateVector<tag>& lhs, const Geometry::CoordinateVector<tag>& rhs) {
  return lhs.coordinates == rhs.coordinates;
}
/// @endcond

}  // namespace airmap

#endif  // AIRMAP_GEOMETRY_H_