#pragma once #include #include #include #include #include #include #include #include #include namespace mbgl { class CanonicalTileID; class UnwrappedTileID; using ScreenCoordinate = mapbox::geometry::point; using ScreenLineString = mapbox::geometry::line_string; using ScreenBox = mapbox::geometry::box; class LatLng { private: double lat; double lon; public: enum WrapMode : bool { Unwrapped, Wrapped }; LatLng(double lat_ = 0, double lon_ = 0, WrapMode mode = Unwrapped) : lat(lat_), lon(lon_) { if (std::isnan(lat)) { throw std::domain_error("latitude must not be NaN"); } if (std::isnan(lon)) { throw std::domain_error("longitude must not be NaN"); } if (std::abs(lat) > 90.0) { throw std::domain_error("latitude must be between -90 and 90"); } if (!std::isfinite(lon)) { throw std::domain_error("longitude must not be infinite"); } if (mode == Wrapped) { wrap(); } } double latitude() const { return lat; } double longitude() const { return lon; } LatLng wrapped() const { return { lat, lon, Wrapped }; } void wrap() { lon = util::wrap(lon, -util::LONGITUDE_MAX, util::LONGITUDE_MAX); } // If the distance from start to end longitudes is between half and full // world, unwrap the start longitude to ensure the shortest path is taken. void unwrapForShortestPath(const LatLng& end) { const double delta = std::abs(end.lon - lon); if (delta <= util::LONGITUDE_MAX || delta >= util::DEGREES_MAX) return; if (lon > 0 && end.lon < 0) lon -= util::DEGREES_MAX; else if (lon < 0 && end.lon > 0) lon += util::DEGREES_MAX; } // Constructs a LatLng object with the top left position of the specified tile. LatLng(const CanonicalTileID& id); LatLng(const UnwrappedTileID& id); friend bool operator==(const LatLng& a, const LatLng& b) { return a.lat == b.lat && a.lon == b.lon; } friend bool operator!=(const LatLng& a, const LatLng& b) { return !(a == b); } }; class LatLngBounds { public: // Return a bounds covering the entire (unwrapped) world. static LatLngBounds world() { return {{-90, -180}, {90, 180}}; } // Return the bounds consisting of the single point. static LatLngBounds singleton(const LatLng& a) { return {a, a}; } // Return the convex hull of two points; the smallest bounds that contains both. static LatLngBounds hull(const LatLng& a, const LatLng& b) { LatLngBounds bounds(a, a); bounds.extend(b); return bounds; } // Return a bounds that may serve as the identity element for the extend operation. static LatLngBounds empty() { LatLngBounds bounds = world(); std::swap(bounds.sw, bounds.ne); return bounds; } /// Construct an infinite bound, a bound for which the constrain method returns its /// input unmodified. /// /// Note: this is different than LatLngBounds::world() since arbitrary unwrapped /// coordinates are also inside the bounds. LatLngBounds() : sw({-90, -180}), ne({90, 180}), bounded(false) {} // Constructs a LatLngBounds object with the tile's exact boundaries. LatLngBounds(const CanonicalTileID&); bool valid() const { return (sw.latitude() <= ne.latitude()) && (sw.longitude() <= ne.longitude()); } double south() const { return sw.latitude(); } double west() const { return sw.longitude(); } double north() const { return ne.latitude(); } double east() const { return ne.longitude(); } LatLng southwest() const { return sw; } LatLng northeast() const { return ne; } LatLng southeast() const { return {south(), east()}; } LatLng northwest() const { return {north(), west()}; } LatLng center() const { return {(sw.latitude() + ne.latitude()) / 2, (sw.longitude() + ne.longitude()) / 2}; } LatLng constrain(const LatLng& p) const; void extend(const LatLng& point) { sw = LatLng(std::min(point.latitude(), sw.latitude()), std::min(point.longitude(), sw.longitude())); ne = LatLng(std::max(point.latitude(), ne.latitude()), std::max(point.longitude(), ne.longitude())); } void extend(const LatLngBounds& bounds) { extend(bounds.sw); extend(bounds.ne); } bool isEmpty() const { return sw.latitude() > ne.latitude() || sw.longitude() > ne.longitude(); } bool crossesAntimeridian() const { return (sw.wrapped().longitude() > ne.wrapped().longitude()); } bool contains(const CanonicalTileID& tileID) const; bool contains(const LatLng& point, LatLng::WrapMode wrap = LatLng::Unwrapped) const; bool contains(const LatLngBounds& area, LatLng::WrapMode wrap = LatLng::Unwrapped) const; bool intersects(LatLngBounds area, LatLng::WrapMode wrap = LatLng::Unwrapped) const; private: LatLng sw; LatLng ne; bool bounded = true; LatLngBounds(LatLng sw_, LatLng ne_) : sw(sw_), ne(ne_) {} bool containsLatitude(double latitude) const; bool containsLongitude(double longitude, LatLng::WrapMode wrap) const; friend bool operator==(const LatLngBounds& a, const LatLngBounds& b) { return (!a.bounded && !b.bounded) || (a.bounded && b.bounded && a.sw == b.sw && a.ne == b.ne); } friend bool operator!=(const LatLngBounds& a, const LatLngBounds& b) { return !(a == b); } }; // Determines the orientation of the map. enum class NorthOrientation : uint8_t { Upwards, // Default Rightwards, Downwards, Leftwards, }; /// The distance on each side between a rectangle and a rectangle within. class EdgeInsets { private: double _top; // Number of pixels inset from the top edge. double _left; // Number of pixels inset from the left edge. double _bottom; // Number of pixels inset from the bottom edge. double _right; // Number of pixels inset from the right edge. public: EdgeInsets(double t_ = 0, double l_ = 0, double b_ = 0, double r_ = 0) : _top(t_), _left(l_), _bottom(b_), _right(r_) { if (std::isnan(_top)) { throw std::domain_error("top must not be NaN"); } if (std::isnan(_left)) { throw std::domain_error("left must not be NaN"); } if (std::isnan(_bottom)) { throw std::domain_error("bottom must not be NaN"); } if (std::isnan(_right)) { throw std::domain_error("right must not be NaN"); } } double top() const { return _top; } double left() const { return _left; } double bottom() const { return _bottom; } double right() const { return _right; } bool isFlush() const { return _top == 0 && _left == 0 && _bottom == 0 && _right == 0; } void operator+=(const EdgeInsets& o) { _top += o._top; _left += o._left; _bottom += o._bottom; _right += o._right; } EdgeInsets operator+(const EdgeInsets& o) const { return { _top + o._top, _left + o._left, _bottom + o._bottom, _right + o._right, }; } ScreenCoordinate getCenter(uint16_t width, uint16_t height) const; friend bool operator==(const EdgeInsets& a, const EdgeInsets& b) { return a._top == b._top && a._left == b._left && a._bottom == b._bottom && a._right == b._right; } friend bool operator!=(const EdgeInsets& a, const EdgeInsets& b) { return !(a == b); } }; struct LatLngAltitude { LatLng location = {0.0, 0.0}; double altitude = 0.0; }; } // namespace mbgl