-
-
Notifications
You must be signed in to change notification settings - Fork 318
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Constrain camera to maximum bounds #2475
base: main
Are you sure you want to change the base?
Conversation
Merge changes from origin
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.
Thanks for your contribution!
This is so much better than the naive implementation with a delegate. There all movement is blocked once you touch the border: slightly panning into the border, zooming out... It's bad.
Did you port this directly from MapLibre GL JS? In that case can you link to the source code for reference?
Not sure how easy it is to add test coverage for this change?
We would need an Android API as well for this, do you by any chance also work with Android? Otherwise I'll create an issue for it.
Some compile errors on Linux
|
Bloaty Results (iOS) 🐋Compared to main
Full report: https://maplibre-native.s3.eu-central-1.amazonaws.com/bloaty-results-ios/pr-2475-compared-to-main.txt |
Yes, I tried that first too and was a bit disappointed with the results.
I hoped I would be able to just port it over, but it turned out that the architecture of the two code bases differ in important ways. I had to add the anchor handling and the scaling of the resulting center in case of having to scale the requested zoom.
I'll see if I can figure out where to add a test or two.
I was under the impression from #1455 that the android platform already had functionality to set the bounds. #1455 (comment) |
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 was under the impression from #1455 that the android platform already had functionality to set the bounds.
The current implementation constrains the center of the screen (as you expected). I think being able to limit the visible area regardless of screen size is a useful feature. But I am not sure yet how the constrainCameraAndZoomToBounds
, constrain
, setLatLngBounds
should interact with each other and what the best API design would be. I think the methods should make clear you are constraining either the visible area or where the center can be.
The contribution from @JulianBissekkou was reverted before the 6.0.0 release because there was a typo in the API. 🙈 I am not against including it again (with another name).
video_2024-06-06_15-04-24.mp4
Here you see the example app of Android on main (LatLngBoundsForCameraActivity), but the PR breaks the above behavior. We need to make this change in a backwards-compatible manner.
Sorry I stumbled, the approval was a misclick.
I did find the ConstrainMode Enum here: enum class ConstrainMode : EnumType {
None,
HeightOnly,
WidthAndHeight,
}; Unfortunately it looks like if you set the bounds it assumes that you want to constrain the center of the screen to the bounds, it would have been nice if there were a |
Actually I think those enums constrain transformations in the way you want, because it is used to make sure you cannot pan off the world. // Constrain scale to avoid zooming out far enough to show off-world areas on the Y axis.
const double ratioY = (rotatedNorth() ? size.width : size.height) / util::tileSize_D;
scale_ = util::max(scale_, ratioY);
// Constrain min/max pan to avoid showing off-world areas on the Y axis.
double max_y = (scale_ * util::tileSize_D - (rotatedNorth() ? size.width : size.height)) / 2;
y_ = std::max(-max_y, std::min(y_, max_y));
if (constrainMode == ConstrainMode::WidthAndHeight) {
// Constrain min/max pan to avoid showing off-world areas on the X axis.
double max_x = (scale_ * util::tileSize_D - (rotatedNorth() ? size.height : size.width)) / 2;
x_ = std::max(-max_x, std::min(x_, max_x));
} If you just make max_x configurable here you'd be done. Note that in |
I did contemplate solving the problem like that, but came to the conclusion that it would be more elegant to actually compute a valid end point and zoom, instead of just start constraining movement mid path. Especially with flyTo where the start point, start zoom, end point, and end zoom are used to calculate the path taken. |
Agreed! |
for more information, see https://pre-commit.ci
for more information, see https://pre-commit.ci
@louwers I've added the requested unit tests and made sure that the change is backwards-compatible. |
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.
Starting to look good! I have some questions:
-
How can the user of the iOS SDK reset the max bounds again?
-
In
BoundOptions
there is a comment
Sets the latitude and longitude bounds to which the camera center are constrained
Constrain the center of the camera to be within these bounds.
Do these need to be updated?
-
Do you think
ConstrainMode::CameraAndZoomToBounds
is a good name? I feel like saying you are constraining zoom to bounds is a bit awkward. MaybeConstrainMode::Screen
would be better? -
Reflecting the above, maybe we want
setMaximumScreenBounds
in case we want to add an Objective-C method to set the camera center bounds.
Currently you can't. This isn't part of my usecase. If someone needs it, i'm sure they are welcome to create a PR with that functionality.
All these should be fixed. I hope I've added all the missing parts, it now constrains the screen to the bounds when you change orientation on your phone too. There were some very subtle bugs hidden in the resize method. I've made the changes backwards compatible if anyone are counting on the resize method behaving in a certain way. Please have a look and let me know what you think. |
Bloaty Results 🐋Compared to main
Full report: https://maplibre-native.s3.eu-central-1.amazonaws.com/bloaty-results/pr-2475-compared-to-main.txtCompared to d387090 (legacy)
Full report: https://maplibre-native.s3.eu-central-1.amazonaws.com/bloaty-results/pr-2475-compared-to-legacy.txt |
Benchmark Results ⚡
Full report: https://maplibre-native.s3.eu-central-1.amazonaws.com/benchmark-results/pr-2475-compared-to-main.txt |
@louwers have you had a chance to look at the changes? |
@christian-boks Will give it another spin tomorrow, thanks for the reminder. |
@JesseCrocker Do you have a use case for this? If so, would you be willing to try it out? |
Having worked with maplibre-gl-js for a web solution I wanted to try maplibre-native for ios, but I couldn't find the functionality where you can set maximum bounds for the camera.
I can see that the issue has been discussed before in #1455 but it ended with some bikeshedding on what to call the missing method, and it was removed again. I added the missing code to the ios platform code, but found out that the current constraining code doesn't work the same way as the web code. It constrains the bounds in the center of the screen?
I've added the code required to get the same functionality as the web does, where the bounds are constrained to the edges of the screen. I'd appreciate a review from someone with a bit more experience in the codebase.