Bug 461569

Summary: centerOn(GeoDataLatLonBox) behaviour does not match documentation
Product: [Applications] marble Reporter: Samuel OMalley <7g7o5v4t>
Component: generalAssignee: marble-bugs
Status: CONFIRMED ---    
Severity: normal CC: rahn
Priority: NOR    
Version: unspecified   
Target Milestone: ---   
Platform: RedHat Enterprise Linux   
OS: Linux   
Latest Commit: Version Fixed In:
Sentry Crash Report:

Description Samuel OMalley 2022-11-08 01:54:57 UTC
SUMMARY
***
NOTE: If you are reporting a crash, please try to attach a backtrace with debug symbols.
See https://community.kde.org/Guidelines_and_HOWTOs/Debugging/How_to_create_useful_crash_reports
***

The documentation for centerOn(GeoDataLatLonBox) specifies: "Center the view on a bounding box so that it **completely fills the viewport**"

However, the actual behaviour of this function is that the map is correctly centered, but zoomed *out* from the bounding box.


STEPS TO REPRODUCE
1. Define a bounding box
2. call centerOn the bounding box

OBSERVED RESULT
Bounding box does _not_ completely fill the viewport as described in the documentation.

EXPECTED RESULT
Bounding box should completely fill the viewport.

SOFTWARE/OS VERSIONS
Linux/KDE Plasma: RHEL7 and RHEL8
Qt Version: 5.10
Comment 1 Torsten Rahn 2023-04-22 13:31:12 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.