#pragma once #include #include #include #include #include #include #include #include #include #include #include #include #include namespace bg = boost::geometry; namespace bu = boost::units; #include #include #include "QGCQGeoCoordinate.h" #include "QmlObjectListModel.h" namespace geometry { //========================================================================= // Geometry stuff. //========================================================================= // Double geometry. typedef double FloatType; typedef bg::model::point FPoint; typedef bg::model::polygon FPolygon; typedef bg::model::linestring FLineString; typedef bg::model::box FBox; typedef std::vector LineStringArray; // Integer geometry. typedef long long IntType; typedef bg::model::point IPoint; typedef bg::model::polygon IPolygon; typedef bg::model::ring IRing; typedef bg::model::linestring ILineString; 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 Matrix; template std::ostream &operator<<(std::ostream &os, const Matrix &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 Matrix { public: 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); } DataType &operator()(std::size_t i, std::size_t j) { assert(i < _m); assert(j < _n); return _matrix[i * _m + j]; } const DataType &operator()(std::size_t i, std::size_t j) const { assert(i < _m); assert(j < _n); return _matrix[i * _m + j]; } std::size_t m() const { return _n; } std::size_t n() const { return _n; } friend std::ostream &operator<<<>(std::ostream &os, const Matrix &dt); private: std::vector _matrix; const std::size_t _m; const std::size_t _n; }; // Matrix struct BoundingBox { BoundingBox(); void clear(); double width; double height; double angle; FPolygon corners; }; static constexpr int earth_radius = 6371000; // meters (m) static constexpr double epsilon = std::numeric_limits::epsilon(); // meters (m) template void toENU(const GeoPoint1 &origin, const GeoPoint2 &in, FPoint &out) { double lat_rad = in.latitude() * M_PI / 180; double lon_rad = in.longitude() * M_PI / 180; double ref_lon_rad = origin.longitude() * M_PI / 180; double ref_lat_rad = origin.latitude() * M_PI / 180; double sin_lat = std::sin(lat_rad); double cos_lat = std::cos(lat_rad); double cos_d_lon = std::cos(lon_rad - ref_lon_rad); double ref_sin_lat = std::sin(ref_lat_rad); double ref_cos_lat = std::cos(ref_lat_rad); double c = std::acos(ref_sin_lat * sin_lat + ref_cos_lat * cos_lat * cos_d_lon); double k = (std::fabs(c) < epsilon) ? 1.0 : (c / std::sin(c)); double x = k * cos_lat * std::sin(lon_rad - ref_lon_rad) * earth_radius; double y = k * (ref_cos_lat * sin_lat - ref_sin_lat * cos_lat * cos_d_lon) * earth_radius; out.set<0>(x); out.set<1>(y); } template void toENU(const GeoPoint1 &origin, const GeoPoint2 &in, Point &out) { using namespace std; double lat_rad = in.latitude() * M_PI / 180; double lon_rad = in.longitude() * M_PI / 180; double ref_lon_rad = origin.longitude() * M_PI / 180; double ref_lat_rad = origin.latitude() * M_PI / 180; double sin_lat = sin(lat_rad); double cos_lat = cos(lat_rad); double cos_d_lon = cos(lon_rad - ref_lon_rad); double ref_sin_lat = sin(ref_lat_rad); double ref_cos_lat = cos(ref_lat_rad); double c = acos(ref_sin_lat * sin_lat + ref_cos_lat * cos_lat * cos_d_lon); double k = (fabs(c) < epsilon) ? 1.0 : (c / sin(c)); double x = k * cos_lat * sin(lon_rad - ref_lon_rad) * earth_radius; double y = k * (ref_cos_lat * sin_lat - ref_sin_lat * cos_lat * cos_d_lon) * earth_radius; out.setX(x); out.setY(y); } template void fromENU(const GeoPoint &origin, const FPoint &in, GeoPoint &out) { using namespace std; double x_rad = in.get<0>() / earth_radius; double y_rad = in.get<1>() / earth_radius; double c = sqrt(y_rad * y_rad + x_rad * x_rad); double sin_c = sin(c); double cos_c = cos(c); double ref_lon_rad = origin.longitude() * M_PI / 180; double ref_lat_rad = origin.latitude() * M_PI / 180; double ref_sin_lat = sin(ref_lat_rad); double ref_cos_lat = cos(ref_lat_rad); double lat_rad; double lon_rad; if (fabs(c) > epsilon) { lat_rad = asin(cos_c * ref_sin_lat + (y_rad * sin_c * ref_cos_lat) / c); lon_rad = (ref_lon_rad + atan2(x_rad * sin_c, c * ref_cos_lat * cos_c - y_rad * ref_sin_lat * sin_c)); } else { lat_rad = ref_lat_rad; lon_rad = ref_lon_rad; } out.setLatitude(lat_rad * 180 / M_PI); out.setLongitude(lon_rad * 180 / M_PI); out.setAltitude(origin.altitude()); } template 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 void areaToEnu(const GeoPoint &origin, const Container &in, FPolygon &out) { for (auto &vertex : in) { FPoint p; toENU(origin, vertex, p); out.outer().push_back(p); } bg::correct(out); } template void areaToEnu(const GeoPoint &origin, QmlObjectListModel &in, FPolygon &out) { FPolygon buffer; for (int i = 0; i < in.count(); ++i) { auto vertex = in.value(i); if (vertex != nullptr) { FPoint p; toENU(origin, vertex->coordinate(), p); buffer.outer().push_back(p); } else { return; } } bg::correct(buffer); out = std::move(buffer); } template void areaFromEnu(const GeoPoint &origin, const Container1 &in, Container2 &out) { for (auto &vertex : in) { typename Container2::value_type p; fromENU(origin, vertex, p); out.push_back(p); } } template void areaFromEnu(const GeoPoint &origin, const FPolygon &in, Container &out) { for (auto &vertex : in.outer()) { typename Container::value_type p; fromENU(origin, vertex, p); out.push_back(p); } } void polygonCenter(const FPolygon &polygon, FPoint ¢er); bool minimalBoundingBox(const FPolygon &polygon, BoundingBox &minBBox); void offsetPolygon(const FPolygon &polygon, FPolygon &polygonOffset, double offset); void graphFromPolygon(const FPolygon &polygon, const FLineString &vertices, Matrix &graph); bool toDistanceMatrix(Matrix &graph); bool dijkstraAlgorithm(size_t numElements, size_t startIndex, size_t endIndex, std::vector &elementPath, double &length, std::function distanceDij); bool shortestPathFromGraph(const Matrix &graph, const size_t startIndex, const size_t endIndex, std::vector &pathIdx); typedef bu::quantity Length; typedef bu::quantity Area; typedef bu::quantity Angle; typedef bu::quantity Radian; typedef bu::quantity Degree; bool joinedArea(const std::vector &areas, FPolygon &jArea); bool joinedArea(const FPolygon &mArea, const FPolygon &sArea, const FPolygon &corridor, FPolygon &jArea, std::string &errorString); } // namespace geometry // operator== and operator!= for boost point namespace boost { namespace geometry { namespace model { bool operator==(::geometry::FPoint &p1, ::geometry::FPoint &p2); bool operator!=(::geometry::FPoint &p1, ::geometry::FPoint &p2); bool operator==(::geometry::IPoint &p1, ::geometry::IPoint &p2); bool operator!=(::geometry::IPoint &p1, ::geometry::IPoint &p2); } // namespace model } // namespace geometry } // namespace boost