1 #include <mbgl/util/geo.hpp>
2 #include <mbgl/util/constants.hpp>
3 #include <mbgl/tile/tile_id.hpp>
4 #include <mbgl/math/clamp.hpp>
5 #include <mbgl/util/tile_range.hpp>
6 
7 #include <cmath>
8 
9 namespace mbgl {
10 
11 namespace {
12 
lat_(const uint8_t z,const int64_t y)13 double lat_(const uint8_t z, const int64_t y) {
14     const double n = M_PI - 2.0 * M_PI * y / std::pow(2.0, z);
15     return util::RAD2DEG * std::atan(0.5 * (std::exp(n) - std::exp(-n)));
16 }
17 
lon_(const uint8_t z,const int64_t x)18 double lon_(const uint8_t z, const int64_t x) {
19     return x / std::pow(2.0, z) * util::DEGREES_MAX - util::LONGITUDE_MAX;
20 }
21 
22 } // end namespace
23 
LatLng(const CanonicalTileID & id)24 LatLng::LatLng(const CanonicalTileID& id) : lat(lat_(id.z, id.y)), lon(lon_(id.z, id.x)) {
25 }
26 
LatLng(const UnwrappedTileID & id)27 LatLng::LatLng(const UnwrappedTileID& id)
28     : lat(lat_(id.canonical.z, id.canonical.y)),
29       lon(lon_(id.canonical.z, id.canonical.x) + id.wrap * util::DEGREES_MAX) {
30 }
31 
LatLngBounds(const CanonicalTileID & id)32 LatLngBounds::LatLngBounds(const CanonicalTileID& id)
33     : sw({ lat_(id.z, id.y + 1), lon_(id.z, id.x) }),
34       ne({ lat_(id.z, id.y), lon_(id.z, id.x + 1) }) {
35 }
36 
contains(const CanonicalTileID & tileID) const37 bool LatLngBounds::contains(const CanonicalTileID& tileID) const {
38     return util::TileRange::fromLatLngBounds(*this, tileID.z).contains(tileID);
39 }
40 
contains(const LatLng & point,LatLng::WrapMode wrap) const41 bool LatLngBounds::contains(const LatLng& point, LatLng::WrapMode wrap /*= LatLng::Unwrapped*/) const {
42     bool containsLatitude = point.latitude() >= sw.latitude() &&
43                             point.latitude() <= ne.latitude();
44     if (!containsLatitude) {
45         return false;
46     }
47 
48     bool containsUnwrappedLongitude = point.longitude() >= sw.longitude() &&
49                                       point.longitude() <= ne.longitude();
50     if (containsUnwrappedLongitude) {
51         return true;
52     } else if (wrap == LatLng::Wrapped) {
53         LatLngBounds wrapped(sw.wrapped(), ne.wrapped());
54         auto ptLon = point.wrapped().longitude();
55         if (crossesAntimeridian()) {
56             return (ptLon >= wrapped.sw.longitude() &&
57                     ptLon <= util::LONGITUDE_MAX) ||
58                    (ptLon <= wrapped.ne.longitude() &&
59                     ptLon >= -util::LONGITUDE_MAX);
60         } else {
61             return (ptLon >= wrapped.sw.longitude() &&
62                     ptLon <= wrapped.ne.longitude());
63         }
64     }
65     return false;
66 }
67 
contains(const LatLngBounds & area,LatLng::WrapMode wrap) const68 bool LatLngBounds::contains(const LatLngBounds& area, LatLng::WrapMode wrap /*= LatLng::Unwrapped*/) const {
69     bool containsLatitude = area.north() <= north() && area.south() >= south();
70     if (!containsLatitude) {
71         return false;
72     }
73 
74     bool containsUnwrapped = area.east() <= east() && area.west() >= west();
75     if(containsUnwrapped) {
76         return true;
77     } else if (wrap == LatLng::Wrapped) {
78         LatLngBounds wrapped(sw.wrapped(), ne.wrapped());
79         LatLngBounds other(area.sw.wrapped(), area.ne.wrapped());
80         if (crossesAntimeridian() & !area.crossesAntimeridian()) {
81             return (other.east() <= util::LONGITUDE_MAX && other.west() >= wrapped.west()) ||
82                    (other.east() <= wrapped.east() && other.west() >= -util::LONGITUDE_MAX);
83         } else {
84             return other.east() <= wrapped.east() && other.west() >= wrapped.west();
85         }
86     }
87     return false;
88 }
89 
intersects(const LatLngBounds area,LatLng::WrapMode wrap) const90 bool LatLngBounds::intersects(const LatLngBounds area, LatLng::WrapMode wrap /*= LatLng::Unwrapped*/) const {
91     bool latitudeIntersects = area.north() > south() && area.south() < north();
92     if (!latitudeIntersects) {
93         return false;
94     }
95 
96     bool longitudeIntersects = area.east() > west() && area.west() < east();
97     if (longitudeIntersects) {
98         return true;
99     } else if (wrap == LatLng::Wrapped) {
100         LatLngBounds wrapped(sw.wrapped(), ne.wrapped());
101         LatLngBounds other(area.sw.wrapped(), area.ne.wrapped());
102         if (crossesAntimeridian()) {
103             return area.crossesAntimeridian() ||
104                    other.east() > wrapped.west() ||
105                    other.west() < wrapped.east();
106         } else if (other.crossesAntimeridian()){
107             return other.east() > wrapped.west() ||
108                    other.west() < wrapped.east();
109         } else {
110             return other.east() > wrapped.west() &&
111                    other.west() < wrapped.east();
112         }
113     }
114     return false;
115 }
116 
getCenter(uint16_t width,uint16_t height) const117 ScreenCoordinate EdgeInsets::getCenter(uint16_t width, uint16_t height) const {
118     return {
119         (width - left() - right()) / 2.0 + left(),
120         (height - top() - bottom()) / 2.0 + top(),
121     };
122 }
123 
124 } // end namespace mbgl
125