summaryrefslogtreecommitdiff
path: root/platform/darwin
diff options
context:
space:
mode:
authorMinh Nguyễn <mxn@1ec5.org>2015-12-20 01:22:52 -0800
committerMinh Nguyễn <mxn@1ec5.org>2015-12-20 03:57:28 -0800
commitd668c0fa8482c86a2a73e5fc9661e32d89f26c56 (patch)
tree08fe4d5a1467f774d95af298be2f54a127355cdf /platform/darwin
parentcafe591d2a84d70a2a6c076b9629135e42e68f46 (diff)
downloadqtlocation-mapboxgl-d668c0fa8482c86a2a73e5fc9661e32d89f26c56.tar.gz
[ios, osx] Better zoom level–altitude conversion
Greatly simplified conversions between zoom level and altitude. Adjusted field of view to more closely match MapKit. Conversions are now well within the same order of magnitude as MapKit at all latitudes. Fixes #2266.
Diffstat (limited to 'platform/darwin')
-rw-r--r--platform/darwin/MGLGeometry.mm25
-rw-r--r--platform/darwin/MGLGeometry_Private.h18
2 files changed, 43 insertions, 0 deletions
diff --git a/platform/darwin/MGLGeometry.mm b/platform/darwin/MGLGeometry.mm
index b80203d142..70f00afd2f 100644
--- a/platform/darwin/MGLGeometry.mm
+++ b/platform/darwin/MGLGeometry.mm
@@ -1,5 +1,15 @@
#import "MGLGeometry_Private.h"
+#import <mbgl/util/projection.hpp>
+
+/** Vertical field of view, measured in degrees, for determining the altitude
+ of the viewpoint.
+
+ TransformState::getProjMatrix() assumes a vertical field of view of
+ 2 arctan ⅓ rad ≈ 36.9°, but MapKit uses a vertical field of view of 30°.
+ flyTo() assumes a field of view of 2 arctan ½ rad. */
+const CLLocationDegrees MGLAngularFieldOfView = 30;
+
const MGLCoordinateSpan MGLCoordinateSpanZero = {0, 0};
CGRect MGLExtendRect(CGRect rect, CGPoint point) {
@@ -19,3 +29,18 @@ CGRect MGLExtendRect(CGRect rect, CGPoint point) {
}
return rect;
}
+
+CLLocationDistance MGLAltitudeForZoomLevel(double zoomLevel, CGFloat pitch, CLLocationDegrees latitude, CGSize size) {
+ CLLocationDistance metersPerPixel = mbgl::Projection::getMetersPerPixelAtLatitude(latitude, zoomLevel);
+ CLLocationDistance metersTall = metersPerPixel * size.height;
+ CLLocationDistance altitude = metersTall / 2 / std::tan(MGLRadiansFromDegrees(MGLAngularFieldOfView) / 2.);
+ return altitude * std::sin(M_PI_2 - MGLRadiansFromDegrees(pitch)) / std::sin(M_PI_2);
+}
+
+double MGLZoomLevelForAltitude(CLLocationDistance altitude, CGFloat pitch, CLLocationDegrees latitude, CGSize size) {
+ CLLocationDistance eyeAltitude = altitude / std::sin(M_PI_2 - MGLRadiansFromDegrees(pitch)) * std::sin(M_PI_2);
+ CLLocationDistance metersTall = eyeAltitude * 2 * std::tan(MGLRadiansFromDegrees(MGLAngularFieldOfView) / 2.);
+ CLLocationDistance metersPerPixel = metersTall / size.height;
+ CGFloat mapPixelWidthAtZoom = std::cos(MGLRadiansFromDegrees(latitude)) * mbgl::util::M2PI * mbgl::util::EARTH_RADIUS_M / metersPerPixel;
+ return ::log2(mapPixelWidthAtZoom / mbgl::util::tileSize);
+}
diff --git a/platform/darwin/MGLGeometry_Private.h b/platform/darwin/MGLGeometry_Private.h
index 49a306701d..bf5bc4e0ff 100644
--- a/platform/darwin/MGLGeometry_Private.h
+++ b/platform/darwin/MGLGeometry_Private.h
@@ -44,3 +44,21 @@ NS_INLINE mbgl::EdgeInsets MGLEdgeInsetsFromNSEdgeInsets(NSEdgeInsets insets) {
return { insets.top, insets.left, insets.bottom, insets.right };
}
#endif
+
+/** Converts a map zoom level to a camera altitude.
+
+ @param zoomLevel The zoom level to convert.
+ @param pitch The camera pitch, measured in degrees.
+ @param latitude The latitude of the point at the center of the viewport.
+ @param size The size of the viewport.
+ @return An altitude measured in meters. */
+CLLocationDistance MGLAltitudeForZoomLevel(double zoomLevel, CGFloat pitch, CLLocationDegrees latitude, CGSize size);
+
+/** Converts a camera altitude to a map zoom level.
+
+ @param altitude The altitude to convert, measured in meters.
+ @param pitch The camera pitch, measured in degrees.
+ @param latitude The latitude of the point at the center of the viewport.
+ @param size The size of the viewport.
+ @return A zero-based zoom level. */
+double MGLZoomLevelForAltitude(CLLocationDistance altitude, CGFloat pitch, CLLocationDegrees latitude, CGSize size);