Skip to content
This repository has been archived by the owner on Aug 8, 2023. It is now read-only.

[core] Asymmetric viewport when edge insets are specified #14664

Merged
merged 2 commits into from
May 28, 2019

Conversation

astojilj
Copy link
Contributor

@astojilj astojilj commented May 14, 2019

The change is implemented in TransformState::getProjMatrix, the rest of the code is making sure that existing API contracts stay and there are tests verifyingrendering and render query processing only items within screen and given tolerance around screen edges.

MapView: don't bake edge insets into relalculated camera center. Keep edge insets as property of camera in TransformState (similar to pitch, zoom, bearing) independent from specified camera center. Interpolate edge insets in animation.

iOS Demo app: "Turn On/Off Content Insets" pitch the camera and navigate to convenient location in Denver, where streets are parallel to cardinal directions, to illustrate viewport center offset when edge insets are set.

Tests:
ViewFrustumCulling: although Annotations are deprecated, queryRenderedFeatures related tests in Annotations would need to get ported and decided to add the edge insets related query tests next to them. Verify frustum culling (render+queryRenderedFeatures) With different camera and edge insets setups. TODO: port Annotations tests.

Transform.Padding: Verify that coordinates take proper place on screen after applying edge insets.

LocalGlyphRasterizer: verify text rendering when applying padding.

Related to #11882: both use projection matrix elements [8] and [9].

Alternative approach to this was to increase and offset map origin so that the screen would be a sub-rectangle in larger map viewport. This approach has a drawback of unecessary processing the items that are outside screen area.

Addreses: mapbox/mapbox-navigation-ios#1845

Fixes: #12728, #12107, https://github.com/mapbox/navigation-sdks/issues/120, #14362

Example1: Turn on/off content half-width left edge inset in horizontal mode. Two finger rotate at the end.
Image

Example2: quarter-height top and quarter width right edge insets.
Image

Copy link
Contributor

@pozdnyakov pozdnyakov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

core LGTM

@julianrex julianrex requested review from d-prukop and fabian-guerra and removed request for a team May 16, 2019 14:55
@julianrex
Copy link
Contributor

@fabian-guerra @d-prukop would you mind looking at this from the SDKs' POV please?

@astojilj
Copy link
Contributor Author

@fabian-guerra , @d-prukop, @frederoni
This fixes issues noticeable on iOS as e.g. iPhone X always has edge insets specified: top inset is larger in portrait mode.

The issue #14362 explains the problem well; user specify camera parameters, but because there is content inset, camera values that user reads back are not the same as specified (inset moves center).

I put focus on honouring existing SDK documentation and contracts and find that the code is in line with it. Render tests pass :)

However, I "might" have stretched the interpretation of the documentation. Please comment:

MGLMapCamera.centerCoordinate

Coordinate at the center of the map view.

It doesn't say center of screen and edge insets documentation further confirms it:

Edge Insets:

The distance from the edges of the map view’s frame to the edges of the map view’s logical viewport. When the value of this property is equal to UIEdgeInsetsZero, viewport properties such as centerCoordinate assume a viewport that matches the map view’s frame. Otherwise, those properties are inset, excluding part of the frame from the viewport. For instance, if the only the top edge is inset, the map center is effectively shifted downward.

This is how I interpreted terms map, map view and map view's frame:
It clearly states that the center of map is shifted. Center of map is the same as center of the map view.
Center of map view is then not the same as center of map's view frame (screen).

I wouldn't use both camera viewport center and center of view in documentation - only viewport should suffice and some of the complicated explanations, like the one above, could be trimmed.
Anyway, I need your opinion here. Thanks.

@1ec5
Copy link
Contributor

1ec5 commented May 17, 2019

It doesn't say center of screen and edge insets documentation further confirms it:

Right, MGLMapCamera.centerCoordinate matches MGLMapView.centerCoordinate, which already accounts for any edge padding. If the developer needs the absolute center without accounting for edge padding, they need to pass UIView.center into -[MGLMapView convertPoint:toCoordinateFromView:].

Copy link
Contributor

@fabian-guerra fabian-guerra left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for fixing this. I added some nits and a question. Also could you please add an entry in the changelogs.

platform/ios/app/MBXViewController.m Outdated Show resolved Hide resolved
platform/ios/app/MBXViewController.m Outdated Show resolved Hide resolved
platform/ios/src/MGLMapView.mm Outdated Show resolved Hide resolved
platform/ios/src/MGLMapView.mm Show resolved Hide resolved
platform/ios/src/MGLMapView.mm Outdated Show resolved Hide resolved
@astojilj
Copy link
Contributor Author

