diff options
-rw-r--r-- | include/mbgl/style/layers/custom_layer.hpp | 2 | ||||
-rw-r--r-- | package.json | 2 | ||||
-rw-r--r-- | platform/darwin/src/MGLGeometry.mm | 4 | ||||
-rw-r--r-- | platform/darwin/src/MGLOpenGLStyleLayer.h | 2 | ||||
-rw-r--r-- | platform/darwin/src/MGLOpenGLStyleLayer.mm | 2 | ||||
-rw-r--r-- | src/mbgl/map/transform_state.cpp | 34 | ||||
-rw-r--r-- | src/mbgl/map/transform_state.hpp | 9 | ||||
-rw-r--r-- | src/mbgl/programs/line_program.cpp | 2 | ||||
-rw-r--r-- | src/mbgl/programs/symbol_program.cpp | 6 | ||||
-rw-r--r-- | src/mbgl/renderer/painter_circle.cpp | 4 | ||||
-rw-r--r-- | src/mbgl/style/layers/custom_layer_impl.cpp | 2 | ||||
-rw-r--r-- | test/map/transform.test.cpp | 14 | ||||
-rw-r--r-- | test/util/tile_cover.test.cpp | 2 |
13 files changed, 49 insertions, 36 deletions
diff --git a/include/mbgl/style/layers/custom_layer.hpp b/include/mbgl/style/layers/custom_layer.hpp index 1b62f82a25..6bde087820 100644 --- a/include/mbgl/style/layers/custom_layer.hpp +++ b/include/mbgl/style/layers/custom_layer.hpp @@ -25,7 +25,7 @@ struct CustomLayerRenderParameters { double zoom; double bearing; double pitch; - double altitude; + double fieldOfView; }; /** diff --git a/package.json b/package.json index c537648251..c449c3ee48 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,7 @@ "ejs": "^2.4.1", "express": "^4.11.1", "lodash": "^4.16.4", - "mapbox-gl": "mapbox/mapbox-gl-js#c52a09639ceeeb809cd837360993df9c45b45420", + "mapbox-gl": "mapbox/mapbox-gl-js#eb6c6596c6a7a61363d30356674e0002153b1d19", "mapbox-gl-style-spec": "mapbox/mapbox-gl-style-spec#49e8b407bdbbe6f7c92dbcb56d3d51f425fc2653", "mapbox-gl-test-suite": "mapbox/mapbox-gl-test-suite#da53a81453068f4c2b440f9077d6bd5e7e14ff3d", "mkdirp": "^0.5.1", diff --git a/platform/darwin/src/MGLGeometry.mm b/platform/darwin/src/MGLGeometry.mm index 70f00afd2f..57922e30b9 100644 --- a/platform/darwin/src/MGLGeometry.mm +++ b/platform/darwin/src/MGLGeometry.mm @@ -5,8 +5,8 @@ /** 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°. + TransformState::getProjMatrix() has a variable vertical field of view that + defaults to 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; diff --git a/platform/darwin/src/MGLOpenGLStyleLayer.h b/platform/darwin/src/MGLOpenGLStyleLayer.h index 7cb6b147c2..8fbbd91854 100644 --- a/platform/darwin/src/MGLOpenGLStyleLayer.h +++ b/platform/darwin/src/MGLOpenGLStyleLayer.h @@ -14,7 +14,7 @@ typedef struct MGLStyleLayerDrawingContext { double zoomLevel; CLLocationDirection direction; CGFloat pitch; - CGFloat perspectiveSkew; + CGFloat fieldOfView; } MGLStyleLayerDrawingContext; @interface MGLOpenGLStyleLayer : MGLStyleLayer diff --git a/platform/darwin/src/MGLOpenGLStyleLayer.mm b/platform/darwin/src/MGLOpenGLStyleLayer.mm index f109ea85b0..745eacbf4e 100644 --- a/platform/darwin/src/MGLOpenGLStyleLayer.mm +++ b/platform/darwin/src/MGLOpenGLStyleLayer.mm @@ -34,7 +34,7 @@ void MGLDrawCustomStyleLayer(void *context, const mbgl::style::CustomLayerRender .zoomLevel = params.zoom, .direction = mbgl::util::wrap(params.bearing, 0., 360.), .pitch = static_cast<CGFloat>(params.pitch), - .perspectiveSkew = static_cast<CGFloat>(params.altitude), + .fieldOfView = static_cast<CGFloat>(params.fieldOfView), }; [layer drawInMapView:layer.mapView withContext:drawingContext]; } diff --git a/src/mbgl/map/transform_state.cpp b/src/mbgl/map/transform_state.cpp index 59ae129518..51ecf52e40 100644 --- a/src/mbgl/map/transform_state.cpp +++ b/src/mbgl/map/transform_state.cpp @@ -27,22 +27,24 @@ void TransformState::matrixFor(mat4& matrix, const UnwrappedTileID& tileID) cons } void TransformState::getProjMatrix(mat4& projMatrix) const { - double halfFov = std::atan(0.5 / getAltitude()); - double topHalfSurfaceDistance = std::sin(halfFov) * getAltitude() / - std::sin(M_PI / 2.0f - getPitch() - halfFov); - // Calculate z value of the farthest fragment that should be rendered. - double farZ = std::cos(M_PI / 2.0f - getPitch()) * topHalfSurfaceDistance + getAltitude(); - matrix::perspective(projMatrix, 2.0f * std::atan((size.height / 2.0f) / getAltitude()), - double(size.width) / size.height, 0.1, farZ); + // Find the distance from the center point [width/2, height/2] to the + // center top point [width/2, 0] in Z units, using the law of sines. + // 1 Z unit is equivalent to 1 horizontal px at the center of the map + // (the distance between[width/2, height/2] and [width/2 + 1, height/2]) + const double halfFov = getFieldOfView() / 2.0; + const double groundAngle = M_PI / 2.0 + getPitch(); + const double topHalfSurfaceDistance = std::sin(halfFov) * getCameraToCenterDistance() / std::sin(M_PI - groundAngle - halfFov); + + // Calculate z value of the farthest fragment that should be rendered. + const double farZ = std::cos(M_PI / 2.0 - getPitch()) * topHalfSurfaceDistance + getCameraToCenterDistance(); - matrix::translate(projMatrix, projMatrix, 0, 0, -getAltitude()); + matrix::perspective(projMatrix, getFieldOfView(), double(size.width) / size.height, 0.1, farZ); - // After the rotateX, z values are in pixel units. Convert them to - // altitude unites. 1 altitude unit = the screen height. const bool flippedY = viewportMode == ViewportMode::FlippedY; - matrix::scale(projMatrix, projMatrix, 1, flippedY ? 1 : -1, - 1.0f / (rotatedNorth() ? size.width : size.height)); + matrix::scale(projMatrix, projMatrix, 1, flippedY ? 1 : -1, 1); + + matrix::translate(projMatrix, projMatrix, 0, 0, -getCameraToCenterDistance()); using NO = NorthOrientation; switch (getNorthOrientation()) { @@ -164,8 +166,12 @@ float TransformState::getAngle() const { return angle; } -float TransformState::getAltitude() const { - return altitude; +float TransformState::getFieldOfView() const { + return fov; +} + +float TransformState::getCameraToCenterDistance() const { + return 0.5 * size.height / std::tan(fov / 2.0); } float TransformState::getPitch() const { diff --git a/src/mbgl/map/transform_state.hpp b/src/mbgl/map/transform_state.hpp index 6faaf4ac41..a35aa5a255 100644 --- a/src/mbgl/map/transform_state.hpp +++ b/src/mbgl/map/transform_state.hpp @@ -56,7 +56,8 @@ public: // Rotation float getAngle() const; - float getAltitude() const; + float getFieldOfView() const; + float getCameraToCenterDistance() const; float getPitch() const; // State @@ -109,7 +110,11 @@ private: double x = 0, y = 0; double angle = 0; double scale = 1; - double altitude = 1.5; + // This fov value is somewhat arbitrary. The altitude of the camera used + // to be defined as 1.5 screen heights above the ground, which was an + // arbitrary choice. This is the fov equivalent to that value calculated with: + // `fov = 2 * arctan((height / 2) / (height * 1.5))` + double fov = 0.6435011087932844; double pitch = 0.0; // cache values for spherical mercator math diff --git a/src/mbgl/programs/line_program.cpp b/src/mbgl/programs/line_program.cpp index 2cadaa6c11..cd53337c10 100644 --- a/src/mbgl/programs/line_program.cpp +++ b/src/mbgl/programs/line_program.cpp @@ -25,7 +25,7 @@ Values makeValues(const LinePaintProperties::Evaluated& properties, // calculate how much longer the real world distance is at the top of the screen // than at the middle of the screen. - float topedgelength = std::sqrt(std::pow(state.getSize().height, 2.0f) / 4.0f * (1.0f + std::pow(state.getAltitude(), 2.0f))); + float topedgelength = std::sqrt(std::pow(state.getSize().height, 2.0f) / 4.0f * (1.0f + std::pow(state.getCameraToCenterDistance(), 2.0f))); float x = state.getSize().height / 2.0f * std::tan(state.getPitch()); return Values { diff --git a/src/mbgl/programs/symbol_program.cpp b/src/mbgl/programs/symbol_program.cpp index 71b45ad4fc..d609dada8d 100644 --- a/src/mbgl/programs/symbol_program.cpp +++ b/src/mbgl/programs/symbol_program.cpp @@ -23,8 +23,8 @@ Values makeValues(const style::SymbolPropertyValues& values, extrudeScale.fill(tile.id.pixelsToTileUnits(1, state.getZoom()) * scale); } else { extrudeScale = {{ - pixelsToGLUnits[0] * scale * state.getAltitude(), - pixelsToGLUnits[1] * scale * state.getAltitude() + pixelsToGLUnits[0] * scale * state.getCameraToCenterDistance(), + pixelsToGLUnits[1] * scale * state.getCameraToCenterDistance() }}; } @@ -77,7 +77,7 @@ static SymbolSDFProgram::UniformValues makeSDFValues(const style::SymbolProperty const float gammaBase = 0.105 * values.sdfScale / values.paintSize / pixelRatio; const float gammaScale = (values.pitchAlignment == AlignmentType::Map ? 1.0 / std::cos(state.getPitch()) - : 1.0) / state.getAltitude(); + : 1.0) / state.getCameraToCenterDistance(); return makeValues<SymbolSDFProgram::UniformValues>( values, diff --git a/src/mbgl/renderer/painter_circle.cpp b/src/mbgl/renderer/painter_circle.cpp index 9385b7b1a3..966d58b59b 100644 --- a/src/mbgl/renderer/painter_circle.cpp +++ b/src/mbgl/renderer/painter_circle.cpp @@ -47,8 +47,8 @@ void Painter::renderCircle(PaintParameters& parameters, uniforms::u_scale_with_map::Value{ scaleWithMap }, uniforms::u_extrude_scale::Value{ scaleWithMap ? std::array<float, 2> {{ - pixelsToGLUnits[0] * state.getAltitude(), - pixelsToGLUnits[1] * state.getAltitude() + pixelsToGLUnits[0] * state.getCameraToCenterDistance(), + pixelsToGLUnits[1] * state.getCameraToCenterDistance() }} : pixelsToGLUnits } }, diff --git a/src/mbgl/style/layers/custom_layer_impl.cpp b/src/mbgl/style/layers/custom_layer_impl.cpp index 3f11943478..baf55205c4 100644 --- a/src/mbgl/style/layers/custom_layer_impl.cpp +++ b/src/mbgl/style/layers/custom_layer_impl.cpp @@ -57,7 +57,7 @@ void CustomLayer::Impl::render(const TransformState& state) const { parameters.zoom = state.getZoom(); parameters.bearing = -state.getAngle() * util::RAD2DEG; parameters.pitch = state.getPitch(); - parameters.altitude = state.getAltitude(); + parameters.fieldOfView = state.getFieldOfView(); renderFn(context, parameters); } diff --git a/test/map/transform.test.cpp b/test/map/transform.test.cpp index 7f3a5e0556..d5b98ac109 100644 --- a/test/map/transform.test.cpp +++ b/test/map/transform.test.cpp @@ -362,7 +362,7 @@ TEST(Transform, Padding) { const LatLng shiftedCenter = transform.getLatLng(padding); ASSERT_NE(trueCenter.latitude, shiftedCenter.latitude); - ASSERT_DOUBLE_EQ(trueCenter.longitude, shiftedCenter.longitude); + ASSERT_NEAR(trueCenter.longitude, shiftedCenter.longitude, 1e-9); ASSERT_DOUBLE_EQ(manualShiftedCenter.latitude, shiftedCenter.latitude); ASSERT_DOUBLE_EQ(manualShiftedCenter.longitude, shiftedCenter.longitude); } @@ -401,12 +401,12 @@ TEST(Transform, Antimeridian) { const LatLng coordinateSanFrancisco { 37.7833, -122.4167 }; ScreenCoordinate pixelSF = transform.latLngToScreenCoordinate(coordinateSanFrancisco); - ASSERT_DOUBLE_EQ(151.79409149185352, pixelSF.x); - ASSERT_DOUBLE_EQ(383.76774094913071, pixelSF.y); + ASSERT_NEAR(151.79409149185352, pixelSF.x, 1e-2); + ASSERT_NEAR(383.76774094913071, pixelSF.y, 1e-2); transform.setLatLng({ 0, -181 }); ScreenCoordinate pixelSFBackwards = transform.latLngToScreenCoordinate(coordinateSanFrancisco); - ASSERT_DOUBLE_EQ(666.63617954008976, pixelSFBackwards.x); + ASSERT_NEAR(666.63617954008976, pixelSFBackwards.x, 1e-2); ASSERT_DOUBLE_EQ(pixelSF.y, pixelSFBackwards.y); transform.setLatLng({ 0, 179 }); @@ -417,12 +417,12 @@ TEST(Transform, Antimeridian) { const LatLng coordinateWaikiri{ -16.9310, 179.9787 }; transform.setLatLngZoom(coordinateWaikiri, 10); ScreenCoordinate pixelWaikiri = transform.latLngToScreenCoordinate(coordinateWaikiri); - ASSERT_DOUBLE_EQ(500.00000000007759, pixelWaikiri.x); - ASSERT_DOUBLE_EQ(500, pixelWaikiri.y); + ASSERT_NEAR(500, pixelWaikiri.x, 1e-2); + ASSERT_NEAR(500, pixelWaikiri.y, 1e-2); transform.setLatLng({ coordinateWaikiri.latitude, 180.0213 }); ScreenCoordinate pixelWaikiriForwards = transform.latLngToScreenCoordinate(coordinateWaikiri); - ASSERT_DOUBLE_EQ(437.95953728819512, pixelWaikiriForwards.x); + ASSERT_NEAR(437.95953728819512, pixelWaikiriForwards.x, 1e-2); ASSERT_DOUBLE_EQ(pixelWaikiri.y, pixelWaikiriForwards.y); LatLng coordinateFromPixel = transform.screenCoordinateToLatLng(pixelWaikiriForwards); ASSERT_NEAR(coordinateWaikiri.latitude, coordinateFromPixel.latitude, 0.000001); diff --git a/test/util/tile_cover.test.cpp b/test/util/tile_cover.test.cpp index 47440ff0b5..809b7df9f2 100644 --- a/test/util/tile_cover.test.cpp +++ b/test/util/tile_cover.test.cpp @@ -30,6 +30,8 @@ TEST(TileCover, WorldZ0) { TEST(TileCover, Pitch) { Transform transform; transform.resize({ 512, 512 }); + // slightly offset center so that tile order is better defined + transform.setLatLng({ 0.01, -0.01 }); transform.setZoom(2); transform.setPitch(40.0 * M_PI / 180.0); |