snake.h 8.5 KB
Newer Older
1 2 3
#pragma once

#include <array>
4 5
#include <atomic>
#include <functional>
Valentin Platzgummer's avatar
Valentin Platzgummer committed
6
#include <memory>
7 8 9 10 11 12 13 14 15
#include <string>
#include <vector>

#include <boost/geometry.hpp>
#include <boost/units/systems/angle/degrees.hpp>
#include <boost/units/systems/si.hpp>
#include <boost/units/systems/si/io.hpp>
#include <boost/units/systems/si/plane_angle.hpp>
#include <boost/units/systems/si/prefixes.hpp>
16

17 18
namespace bg = boost::geometry;
namespace bu = boost::units;
19

Valentin Platzgummer's avatar
Valentin Platzgummer committed
20 21 22
#include <GeographicLib/Geocentric.hpp>
#include <GeographicLib/LocalCartesian.hpp>

23 24 25
using namespace std;

namespace snake {
Valentin Platzgummer's avatar
Valentin Platzgummer committed
26 27 28
//=========================================================================
// Geometry stuff.
//=========================================================================
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
// Double geometry.
using FloatType = double;
typedef bg::model::point<double, 2, bg::cs::cartesian> FPoint;
typedef bg::model::polygon<FPoint> FPolygon;
typedef bg::model::linestring<FPoint> FLineString;
typedef bg::model::box<FPoint> FBox;

// Integer geometry.
using IntType = long long;
using IPoint = bg::model::point<IntType, 2, bg::cs::cartesian>;
using IPolygon = bg::model::polygon<IPoint>;
using IRing = bg::model::ring<IPoint>;
using ILineString = bg::model::linestring<IPoint>;

FPoint int2Float(const IPoint &ip);
FPoint int2Float(const IPoint &ip, IntType scale);
IPoint float2Int(const FPoint &ip);
IPoint float2Int(const FPoint &ip, IntType scale);

template <class T> class Matrix;

template <class DataType>
ostream &operator<<(ostream &os, const Matrix<DataType> &matrix) {
  for (std::size_t i = 0; i < matrix.m(); ++i) {
    for (std::size_t j = 0; j < matrix.n(); ++j) {
      os << "(" << i << "," << j << "):" << matrix(i, j) << std::endl;
    }
  }
  return os;
}

// Matrix
template <class DataType> class Matrix {
Valentin Platzgummer's avatar
Valentin Platzgummer committed
63
public:
64 65 66 67
  using value_type = DataType;
  Matrix(std::size_t m, std::size_t n) : _m(m), _n(n) { _matrix.resize(m * n); }
  Matrix(std::size_t m, std::size_t n, DataType value) : _m(m), _n(n) {
    _matrix.resize(m * n, value);
68 69
  }

70
  DataType &operator()(std::size_t i, std::size_t j) {
71 72 73 74 75
    assert(i < _m);
    assert(j < _n);
    return _matrix[i * _m + j];
  }

76
  const DataType &operator()(std::size_t i, std::size_t j) const {
77 78
    assert(i < _m);
    assert(j < _n);
79
    return _matrix[i * _m + j];
80 81
  }

82 83
  std::size_t m() const { return _n; }
  std::size_t n() const { return _n; }
84

85
  friend ostream &operator<<<>(ostream &os, const Matrix<DataType> &dt);
Valentin Platzgummer's avatar
Valentin Platzgummer committed
86 87

private:
88 89 90 91
  std::vector<DataType> _matrix;
  const std::size_t _m;
  const std::size_t _n;
}; // Matrix
Valentin Platzgummer's avatar
Valentin Platzgummer committed
92

93 94
struct BoundingBox {
  BoundingBox();
Valentin Platzgummer's avatar
Valentin Platzgummer committed
95

96
  void clear();
Valentin Platzgummer's avatar
Valentin Platzgummer committed
97

98 99 100
  double width;
  double height;
  double angle;
101
  FPolygon corners;
Valentin Platzgummer's avatar
Valentin Platzgummer committed
102
};
Valentin Platzgummer's avatar
Valentin Platzgummer committed
103

104
template <class GeoPoint1, class GeoPoint2>
105
void toENU(const GeoPoint1 &origin, const GeoPoint2 &in, FPoint &out) {
106 107
  static GeographicLib::Geocentric earth(GeographicLib::Constants::WGS84_a(),
                                         GeographicLib::Constants::WGS84_f());
108 109 110
  GeographicLib::LocalCartesian proj(origin.latitude(), origin.longitude(),
                                     origin.altitude(), earth);

Valentin Platzgummer's avatar
Valentin Platzgummer committed
111
  double x = 0, y = 0, z = 0;
Valentin Platzgummer's avatar
Valentin Platzgummer committed
112 113 114
  auto alt = in.altitude();
  alt = std::isnan(alt) ? 0 : alt;
  proj.Forward(in.latitude(), in.longitude(), alt, x, y, z);
115
  out.set<0>(x);
Valentin Platzgummer's avatar
Valentin Platzgummer committed
116
  out.set<1>(y);
117
  (void)z;
Valentin Platzgummer's avatar
Valentin Platzgummer committed
118
}
Valentin Platzgummer's avatar
Valentin Platzgummer committed
119

120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135
template <class GeoPoint1, class GeoPoint2, class Point>
void toENU(const GeoPoint1 &origin, const GeoPoint2 &in, Point &out) {
  static GeographicLib::Geocentric earth(GeographicLib::Constants::WGS84_a(),
                                         GeographicLib::Constants::WGS84_f());
  GeographicLib::LocalCartesian proj(origin.latitude(), origin.longitude(),
                                     origin.altitude(), earth);

  double x = 0, y = 0, z = 0;
  auto alt = in.altitude();
  alt = std::isnan(alt) ? 0 : alt;
  proj.Forward(in.latitude(), in.longitude(), alt, x, y, z);
  out.setX(x);
  out.setY(y);
  (void)z;
}

136
template <class GeoPoint>
137
void fromENU(const GeoPoint &origin, const FPoint &in, GeoPoint &out) {
138 139
  static GeographicLib::Geocentric earth(GeographicLib::Constants::WGS84_a(),
                                         GeographicLib::Constants::WGS84_f());
140 141 142
  GeographicLib::LocalCartesian proj(origin.latitude(), origin.longitude(),
                                     origin.altitude(), earth);

Valentin Platzgummer's avatar
Valentin Platzgummer committed
143
  double lat = 0, lon = 0, alt = 0;
144 145 146 147
  proj.Reverse(in.get<0>(), in.get<1>(), 0.0, lat, lon, alt);
  out.setLatitude(lat);
  out.setLongitude(lon);
  out.setAltitude(alt);
Valentin Platzgummer's avatar
Valentin Platzgummer committed
148 149
}

150 151 152 153 154 155 156 157 158 159
template <class GeoPoint, class Container1, class Container2>
void areaToEnu(const GeoPoint &origin, const Container1 &in, Container2 &out) {
  for (auto &vertex : in) {
    typename Container2::value_type p;
    toENU(origin, vertex, p);
    out.push_back(p);
  }
}

template <class GeoPoint, class Container>
160
void areaToEnu(const GeoPoint &origin, const Container &in, FPolygon &out) {
161
  for (auto &vertex : in) {
162
    FPoint p;
163 164 165 166
    toENU(origin, vertex, p);
    out.outer().push_back(p);
  }
  bg::correct(out);
Valentin Platzgummer's avatar
Valentin Platzgummer committed
167 168
}

169 170 171 172 173 174 175 176 177 178 179
template <class GeoPoint, class Container1, class Container2>
void areaFromEnu(const GeoPoint &origin, Container1 &in,
                 const Container2 &out) {
  for (auto &vertex : in) {
    typename Container2::value_type p;
    fromENU(origin, vertex, p);
    out.push_back(p);
  }
}

template <class GeoPoint, class Container>
180
void areaFromEnu(const GeoPoint &origin, FPolygon &in, const Container &out) {
181 182
  for (auto &vertex : in.outer()) {
    typename Container::value_type p;
183 184 185
    fromENU(origin, vertex, p);
    out.push_back(p);
  }
Valentin Platzgummer's avatar
Valentin Platzgummer committed
186
}
187

188 189 190
void polygonCenter(const FPolygon &polygon, FPoint &center);
bool minimalBoundingBox(const FPolygon &polygon, BoundingBox &minBBox);
void offsetPolygon(const FPolygon &polygon, FPolygon &polygonOffset,
Valentin Platzgummer's avatar
Valentin Platzgummer committed
191
                   double offset);
192 193
void graphFromPolygon(const FPolygon &polygon, const FLineString &vertices,
                      Matrix<double> &graph);
194
bool toDistanceMatrix(Matrix<double> &graph);
195 196 197 198 199 200
bool dijkstraAlgorithm(size_t numElements, size_t startIndex, size_t endIndex,
                       std::vector<size_t> &elementPath, double &length,
                       std::function<double(size_t, size_t)> distanceDij);

bool shortestPathFromGraph(const Matrix<double> &graph, const size_t startIndex,
                           const size_t endIndex, std::vector<size_t> &pathIdx);
Valentin Platzgummer's avatar
Valentin Platzgummer committed
201

Valentin Platzgummer's avatar
Valentin Platzgummer committed
202 203 204
typedef bu::quantity<bu::si::length> Length;
typedef bu::quantity<bu::si::area> Area;
typedef bu::quantity<bu::si::plane_angle> Angle;
Valentin Platzgummer's avatar
Valentin Platzgummer committed
205 206
typedef bu::quantity<bu::si::plane_angle> Radian;
typedef bu::quantity<bu::degree::plane_angle> Degree;
Valentin Platzgummer's avatar
Valentin Platzgummer committed
207

208 209 210
bool joinedArea(const std::vector<FPolygon *> &areas, FPolygon &jArea);
bool joinedArea(const FPolygon &mArea, const FPolygon &sArea,
                const FPolygon &corridor, FPolygon &jArea,
Valentin Platzgummer's avatar
Valentin Platzgummer committed
211
                std::string &errorString);
212 213 214
bool tiles(const FPolygon &area, Length tileHeight, Length tileWidth,
           Area minTileArea, std::vector<FPolygon> &tiles, BoundingBox &bbox,
           std::string &errorString);
215

216
using Transects = vector<FLineString>;
217 218 219
using Progress = vector<int>;

bool transectsFromScenario(Length distance, Length minLength, Angle angle,
220 221
                           const FPolygon &mArea,
                           const std::vector<FPolygon> &tiles,
Valentin Platzgummer's avatar
Valentin Platzgummer committed
222 223
                           const Progress &p, Transects &t,
                           string &errorString);
Valentin Platzgummer's avatar
Valentin Platzgummer committed
224 225 226 227 228 229

struct TransectInfo {
  TransectInfo(size_t n, bool r) : index(n), reversed(r) {}
  size_t index;
  bool reversed;
};
230 231 232 233 234 235
struct Route {
  FLineString path;
  std::vector<TransectInfo> info;
};
using Solution =
    std::vector<Route>; // Every route corresponds to one run/vehicle
236 237
struct RouteParameter {
  RouteParameter()
238 239
      : numSolutionsPerRun(1), numRuns(1), minNumTransectsPerRun(5),
        stop([] { return false; }) {}
240 241
  std::size_t numSolutionsPerRun;
  std::size_t numRuns;
242
  std::size_t minNumTransectsPerRun;
243 244 245
  std::function<bool(void)> stop;
  mutable std::string errorString;
};
246
bool route(const FPolygon &area, const Transects &transects,
247
           std::vector<Solution> &solutionVector,
248
           const RouteParameter &par = RouteParameter());
Valentin Platzgummer's avatar
Valentin Platzgummer committed
249 250

namespace detail {
251
const double offsetConstant =
Valentin Platzgummer's avatar
Valentin Platzgummer committed
252
    0.1; // meter, polygon offset to compenstate for numerical inaccurracies.
Valentin Platzgummer's avatar
Valentin Platzgummer committed
253
} // namespace detail
254 255 256 257 258 259 260
} // namespace snake

// operator== and operator!= for boost point
namespace boost {
namespace geometry {
namespace model {

261 262 263 264
bool operator==(snake::FPoint &p1, snake::FPoint &p2);
bool operator!=(snake::FPoint &p1, snake::FPoint &p2);
bool operator==(snake::IPoint &p1, snake::IPoint &p2);
bool operator!=(snake::IPoint &p1, snake::IPoint &p2);
265

266 267 268
} // namespace model
} // namespace geometry
} // namespace boost