-
Notifications
You must be signed in to change notification settings - Fork 35
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This assumes the physical distance between the old center and old northeast corner is equal to the physical distance between the new center and the new northeast corner. Because the map uses Mercator projection, the latitude lines aren’t evenly spaced. So the center may change by a different amount than the top and bottom edges of the view. I’d imagine this issue would be most apparent when dramatically swiping the map north or south to either pole. You can mitigate this issue by restricting the map to high zoom levels, but that would limit the example’s usefulness.
Moreover, if the user rotates the map, these calculations can become severely inaccurate. You could mitigate this issue by turning off rotation.
An alternative approach would be to “set and revert” within mapView(_:shouldChangeFrom:to:)
: store the current camera as camera
, set mapView.camera
to newCamera
, store the visibleCoordinateBounds
in a local variable, and set mapView.camera
back to camera
. (I’d avoid relying on oldCamera
to equal mapView.camera
, because we may figure out a way to batch up calls to mapView(_:shouldChangeFrom:to:)
in the future.)
// Colorado's bounds | ||
let ne = CLLocationCoordinate2D(latitude: 40.989329, longitude: -102.062592) | ||
let sw = CLLocationCoordinate2D(latitude: 36.986207, longitude: -109.049896) | ||
colorado = MGLCoordinateBoundsMake(sw, ne) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use MGLCoordinateBounds(sw:ne:)
instead of MGLCoordinateBoundsMake(_:_:)
.
I think it'd be interesting to do a performance comparison with the approach already in this PR and the approach outlined in #65 (review). A less accurate, limited solution may still be useful for cases involving offline maps that usually involve higher zoom levels. |
MGLMapView *mapView = [[MGLMapView alloc] initWithFrame:self.view.bounds]; | ||
mapView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; | ||
mapView.rotateEnabled = NO; | ||
mapView.minimumZoomLevel = 10; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it still necessary to disable rotation and cap the zoom level, now that you’re doing the set-and-revert dance?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The example I made deals with rotation but I considered was not important for restricting boundaries, I reverted this.
CLLocationCoordinate2D newCameraCenter = newCamera.centerCoordinate; | ||
MGLMapCamera *camera = mapView.camera; | ||
|
||
// Get new bounds |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These comments say what the developer is expected to do, but not why. An example needs to explain the rationale behind each non-obvious step, in order to avoid the phenomenon of cargo cult programming. In particular, we should be explicit about the fact that we’re changing and resetting the map view’s camera in order to predict the extents of the new viewport.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I changed the comments to make it more explicit.
|
||
// Test if the new camera center point and boundaries are inside colorado | ||
BOOL inside = MGLCoordinateInCoordinateBounds(newCameraCenter, self.colorado); | ||
BOOL intersects = MGLCoordinateInCoordinateBounds(newVisibleCoordinates.ne, self.colorado) && MGLCoordinateInCoordinateBounds(newVisibleCoordinates.sw, self.colorado); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, I see why you’ve restricted the zoom level and disabled rotation. Can you think of a way to test whether the new viewport would fit inside the allowed region (Colorado) while accounting for rotation? Perhaps the logic in turf-inside would be helpful here, although it might be overkill.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm already taking a similar approach like function inBBox
and also accounts for restricting rotation if its out of boundaries.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, this code is fine. I was mistaken previously in thinking that this logic would produce incorrect results when the map is rotated, but the visible coordinate bounds will extend beyond the allowed region. This logic would not work if the map is tilted or if the allowed region itself is rotated.
7ce1890
to
7ae2af7
Compare
0cb288e
to
84d7528
Compare
@1ec5 @captainbarbosa @jmkiley could you please take a look. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A couple minor style notes, but otherwise this is good to go.
// Test if the newCameraCenter and newVisibleCoordinates | ||
// are inside self.colorado | ||
let inside: Bool = MGLCoordinateInCoordinateBounds(newCameraCenter, self.colorado) | ||
let intersects: Bool = MGLCoordinateInCoordinateBounds(newVisibleCoordinates.ne, self.colorado) && MGLCoordinateInCoordinateBounds(newVisibleCoordinates.sw, self.colorado) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: drop self.
, since it’s implied.
} | ||
|
||
// This example uses Colorado's boundaries to restrict | ||
// the camera movement |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The use of a period at the end of a comment is inconsistent in this file. Here there’s no period at the end of the sentence; above, “Starting point” does end with a period, even though it isn’t a sentence. Normally I end all the comments with periods if any of them is a sentence.
|
||
// From the new camera obtain the center to test | ||
// if it's inside the boundaries | ||
let newCameraCenter: CLLocationCoordinate2D = newCamera.centerCoordinate |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: centerCoordinate
’s type is inferred as CLLocationCoordinate2D
, so there’s no need to declare newCameraCenter
’s type here. (Same with inside
and intersects
below.)
No description provided.