astojilj commented May 23, 2019

@tobrun,
I have verified this on Android using Mapbox Android SDK TestApp's Map Padding activity: zoomed out to Denver (Denver streets parallel to cardinal directions), tilted the map and aligned to north. On image before (with master) it is obvious that projection center is in the middle of the screen while, with the patch, it is in the center of padded area.
Note that there was no Android specific code changed.
Screenshot 2019-05-23 at 16 23 18

Copy link
Contributor

@fabian-guerra fabian-guerra left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a minor blurb change. LGTM.

platform/ios/CHANGELOG.md Outdated Show resolved Hide resolved
@astojilj astojilj force-pushed the astojilj-center-offset branch 2 times, most recently from 4e6cd24 to 7a9ce6c Compare May 28, 2019 09:29
@tobrun
Copy link
Member

tobrun commented May 28, 2019

re #14664 (comment), looks great @astojilj!

The change is implemented in TransformState::getProjMatrix, the rest of the code is making sure that existing API contracts stay and there are tests verifyingrendering and render query processing only items within screen and given tolerance around screen edges.

MapView: don't bake edge insets into relalculated camera center. Keep edge insets as property of camera in TransformState (similar to pitch, zoom, bearing) independent from specified camera center. Interpolate edge insets in animation.

iOS Demo app: "Turn On/Off Content Insets" pitch the camera and navigate to convenient location in Denver, where streets are parallel to cardinal directions, to illustrate viewport center offset when edge insets are set.

Tests:
ViewFrustumCulling: although Annotations are deprecated, queryRenderedFeatures related tests in Annotations would need to get ported and decided to add the edge insets related query tests next to them. Verify frustum culling (render+queryRenderedFeatures) With different camera and edge insets setups. TODO: port Annotations tests.

Transform.Padding: Verify that coordinates take proper place on screen after applying edge insets.

LocalGlyphRasterizer: verify text rendering when applying padding.

Related to #11882: both use projection matrix elements [8] and [9].

Alternative approach to this was to increase and offset map origin so that the screen would be a sub-rectangle in larger map viewport. This approach has a drawback of unecessary processing the items that are outside screen area.

Fixes #12107, #12728, navigation-sdks/issues/120
Check edge insets difference, in addition to isEqualToMapCamera in all the places in MGLMapView before map.easeTo/map.flyTo.
@astojilj astojilj merged commit e5431d0 into master May 28, 2019
@kkaefer kkaefer deleted the astojilj-center-offset branch May 28, 2019 12:13
platform/ios/CHANGELOG.md Show resolved Hide resolved
platform/macos/CHANGELOG.md Show resolved Hide resolved
astojilj added a commit that referenced this pull request Jun 3, 2019
Allows changing camera when user duplicates content insets.

