| Summary: | centerOn(GeoDataLatLonBox) behaviour does not match documentation | ||
|---|---|---|---|
| Product: | [Applications] marble | Reporter: | Samuel OMalley <7g7o5v4t> |
| Component: | general | Assignee: | marble-bugs |
| Status: | CONFIRMED --- | ||
| Severity: | normal | CC: | rahn |
| Priority: | NOR | ||
| Version First Reported In: | unspecified | ||
| Target Milestone: | --- | ||
| Platform: | RedHat Enterprise Linux | ||
| OS: | Linux | ||
| Latest Commit: | Version Fixed/Implemented In: | ||
| Sentry Crash Report: | |||
|
Description
Samuel OMalley
2022-11-08 01:54:57 UTC
Yes, the current implementation of
void MarbleAbstractPresenter::centerOn(const GeoDataLatLonBox &box, bool animated)
is only a rough approximation. In order to center on a boundingbox internally Marble needs to center on the center point and adjust the zoom level (which is internally tied to the pixel-radius that a fully rendered earth would cover in terms of vertical extent).
Since Marble allows for usage of different projections the actual calculation of the zoom level would hard to calculate in a generic way. So the only "better" option would be to iteratively approximate the optimal zoom level (while either working on a copy of the view parameters or turning off rendering during the iterative convergence towards the optimal zoom level).
The current code looks like this:
void MarbleAbstractPresenter::centerOn(const GeoDataLatLonBox &box, bool animated)
{
if (box.isEmpty())
{
return;
}
int newRadius = radius();
ViewportParams* viewparams = map()->viewport();
//prevent divide by zero
if(box.height() && box.width())
{
//work out the needed zoom level
int const horizontalRadius = ( 0.25 * M_PI ) * (viewparams->height() / box.height());
int const verticalRadius = ( 0.25 * M_PI ) * (viewparams->width() / box.width());
newRadius = qMin<int>(horizontalRadius, verticalRadius );
newRadius = qMax<int>(radius(minimumZoom()), qMin<int>(newRadius, radius(maximumZoom())));
}
//move the map
GeoDataLookAt target;
target.setCoordinates(box.center());
target.setAltitude(box.center().altitude());
target.setRange(KM2METER * distanceFromRadius(newRadius));
flyTo(target, animated ? Automatic : Instant);
}
Any suggestions for improvements welcome.
|