-
Notifications
You must be signed in to change notification settings - Fork 85
Rework handling of panning to identified features #4591
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
base: master
Are you sure you want to change the base?
Changes from all commits
3321e9f
436777a
a63de42
c5e5d4f
c9b8b3d
516683f
4f45e09
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -321,34 +321,84 @@ void InputUtils::setExtentToGeom( const QgsGeometry &geom, InputMapSettings *map | |||||||||
| mapSettings->setExtent( currentExtent ); | ||||||||||
| } | ||||||||||
|
|
||||||||||
| QPointF InputUtils::relevantGeometryCenterToScreenCoordinates( const QgsGeometry &geom, InputMapSettings *mapSettings ) | ||||||||||
| QPointF InputUtils::whereToPanWhenIdentifying( const QgsGeometry &geom, InputMapSettings *mapSettings, double bottomOffset, const QPointF &identifyLocation ) | ||||||||||
| { | ||||||||||
| QPointF screenPoint; | ||||||||||
| QgsPoint target; | ||||||||||
| if ( !mapSettings || geom.isNull() || !geom.constGet() ) | ||||||||||
| return screenPoint; | ||||||||||
| QgsRectangle effectiveExtent( mapSettings->visibleExtent() ); | ||||||||||
|
|
||||||||||
| // canvas size in logical pixels; bottomOffset is in logical pixels too and | ||||||||||
| // screenToCoordinate() expects logical pixel coordinates | ||||||||||
| const double canvasWidth = mapSettings->outputSize().width() / mapSettings->devicePixelRatio(); | ||||||||||
| const double canvasHeight = mapSettings->outputSize().height() / mapSettings->devicePixelRatio(); | ||||||||||
| const QPointF bottomPoint( canvasWidth / 2.0, canvasHeight - bottomOffset ); | ||||||||||
|
|
||||||||||
| const QgsRectangle currentExtent = mapSettings->mapSettings().visibleExtent(); | ||||||||||
| const QgsPoint bottomPointMap = mapSettings->screenToCoordinate( bottomPoint ); | ||||||||||
|
|
||||||||||
| // Cut the geometry to current extent | ||||||||||
| const QgsGeometry currentExtentAsGeom = QgsGeometry::fromRect( currentExtent ); | ||||||||||
| const QgsGeometry intersectedGeom = geom.intersection( currentExtentAsGeom ); | ||||||||||
| effectiveExtent.setYMinimum( bottomPointMap.y() ); | ||||||||||
|
|
||||||||||
| if ( !intersectedGeom.isEmpty() ) | ||||||||||
| // Now we calculate a safeEffectiveExtent, slightly smaller, so that we don't allow geometries too close to the screen borders | ||||||||||
| constexpr double EXTENT_BUFFER_SCALE = 0.82; | ||||||||||
| const QgsRectangle safeEffectiveExtent( effectiveExtent.scaled( EXTENT_BUFFER_SCALE ) ); | ||||||||||
|
|
||||||||||
| QPointF screenPoint; | ||||||||||
| QgsPoint target; | ||||||||||
| if ( safeEffectiveExtent.contains( geom.boundingBox() ) ) | ||||||||||
| { | ||||||||||
| target = QgsPoint( intersectedGeom.boundingBox().center() ); | ||||||||||
| // If the whole geometry is visible, don't move map | ||||||||||
| return { std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN() }; | ||||||||||
| } | ||||||||||
| else | ||||||||||
| else if ( effectiveExtent.width() >= geom.boundingBox().width() && | ||||||||||
| effectiveExtent.height() >= geom.boundingBox().height() ) | ||||||||||
| { | ||||||||||
| // The geometry is outside the current viewed extent | ||||||||||
| setExtentToGeom( geom, mapSettings ); | ||||||||||
| // if the whole geometry would fit without changing scale, center it | ||||||||||
| target = QgsPoint( geom.boundingBox().center() ); | ||||||||||
| } | ||||||||||
| else | ||||||||||
| { | ||||||||||
| // the geometry is big, let's pan to the point the user clicked on the map | ||||||||||
| target = QgsPoint( identifyLocation ); | ||||||||||
| } | ||||||||||
|
|
||||||||||
| screenPoint = mapSettings->coordinateToScreen( target ); | ||||||||||
| screenPoint.ry() += bottomOffset / 2; | ||||||||||
|
|
||||||||||
| return screenPoint; | ||||||||||
| } | ||||||||||
|
|
||||||||||
| QgsRectangle InputUtils::drawerCompensatedExtent( const QgsGeometry &geom, InputMapSettings *mapSettings, double bottomOffset ) | ||||||||||
| { | ||||||||||
| const QgsRectangle bbox = geom.boundingBox(); | ||||||||||
| QgsRectangle currentExtent = mapSettings->mapSettings().visibleExtent(); | ||||||||||
|
|
||||||||||
| // canvas size in logical pixels; the bottom bottomOffset of the canvas is covered by another | ||||||||||
| // component (e.g. preview drawer), so we center the geometry in the remaining visible part | ||||||||||
| const double canvasWidth = mapSettings->outputSize().width() / mapSettings->devicePixelRatio(); | ||||||||||
| const double canvasHeight = mapSettings->outputSize().height() / mapSettings->devicePixelRatio(); | ||||||||||
| const double visibleHeight = std::max( canvasHeight - bottomOffset, 1.0 ); | ||||||||||
|
|
||||||||||
| if ( bbox.isEmpty() ) // Deal with an empty bouding box e.g : a point | ||||||||||
| { | ||||||||||
| const QgsPointXY center( bbox.center().x(), bbox.center().y() - bottomOffset / 2.0 * mapSettings->mapUnitsPerPoint() ); | ||||||||||
| const QgsVector offset = currentExtent.center() - center; | ||||||||||
| currentExtent -= offset; | ||||||||||
| } | ||||||||||
| else | ||||||||||
| { | ||||||||||
| QgsRectangle paddedBbox = bbox; | ||||||||||
|
|
||||||||||
| // Add a offset to encompass handles etc.. | ||||||||||
| // This number is based on what feel confortable for the user | ||||||||||
|
Comment on lines
+388
to
+389
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||
| constexpr double SCALE_FACTOR = 1.18; | ||||||||||
| paddedBbox.scale( SCALE_FACTOR ); | ||||||||||
|
|
||||||||||
| const double mapUnitsPerPoint = std::max( paddedBbox.width() / canvasWidth, paddedBbox.height() / visibleHeight ); | ||||||||||
| const double cx = bbox.center().x(); | ||||||||||
| const double cy = bbox.center().y() - bottomOffset / 2.0 * mapUnitsPerPoint; | ||||||||||
| currentExtent = QgsRectangle( cx - canvasWidth * mapUnitsPerPoint / 2, cy - canvasHeight * mapUnitsPerPoint / 2, | ||||||||||
| cx + canvasWidth * mapUnitsPerPoint / 2, cy + canvasHeight * mapUnitsPerPoint / 2 ); | ||||||||||
| } | ||||||||||
| return currentExtent; | ||||||||||
| } | ||||||||||
|
|
||||||||||
| double InputUtils::convertCoordinateString( const QString &rationalValue ) | ||||||||||
| { | ||||||||||
| QStringList values = rationalValue.split( "," ); | ||||||||||
|
|
@@ -2146,6 +2196,11 @@ QString InputUtils::getUniqueString( const QString &newString, const QStringList | |||||||||
| return uniqueString; | ||||||||||
| } | ||||||||||
|
|
||||||||||
| QgsRectangle InputUtils::extentFromMinMax( double xMin, double yMin, double xMax, double yMax ) | ||||||||||
| { | ||||||||||
| return QgsRectangle( xMin, yMin, xMax, yMax ); | ||||||||||
| } | ||||||||||
|
|
||||||||||
| bool InputUtils::rescaleImage( const QString &path, QgsProject *activeProject ) | ||||||||||
| { | ||||||||||
| int quality = activeProject->readNumEntry( QStringLiteral( "Mergin" ), QStringLiteral( "PhotoQuality" ), 0 ); | ||||||||||
|
|
||||||||||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -37,7 +37,7 @@ Item { | |||||
| property bool layerIsReadOnly: featureLayerPair?.layer?.readOnly ?? false | ||||||
| property bool layerIsSpatial: featureLayerPair ? __inputUtils.isSpatialLayer( featureLayerPair.layer ) : false | ||||||
|
|
||||||
| property real drawerHeight: drawer.height | ||||||
| property real previewPanelHeight: previewPanel.implicitHeight | ||||||
|
|
||||||
| signal closed() | ||||||
| signal saveRequested() | ||||||
|
|
@@ -46,7 +46,7 @@ Item { | |||||
| signal createLinkedFeature( var targetLayer, var parentPair ) | ||||||
| signal multiSelectFeature( var feature ) | ||||||
| signal stakeoutFeature( var feature ) | ||||||
| signal previewPanelChanged( var panelHeight ) | ||||||
| signal previewPanelChanged() | ||||||
|
|
||||||
| function openDrawer() { | ||||||
| root.panelState = "form" | ||||||
|
|
@@ -142,11 +142,6 @@ Item { | |||||
| edge: Qt.BottomEdge | ||||||
| closePolicy: Popup.CloseOnEscape // prevents the drawer closing while moving canvas | ||||||
|
|
||||||
| onOpened: { | ||||||
| if ( panelState === "preview" ) | ||||||
| previewPanelChanged( previewPanel.implicitHeight ) | ||||||
| } | ||||||
|
|
||||||
| onClosed: { | ||||||
| if ( statesManager.state !== "hidden" ) | ||||||
| statesManager.state = "closed" | ||||||
|
|
@@ -179,8 +174,9 @@ Item { | |||||
|
|
||||||
| onCloseClicked: drawer.close() | ||||||
|
|
||||||
| onImplicitHeightChanged: { | ||||||
| previewPanelChanged( previewPanel.implicitHeight ) | ||||||
| onDoneLoading: { | ||||||
| if ( root.panelState === "preview" ) | ||||||
| previewPanelChanged() | ||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
| } | ||||||
| } | ||||||
|
|
||||||
|
|
@@ -243,9 +239,4 @@ Item { | |||||
| } | ||||||
| } | ||||||
| } | ||||||
|
|
||||||
| onFeatureLayerPairChanged: { | ||||||
| if ( panelState === "preview" ) | ||||||
| previewPanelChanged( previewPanel.implicitHeight ) | ||||||
| } | ||||||
| } | ||||||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -104,15 +104,16 @@ ApplicationWindow { | |||||||||||||||||
| projDialog.open() | ||||||||||||||||||
| } | ||||||||||||||||||
|
|
||||||||||||||||||
| function identifyFeature( pair ) { | ||||||||||||||||||
| let hasNullGeometry = pair.feature.geometry.isNull | ||||||||||||||||||
| function identifyFeature( pair, point = Qt.point(NaN, NaN) ) { | ||||||||||||||||||
| map.identifyLocation = point | ||||||||||||||||||
|
|
||||||||||||||||||
| if ( hasNullGeometry ) { | ||||||||||||||||||
| let skipPreview = __inputUtils.isEmptyGeometry( pair.feature.geometry ) | ||||||||||||||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||||
| if ( skipPreview ) { | ||||||||||||||||||
| formsStackManager.openForm( pair, "readOnly", "form" ) | ||||||||||||||||||
| } | ||||||||||||||||||
| else if ( pair.valid ) { | ||||||||||||||||||
| map.highlightPair( pair ) | ||||||||||||||||||
| formsStackManager.openForm( pair, "readOnly", "preview") | ||||||||||||||||||
| formsStackManager.openForm( pair, "readOnly", "preview" ) | ||||||||||||||||||
| } | ||||||||||||||||||
| } | ||||||||||||||||||
|
|
||||||||||||||||||
|
|
@@ -180,8 +181,8 @@ ApplicationWindow { | |||||||||||||||||
| return 0 | ||||||||||||||||||
| } | ||||||||||||||||||
|
|
||||||||||||||||||
| onFeatureIdentified: function( pair ) { | ||||||||||||||||||
| formsStackManager.openForm( pair, "readOnly", "preview" ); | ||||||||||||||||||
| onFeatureIdentified: function( pair, point ) { | ||||||||||||||||||
| window.identifyFeature( pair, point ) | ||||||||||||||||||
| } | ||||||||||||||||||
|
|
||||||||||||||||||
| onFeaturesIdentified: function( pairs ) { | ||||||||||||||||||
|
|
@@ -190,6 +191,7 @@ ApplicationWindow { | |||||||||||||||||
| } | ||||||||||||||||||
|
|
||||||||||||||||||
| onNothingIdentified: { | ||||||||||||||||||
| map.hideHighlight() | ||||||||||||||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think the highlight should be managed mainly by |
||||||||||||||||||
| formsStackManager.closeDrawer() | ||||||||||||||||||
| } | ||||||||||||||||||
|
Comment on lines
193
to
196
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||||
|
|
||||||||||||||||||
|
|
@@ -860,8 +862,8 @@ ApplicationWindow { | |||||||||||||||||
| closeDrawer() | ||||||||||||||||||
| } | ||||||||||||||||||
|
|
||||||||||||||||||
| onPreviewPanelChanged: function( panelHeight ) { | ||||||||||||||||||
| map.jumpToHighlighted( panelHeight - mapToolbar.height ) | ||||||||||||||||||
| onPreviewPanelChanged: { | ||||||||||||||||||
| map.jumpToHighlighted() | ||||||||||||||||||
| } | ||||||||||||||||||
|
Comment on lines
+865
to
867
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||||
| } | ||||||||||||||||||
|
|
||||||||||||||||||
|
|
@@ -957,10 +959,8 @@ ApplicationWindow { | |||||||||||||||||
| secondaryText: model.LayerName | ||||||||||||||||||
| leftContent: MMIcon { source: model.LayerIcon } | ||||||||||||||||||
| onClicked: { | ||||||||||||||||||
| let pair = model.FeaturePair | ||||||||||||||||||
| featurePairSelection.close() | ||||||||||||||||||
| map.highlightPair( pair ) | ||||||||||||||||||
| formsStackManager.openForm( pair, "readOnly", "preview" ); | ||||||||||||||||||
| window.identifyFeature( model.FeaturePair ); | ||||||||||||||||||
| } | ||||||||||||||||||
| } | ||||||||||||||||||
|
|
||||||||||||||||||
|
|
||||||||||||||||||
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.