Related to previous patch and comment:
#14664 (review)
Thanks @1ec5
astojilj added a commit that referenced this pull request Jul 10, 2019
To changelog:
Fixed incorrect center coordinate after pinch regression caused by edge insets fix (#14664).

While working on #14664, missed to understand the logic used in

```
                CLLocationCoordinate2D centerCoordinate = _previousPinchCenterCoordinate;
                mbgl::EdgeInsets padding { centerPoint.y, centerPoint.x, self.size.height - centerPoint.y, self.size.width - centerPoint.x };
                self.mbglMap.jumpTo(mbgl::CameraOptions()
                                        .withCenter(MGLLatLngFromLocationCoordinate2D(centerCoordinate))
                                        .withPadding(padding));

```

Replacing this code by moveBy achieves the required translation.

Fixes: #14977, #15082
friedbunny pushed a commit that referenced this pull request Jul 13, 2019
To changelog:
Fixed incorrect center coordinate after pinch regression caused by edge insets fix (#14664).

While working on #14664, missed to understand the logic used in

```
                CLLocationCoordinate2D centerCoordinate = _previousPinchCenterCoordinate;
                mbgl::EdgeInsets padding { centerPoint.y, centerPoint.x, self.size.height - centerPoint.y, self.size.width - centerPoint.x };
                self.mbglMap.jumpTo(mbgl::CameraOptions()
                                        .withCenter(MGLLatLngFromLocationCoordinate2D(centerCoordinate))
                                        .withPadding(padding));

```

Replacing this code by moveBy achieves the required translation.

Fixes: #14977, #15082
astojilj added a commit that referenced this pull request Jul 14, 2019
To changelog:
Fixed incorrect center coordinate after pinch regression caused by edge insets fix (#14664).

While working on #14664, missed to understand the logic used in

```
                CLLocationCoordinate2D centerCoordinate = _previousPinchCenterCoordinate;
                mbgl::EdgeInsets padding { centerPoint.y, centerPoint.x, self.size.height - centerPoint.y, self.size.width - centerPoint.x };
                self.mbglMap.jumpTo(mbgl::CameraOptions()
                                        .withCenter(MGLLatLngFromLocationCoordinate2D(centerCoordinate))
                                        .withPadding(padding));

```

Replacing this code by moveBy achieves the required translation.

Fixes: #14977, #15082
astojilj added a commit that referenced this pull request Jul 16, 2019
Viewport center offset usage was wrongly submitted in #14664. It was part of alternative approach that used enlarged viewport. Existing and added tests were not sufficient to spot the regression, since the collision check padding is usually larger than the center offset x and y. Annotation picking has tolerance of only 10 pixels but no annotation integration test was using content insets.

Usage of offset is not needed because `posMatrix` in e.g. `CollisionIndex::projectPoint(const mat4& posMatrix, const Point<float>& point)` already incorporates center offset (projection matrix) and the code in current master was just offsetting all by the value.

Modified [ios] MGLAnnotationViewIntegrationTests.testSelectingAnnotationWithCenterOffset to use different insets. It verifies the fix.

Fixes [iOS] Annotations are not selectable (added via iosapp menu) #15106:

In case of #15106, view's original content insets is {top:88, bottom:34}, causing that center offset is {x:0, y:27} and selection with tolerance of 10 wouldn't select annotation.
After tapping the view, so that the header gets removed, view's content insets get changed to {top:44, bottom:34}, center offset is {x:0, y:5} and annotation selection would work, as described in #15106.

Fixes: #15106
friedbunny pushed a commit that referenced this pull request Jul 17, 2019
Viewport center offset usage was wrongly submitted in #14664. It was part of alternative approach that used enlarged viewport. Existing and added tests were not sufficient to spot the regression, since the collision check padding is usually larger than the center offset x and y. Annotation picking has tolerance of only 10 pixels but no annotation integration test was using content insets.

Usage of offset is not needed because `posMatrix` in e.g. `CollisionIndex::projectPoint(const mat4& posMatrix, const Point<float>& point)` already incorporates center offset (projection matrix) and the code in current master was just offsetting all by the value.

Modified [ios] MGLAnnotationViewIntegrationTests.testSelectingAnnotationWithCenterOffset to use different insets. It verifies the fix.

Fixes [iOS] Annotations are not selectable (added via iosapp menu) #15106:

In case of #15106, view's original content insets is {top:88, bottom:34}, causing that center offset is {x:0, y:27} and selection with tolerance of 10 wouldn't select annotation.
After tapping the view, so that the header gets removed, view's content insets get changed to {top:44, bottom:34}, center offset is {x:0, y:5} and annotation selection would work, as described in #15106.

Fixes: #15106
astojilj added a commit that referenced this pull request Jul 19, 2019
To changelog:
Fixed incorrect center coordinate after pinch regression caused by edge insets fix (#14664).

While working on #14664, missed to understand the logic used in

```
                CLLocationCoordinate2D centerCoordinate = _previousPinchCenterCoordinate;
                mbgl::EdgeInsets padding { centerPoint.y, centerPoint.x, self.size.height - centerPoint.y, self.size.width - centerPoint.x };
                self.mbglMap.jumpTo(mbgl::CameraOptions()
                                        .withCenter(MGLLatLngFromLocationCoordinate2D(centerCoordinate))
                                        .withPadding(padding));

```

Replacing this code by moveBy achieves the required translation.

Fixes: #14977, #15082
astojilj added a commit that referenced this pull request Jul 19, 2019
Viewport center offset usage was wrongly submitted in #14664. It was part of alternative approach that used enlarged viewport. Existing and added tests were not sufficient to spot the regression, since the collision check padding is usually larger than the center offset x and y. Annotation picking has tolerance of only 10 pixels but no annotation integration test was using content insets.

Usage of offset is not needed because `posMatrix` in e.g. `CollisionIndex::projectPoint(const mat4& posMatrix, const Point<float>& point)` already incorporates center offset (projection matrix) and the code in current master was just offsetting all by the value.

Modified [ios] MGLAnnotationViewIntegrationTests.testSelectingAnnotationWithCenterOffset to use different insets. It verifies the fix.

Fixes [iOS] Annotations are not selectable (added via iosapp menu) #15106:

In case of #15106, view's original content insets is {top:88, bottom:34}, causing that center offset is {x:0, y:27} and selection with tolerance of 10 wouldn't select annotation.
After tapping the view, so that the header gets removed, view's content insets get changed to {top:44, bottom:34}, center offset is {x:0, y:5} and annotation selection would work, as described in #15106.

Fixes: #15106
astojilj added a commit that referenced this pull request Jul 23, 2019
To changelog:
Fixed incorrect center coordinate after pinch regression caused by edge insets fix (#14664).

While working on #14664, missed to understand the logic used in

```
                CLLocationCoordinate2D centerCoordinate = _previousPinchCenterCoordinate;
                mbgl::EdgeInsets padding { centerPoint.y, centerPoint.x, self.size.height - centerPoint.y, self.size.width - centerPoint.x };
                self.mbglMap.jumpTo(mbgl::CameraOptions()
                                        .withCenter(MGLLatLngFromLocationCoordinate2D(centerCoordinate))
                                        .withPadding(padding));

```

Replacing this code by moveBy achieves the required translation.

Fixes: #14977, #15082
astojilj added a commit that referenced this pull request Jul 23, 2019
Viewport center offset usage was wrongly submitted in #14664. It was part of alternative approach that used enlarged viewport. Existing and added tests were not sufficient to spot the regression, since the collision check padding is usually larger than the center offset x and y. Annotation picking has tolerance of only 10 pixels but no annotation integration test was using content insets.

Usage of offset is not needed because `posMatrix` in e.g. `CollisionIndex::projectPoint(const mat4& posMatrix, const Point<float>& point)` already incorporates center offset (projection matrix) and the code in current master was just offsetting all by the value.

Modified [ios] MGLAnnotationViewIntegrationTests.testSelectingAnnotationWithCenterOffset to use different insets. It verifies the fix.

Fixes [iOS] Annotations are not selectable (added via iosapp menu) #15106:

In case of #15106, view's original content insets is {top:88, bottom:34}, causing that center offset is {x:0, y:27} and selection with tolerance of 10 wouldn't select annotation.
After tapping the view, so that the header gets removed, view's content insets get changed to {top:44, bottom:34}, center offset is {x:0, y:5} and annotation selection would work, as described in #15106.

Fixes: #15106
astojilj added a commit to mapbox/mapbox-navigation-ios that referenced this pull request Aug 12, 2019
Decouple dependency content insets -> anchor point -> padding/content insets broken after mapbox/mapbox-gl-native#14664 introduced animated interpolation for padding change.

Remove the need to specify center for puck view - use the approach where content inset is keeping it centered.

Take safeArea into account when calculating contentInsets.

Addresses: mapbox/mapbox-gl-native#15232, mapbox/mapbox-gl-native#15233

Related to: #2165,

Fixes: #2145
astojilj added a commit to mapbox/mapbox-navigation-ios that referenced this pull request Sep 9, 2019
Decouple dependency content insets -> anchor point -> padding/content insets broken after mapbox/mapbox-gl-native#14664 introduced animated interpolation for padding change.

Remove the need to specify center for puck view - use the approach where content inset is keeping it centered.

Take safeArea into account when calculating contentInsets.

Addresses: mapbox/mapbox-gl-native#15232, mapbox/mapbox-gl-native#15233

Related to: #2165,

Fixes: #2145
1ec5 pushed a commit to mapbox/mapbox-navigation-ios that referenced this pull request Oct 2, 2019
Decouple dependency content insets -> anchor point -> padding/content insets broken after mapbox/mapbox-gl-native#14664 introduced animated interpolation for padding change.

Remove the need to specify center for puck view - use the approach where content inset is keeping it centered.

Take safeArea into account when calculating contentInsets.

Addresses: mapbox/mapbox-gl-native#15232, mapbox/mapbox-gl-native#15233

Related to: #2165,

Fixes: #2145
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
Development

Successfully merging this pull request may close these issues.

MGLMapCamera(lookingAtCenter:, fromDistance:, pitch:, heading:) is not respecting content insets properly.
6 participants