From cd7dc4c8aeb7f044cb5ab203a7dec176f7dc9f48 Mon Sep 17 00:00:00 2001 From: VitorVieiraZ Date: Mon, 12 Aug 2024 23:12:16 -0300 Subject: [PATCH 01/60] styling new tool --- app/icons/Measure.svg | 7 ++++ app/icons/icons.qrc | 1 + app/images/NeutralMMSymbol.svg | 23 ++++++++++++ app/images/images.qrc | 1 + app/mmstyle.h | 4 +++ app/qml/CMakeLists.txt | 1 + app/qml/dialogs/MMFinishMeasurementDialog.qml | 35 +++++++++++++++++++ app/qml/main.qml | 8 +++++ app/qml/map/MMMeasurementTools.qml | 5 +++ gallery/qml.qrc | 1 + gallery/qml/pages/DrawerPage.qml | 12 +++++++ gallery/qml/pages/IconsPage.qml | 1 + 12 files changed, 99 insertions(+) create mode 100644 app/icons/Measure.svg create mode 100644 app/images/NeutralMMSymbol.svg create mode 100644 app/qml/dialogs/MMFinishMeasurementDialog.qml create mode 100644 app/qml/map/MMMeasurementTools.qml diff --git a/app/icons/Measure.svg b/app/icons/Measure.svg new file mode 100644 index 000000000..0666bf957 --- /dev/null +++ b/app/icons/Measure.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/app/icons/icons.qrc b/app/icons/icons.qrc index c3f553a97..4166c8ae7 100644 --- a/app/icons/icons.qrc +++ b/app/icons/icons.qrc @@ -97,5 +97,6 @@ ZoomToProject.svg StakeOut.svg Student.svg + Measure.svg diff --git a/app/images/NeutralMMSymbol.svg b/app/images/NeutralMMSymbol.svg new file mode 100644 index 000000000..e31c406a2 --- /dev/null +++ b/app/images/NeutralMMSymbol.svg @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/images/images.qrc b/app/images/images.qrc index ac0474d90..b0b772a30 100644 --- a/app/images/images.qrc +++ b/app/images/images.qrc @@ -23,6 +23,7 @@ ExternalGpsGreen.svg NegativeMMSymbol.svg PositiveMMSymbol.svg + NeutralMMSymbol.svg CloseAccount.svg Attention.svg Bubble.svg diff --git a/app/mmstyle.h b/app/mmstyle.h index 7d65b0e91..98096c3fc 100644 --- a/app/mmstyle.h +++ b/app/mmstyle.h @@ -168,6 +168,7 @@ class MMStyle: public QObject Q_PROPERTY( QUrl streamingIcon READ streamingIcon CONSTANT ) Q_PROPERTY( QUrl redrawGeometryIcon READ redrawGeometryIcon CONSTANT ) Q_PROPERTY( QUrl cloudIcon READ cloudIcon CONSTANT ) + Q_PROPERTY( QUrl measurementToolIcon READ measurementToolIcon CONSTANT ) // Filled Icons - for visualizing of selected item in toolbar Q_PROPERTY( QUrl projectsFilledIcon READ projectsFilledIcon CONSTANT ) @@ -215,6 +216,7 @@ class MMStyle: public QObject Q_PROPERTY( QUrl externalGpsRedImage READ externalGpsRedImage CONSTANT ) Q_PROPERTY( QUrl negativeMMSymbolImage READ negativeMMSymbolImage CONSTANT ) Q_PROPERTY( QUrl positiveMMSymbolImage READ positiveMMSymbolImage CONSTANT ) + Q_PROPERTY( QUrl neutralMMSymbolImage READ neutralMMSymbolImage CONSTANT ) Q_PROPERTY( QUrl closeAccountImage READ closeAccountImage CONSTANT ) Q_PROPERTY( QUrl attentionImage READ attentionImage CONSTANT ) Q_PROPERTY( QUrl blueInfoImage READ blueInfoImage CONSTANT ) @@ -422,6 +424,7 @@ class MMStyle: public QObject QUrl moreVerticalIcon() {return QUrl( "qrc:/MoreVertical.svg" );} QUrl morePhotosIcon() {return QUrl( "qrc:/MorePhotos.svg" );} QUrl mouthIcon() {return QUrl( "qrc:/Mouth.svg" );} + QUrl measurementToolIcon() {return QUrl( "qrc:/Measure.svg" );} QUrl naturalResourcesIcon() {return QUrl( "qrc:/NaturalResources.svg" );} QUrl nextIcon() {return QUrl( "qrc:/Next.svg" );} QUrl otherIcon() {return QUrl( "qrc:/Other.svg" );} @@ -498,6 +501,7 @@ class MMStyle: public QObject QUrl externalGpsRedImage() {return QUrl( "qrc:/images/ExternalGpsRed.svg" );} QUrl negativeMMSymbolImage() {return QUrl( "qrc:/images/NegativeMMSymbol.svg" );} QUrl positiveMMSymbolImage() {return QUrl( "qrc:/images/PositiveMMSymbol.svg" );} + QUrl neutralMMSymbolImage() {return QUrl( "qrc:/images/NeutralMMSymbol.svg" );} QUrl closeAccountImage() {return QUrl( "qrc:/images/CloseAccount.svg" );} QUrl attentionImage() {return QUrl( "qrc:/images/Attention.svg" );} QUrl blueInfoImage() {return QUrl( "qrc:/images/BlueInfo.svg" );} diff --git a/app/qml/CMakeLists.txt b/app/qml/CMakeLists.txt index bf848bd61..ac5016cbf 100644 --- a/app/qml/CMakeLists.txt +++ b/app/qml/CMakeLists.txt @@ -135,6 +135,7 @@ set(MM_QML map/MMSplittingTools.qml map/MMStakeoutTools.qml map/MMRecordingTools.qml + map/MMMeasurementTools.qml map/components/MMHidingBox.qml map/components/MMCrosshair.qml map/components/MMMapHidingLabel.qml diff --git a/app/qml/dialogs/MMFinishMeasurementDialog.qml b/app/qml/dialogs/MMFinishMeasurementDialog.qml new file mode 100644 index 000000000..bde199dd1 --- /dev/null +++ b/app/qml/dialogs/MMFinishMeasurementDialog.qml @@ -0,0 +1,35 @@ +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +import QtQuick + +import "../components" + +MMDrawerDialog { + id: root + + signal finishMeasurementRequested() + + imageSource: __style.neutralMMSymbolImage + title: qsTr( "Do you wish to finish the measurement?" ) + description: qsTr( "Your measured segment will be lost." ) + primaryButton.text: qsTr( "Yes" ) + secondaryButton.text: qsTr( "No" ) + + onPrimaryButtonClicked: { + console.log(" Measurement : Finish YES") + root.finishMeasurementRequested() + close() + } + + onSecondaryButtonClicked: { + console.log(" Measurement : Finish NO") + close() + } +} diff --git a/app/qml/main.qml b/app/qml/main.qml index 822e7bd41..746ef4327 100644 --- a/app/qml/main.qml +++ b/app/qml/main.qml @@ -326,6 +326,14 @@ ApplicationWindow { } } + MMToolbarButton { + text: qsTr("Measure") + iconSource: __style.measurementToolIcon + onClicked: { + console.log(" Measurement tool") + } + } + MMToolbarButton { text: qsTr("Local changes") iconSource: __style.localChangesIcon diff --git a/app/qml/map/MMMeasurementTools.qml b/app/qml/map/MMMeasurementTools.qml new file mode 100644 index 000000000..5560aee72 --- /dev/null +++ b/app/qml/map/MMMeasurementTools.qml @@ -0,0 +1,5 @@ +import QtQuick + +Item { + +} diff --git a/gallery/qml.qrc b/gallery/qml.qrc index b54c2ff92..b66430682 100644 --- a/gallery/qml.qrc +++ b/gallery/qml.qrc @@ -155,5 +155,6 @@ ../app/qml/dialogs/MMDiscardGeometryChangesDialog.qml ../app/qml/dialogs/MMProviderRemoveReceiverDialog.qml ../app/qml/dialogs/components/MMDialogAdditionalText.qml + ../app/qml/dialogs/MMFinishMeasurementDialog.qml diff --git a/gallery/qml/pages/DrawerPage.qml b/gallery/qml/pages/DrawerPage.qml index e3400a423..be7cf90e3 100644 --- a/gallery/qml/pages/DrawerPage.qml +++ b/gallery/qml/pages/DrawerPage.qml @@ -194,6 +194,14 @@ Page { welcomeToNewDesignDialog.open() } } + + Button { + text: "finishMeasurementDialog" + + onClicked: { + finishMeasurementDialog.open() + } + } } } @@ -367,4 +375,8 @@ Page { MMWelcomeToNewDesignDialog { id: welcomeToNewDesignDialog } + + MMFinishMeasurementDialog { + id: finishMeasurementDialog + } } diff --git a/gallery/qml/pages/IconsPage.qml b/gallery/qml/pages/IconsPage.qml index a9d56b6dd..5a89348a0 100644 --- a/gallery/qml/pages/IconsPage.qml +++ b/gallery/qml/pages/IconsPage.qml @@ -76,6 +76,7 @@ ScrollView { GalleryComponents.IconLine { name: "morePhotosIcon"; source: __style.morePhotosIcon; showRect: checkboxBorder.checked; invertColors: checkboxColor.checked } GalleryComponents.IconLine { name: "plusIcon"; source: __style.plusIcon; showRect: checkboxBorder.checked; invertColors: checkboxColor.checked } GalleryComponents.IconLine { name: "positionTrackingIcon"; source: __style.positionTrackingIcon; showRect: checkboxBorder.checked; invertColors: checkboxColor.checked } + GalleryComponents.IconLine { name: "measurementToolIcon"; source: __style.measurementToolIcon; showRect: checkboxBorder.checked; invertColors: checkboxColor.checked } GalleryComponents.IconLine { name: "qrCodeIcon"; source: __style.qrCodeIcon; showRect: checkboxBorder.checked; invertColors: checkboxColor.checked } GalleryComponents.IconLine { name: "satelliteIcon"; source: __style.satelliteIcon; showRect: checkboxBorder.checked; invertColors: checkboxColor.checked } GalleryComponents.IconLine { name: "searchIcon"; source: __style.searchIcon; showRect: checkboxBorder.checked; invertColors: checkboxColor.checked } From f77fc898db1ceabac99aa2011071d7a5c300b89d Mon Sep 17 00:00:00 2001 From: VitorVieiraZ Date: Tue, 13 Aug 2024 07:48:57 -0300 Subject: [PATCH 02/60] starting new crosshair --- app/qml/CMakeLists.txt | 1 + app/qml/dialogs/MMFinishMeasurementDialog.qml | 2 +- app/qml/map/components/MMDataCrosshair.qml | 255 ++++++++++++++++++ 3 files changed, 257 insertions(+), 1 deletion(-) create mode 100644 app/qml/map/components/MMDataCrosshair.qml diff --git a/app/qml/CMakeLists.txt b/app/qml/CMakeLists.txt index ac5016cbf..59db38dce 100644 --- a/app/qml/CMakeLists.txt +++ b/app/qml/CMakeLists.txt @@ -138,6 +138,7 @@ set(MM_QML map/MMMeasurementTools.qml map/components/MMHidingBox.qml map/components/MMCrosshair.qml + map/components/MMDataCrosshair.qml map/components/MMMapHidingLabel.qml map/components/MMMapButton.qml map/components/MMMapLabel.qml diff --git a/app/qml/dialogs/MMFinishMeasurementDialog.qml b/app/qml/dialogs/MMFinishMeasurementDialog.qml index bde199dd1..96a68a424 100644 --- a/app/qml/dialogs/MMFinishMeasurementDialog.qml +++ b/app/qml/dialogs/MMFinishMeasurementDialog.qml @@ -17,7 +17,7 @@ MMDrawerDialog { signal finishMeasurementRequested() imageSource: __style.neutralMMSymbolImage - title: qsTr( "Do you wish to finish the measurement?" ) + title: qsTr( "Do you wish to finish the measurement?" ) description: qsTr( "Your measured segment will be lost." ) primaryButton.text: qsTr( "Yes" ) secondaryButton.text: qsTr( "No" ) diff --git a/app/qml/map/components/MMDataCrosshair.qml b/app/qml/map/components/MMDataCrosshair.qml new file mode 100644 index 000000000..a9c7ec465 --- /dev/null +++ b/app/qml/map/components/MMDataCrosshair.qml @@ -0,0 +1,255 @@ +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +import QtQuick +import Qt5Compat.GraphicalEffects + +import mm 1.0 as MM + +Item { + id: root + + /*required*/ property var qgsProject + /*required*/ property var mapSettings + property bool shouldUseSnapping: false + + property point center: Qt.point( root.width / 2, root.height / 2 ) + + property var recordPoint: snapUtils.recordPoint + + property point screenPoint: snapUtils.snapped && __activeLayer.vectorLayer ? __inputUtils.transformPointToScreenCoordinates(__activeLayer.vectorLayer.crs, mapSettings, recordPoint) : center + + property real outerSize: 60 * __dp + property real innerDotSize: 10 * __dp + + MM.SnapUtils { + id: snapUtils + + centerPosition: root.center + mapSettings: root.mapSettings + qgsProject: root.qgsProject + useSnapping: root.shouldUseSnapping + destinationLayer: __activeLayer.vectorLayer + + } + + Image { + id: crosshairBackground // white background of the crosshair + + x: root.screenPoint.x - width / 2 + y: root.screenPoint.y - height / 2 + + Behavior on x { + PropertyAnimation { + properties: "x" + duration: 50 + easing.type: Easing.InQuad + } + } + + Behavior on y { + PropertyAnimation { + properties: "y" + duration: 50 + easing.type: Easing.InQuad + } + } + + height: root.outerSize + width: height + + source: __style.crosshairBackgroundImage + sourceSize.width: width + sourceSize.height: height + } + + Image { + id: crosshairForeground // green / purple outer circle of the crosshair + + x: root.screenPoint.x - width / 2 + y: root.screenPoint.y - height / 2 + + Behavior on x { + PropertyAnimation { + properties: "x" + duration: 50 + easing.type: Easing.InQuad + } + } + + Behavior on y { + PropertyAnimation { + properties: "y" + duration: 50 + easing.type: Easing.InQuad + } + } + + height: root.outerSize + width: height + + source: __style.crosshairForegroundImage + sourceSize.width: width + sourceSize.height: height + } + + ColorOverlay { + anchors.fill: crosshairForeground + source: crosshairForeground + color: snapUtils.snapped ? __style.snappingColor : __style.forestColor + } + + Image { + id: crossCenterDot // Center dot - visible when not snapped (green) + + x: root.screenPoint.x - width / 2 + y: root.screenPoint.y - height / 2 + + Behavior on x { + PropertyAnimation { + properties: "x" + duration: 50 + easing.type: Easing.InQuad + } + } + + Behavior on y { + PropertyAnimation { + properties: "y" + duration: 50 + easing.type: Easing.InQuad + } + } + + opacity: snapUtils.snapped ? 0 : 100 + + Behavior on opacity { + PropertyAnimation { + properties: "opacity" + duration: 100 + easing.type: Easing.InQuad + } + } + + height: root.innerDotSize + width: height + sourceSize.width: width + sourceSize.height: height + + source: __style.crosshairCenterImage + } + + Image { + id: crossCenterPlus // Center plus - visible when not snapped (purple) + + x: root.screenPoint.x - width / 2 + y: root.screenPoint.y - height / 2 + + Behavior on x { + PropertyAnimation { + properties: "x" + duration: 50 + easing.type: Easing.InQuad + } + } + + Behavior on y { + PropertyAnimation { + properties: "y" + duration: 50 + easing.type: Easing.InQuad + } + } + + opacity: snapUtils.snapped && ( snapUtils.snapType === MM.SnapUtils.Vertex || snapUtils.snapType === MM.SnapUtils.Other ) ? 100 : 0 + + Behavior on opacity { + PropertyAnimation { + properties: "opacity" + duration: 100 + easing.type: Easing.InQuad + } + } + + rotation: snapUtils.snapType === MM.SnapUtils.Other ? 0 : 45 + + Behavior on rotation { + PropertyAnimation { + properties: "rotation" + duration: 50 + easing.type: Easing.InQuad + } + } + + height: root.innerDotSize * 2 + width: height + sourceSize.width: width + sourceSize.height: height + + // Important: must be same color as __style.snappingColor + source: __style.crosshairPlusImage + } + + Image { + id: crossCenterCircle // Center circle - visible when snapped to segment (purple) + + x: root.screenPoint.x - width / 2 + y: root.screenPoint.y - height / 2 + + Behavior on x { + PropertyAnimation { + properties: "x" + duration: 50 + easing.type: Easing.InQuad + } + } + + Behavior on y { + PropertyAnimation { + properties: "y" + duration: 50 + easing.type: Easing.InQuad + } + } + + opacity: snapUtils.snapped && snapUtils.snapType === MM.SnapUtils.Segment ? 100 : 0 + + Behavior on opacity { + PropertyAnimation { + properties: "opacity" + duration: 100 + easing.type: Easing.InQuad + } + } + + height: root.innerDotSize * 2 + width: height + sourceSize.width: width + sourceSize.height: height + + // Important: must be same color as __style.snappingColor + source: __style.crosshairCircleImage + } + + Connections { + target: __activeProject + + function onProjectWillBeReloaded() { + snapUtils.clear() + } + + function onProjectReloaded( project ) { + // We need to re-assign qgs project to snaputils, because + // even though we loaded a different project, + // internally we keep the same pointer for QgsProject. + snapUtils.qgsProject = __activeProject.qgsProject + snapUtils.mapSettings = root.mapSettings + } + } +} From 427948d5c9c0e5cc57df8cc898d5d64024101143 Mon Sep 17 00:00:00 2001 From: VitorVieiraZ Date: Wed, 14 Aug 2024 09:36:47 -0300 Subject: [PATCH 03/60] crosshair development --- app/qml/map/MMRecordingTools.qml | 2 +- app/qml/map/components/MMDataCrosshair.qml | 384 ++++++++++++--------- app/qml/map/components/MMMapLabel.qml | 1 + 3 files changed, 224 insertions(+), 163 deletions(-) diff --git a/app/qml/map/MMRecordingTools.qml b/app/qml/map/MMRecordingTools.qml index babe68419..24d1b9a14 100644 --- a/app/qml/map/MMRecordingTools.qml +++ b/app/qml/map/MMRecordingTools.qml @@ -144,7 +144,7 @@ Item { accuracyRingSize: positionMarkerComponent.accuracyRingSize } - MMCrosshair { + MMDataCrosshair { id: crosshair anchors.fill: parent diff --git a/app/qml/map/components/MMDataCrosshair.qml b/app/qml/map/components/MMDataCrosshair.qml index a9c7ec465..ee3e5036c 100644 --- a/app/qml/map/components/MMDataCrosshair.qml +++ b/app/qml/map/components/MMDataCrosshair.qml @@ -15,6 +15,11 @@ import mm 1.0 as MM Item { id: root + // Rectangle { //map + // anchors.fill: parent + // color: "lightblue" + // } + /*required*/ property var qgsProject /*required*/ property var mapSettings property bool shouldUseSnapping: false @@ -29,227 +34,282 @@ Item { property real innerDotSize: 10 * __dp MM.SnapUtils { - id: snapUtils + id: snapUtils - centerPosition: root.center - mapSettings: root.mapSettings - qgsProject: root.qgsProject - useSnapping: root.shouldUseSnapping - destinationLayer: __activeLayer.vectorLayer + centerPosition: root.center + mapSettings: root.mapSettings + qgsProject: root.qgsProject + useSnapping: root.shouldUseSnapping + destinationLayer: __activeLayer.vectorLayer } Image { - id: crosshairBackground // white background of the crosshair - - x: root.screenPoint.x - width / 2 - y: root.screenPoint.y - height / 2 - - Behavior on x { - PropertyAnimation { - properties: "x" - duration: 50 - easing.type: Easing.InQuad + id: crosshairBackground // white background of the crosshair + + // Rectangle { + // anchors.fill: parent + // color: "lightcoral" + // } + + x: root.screenPoint.x - width / 2 + y: root.screenPoint.y - height / 2 + + Behavior on x { + PropertyAnimation { + properties: "x" + duration: 50 + easing.type: Easing.InQuad + } } - } - Behavior on y { - PropertyAnimation { - properties: "y" - duration: 50 - easing.type: Easing.InQuad + Behavior on y { + PropertyAnimation { + properties: "y" + duration: 50 + easing.type: Easing.InQuad + } } - } - height: root.outerSize - width: height + height: root.outerSize + width: height - source: __style.crosshairBackgroundImage - sourceSize.width: width - sourceSize.height: height + source: __style.crosshairBackgroundImage + sourceSize.width: width + sourceSize.height: height } Image { - id: crosshairForeground // green / purple outer circle of the crosshair - - x: root.screenPoint.x - width / 2 - y: root.screenPoint.y - height / 2 - - Behavior on x { - PropertyAnimation { - properties: "x" - duration: 50 - easing.type: Easing.InQuad + id: crosshairForeground // green / purple outer circle of the crosshair + + // Rectangle { + // anchors.fill: parent + // color: "lightyellow" + // } + + x: root.screenPoint.x - width / 2 + y: root.screenPoint.y - height / 2 + + Behavior on x { + PropertyAnimation { + properties: "x" + duration: 50 + easing.type: Easing.InQuad + } } - } - Behavior on y { - PropertyAnimation { - properties: "y" - duration: 50 - easing.type: Easing.InQuad + Behavior on y { + PropertyAnimation { + properties: "y" + duration: 50 + easing.type: Easing.InQuad + } } - } - height: root.outerSize - width: height + height: root.outerSize + width: height - source: __style.crosshairForegroundImage - sourceSize.width: width - sourceSize.height: height + source: __style.crosshairForegroundImage + sourceSize.width: width + sourceSize.height: height } ColorOverlay { - anchors.fill: crosshairForeground - source: crosshairForeground - color: snapUtils.snapped ? __style.snappingColor : __style.forestColor + anchors.fill: crosshairForeground + source: crosshairForeground + color: snapUtils.snapped ? __style.snappingColor : __style.forestColor + + // Rectangle { + // anchors.fill: parent + // color: "lightpink" + // } } Image { - id: crossCenterDot // Center dot - visible when not snapped (green) - - x: root.screenPoint.x - width / 2 - y: root.screenPoint.y - height / 2 - - Behavior on x { - PropertyAnimation { - properties: "x" - duration: 50 - easing.type: Easing.InQuad + id: crossCenterDot // Center dot - visible when not snapped (green) + + // Rectangle { + // anchors.fill: parent + // color: "lightgrey" + // } + + x: root.screenPoint.x - width / 2 + y: root.screenPoint.y - height / 2 + + Behavior on x { + PropertyAnimation { + properties: "x" + duration: 50 + easing.type: Easing.InQuad + } } - } - Behavior on y { - PropertyAnimation { - properties: "y" - duration: 50 - easing.type: Easing.InQuad + Behavior on y { + PropertyAnimation { + properties: "y" + duration: 50 + easing.type: Easing.InQuad + } } - } - opacity: snapUtils.snapped ? 0 : 100 + opacity: snapUtils.snapped ? 0 : 100 - Behavior on opacity { - PropertyAnimation { - properties: "opacity" - duration: 100 - easing.type: Easing.InQuad + Behavior on opacity { + PropertyAnimation { + properties: "opacity" + duration: 100 + easing.type: Easing.InQuad + } } - } - height: root.innerDotSize - width: height - sourceSize.width: width - sourceSize.height: height + height: root.innerDotSize + width: height + sourceSize.width: width + sourceSize.height: height - source: __style.crosshairCenterImage + source: __style.crosshairCenterImage } Image { - id: crossCenterPlus // Center plus - visible when not snapped (purple) - - x: root.screenPoint.x - width / 2 - y: root.screenPoint.y - height / 2 - - Behavior on x { - PropertyAnimation { - properties: "x" - duration: 50 - easing.type: Easing.InQuad + id: crossCenterPlus // Center plus - visible when not snapped (purple) + + // Rectangle { + // anchors.fill: parent + // color: "lightseagreen" + // } + + x: root.screenPoint.x - width / 2 + y: root.screenPoint.y - height / 2 + + Behavior on x { + PropertyAnimation { + properties: "x" + duration: 50 + easing.type: Easing.InQuad + } } - } - Behavior on y { - PropertyAnimation { - properties: "y" - duration: 50 - easing.type: Easing.InQuad + Behavior on y { + PropertyAnimation { + properties: "y" + duration: 50 + easing.type: Easing.InQuad + } } - } - opacity: snapUtils.snapped && ( snapUtils.snapType === MM.SnapUtils.Vertex || snapUtils.snapType === MM.SnapUtils.Other ) ? 100 : 0 + opacity: snapUtils.snapped && ( snapUtils.snapType === MM.SnapUtils.Vertex || snapUtils.snapType === MM.SnapUtils.Other ) ? 100 : 0 - Behavior on opacity { - PropertyAnimation { - properties: "opacity" - duration: 100 - easing.type: Easing.InQuad + Behavior on opacity { + PropertyAnimation { + properties: "opacity" + duration: 100 + easing.type: Easing.InQuad + } } - } - rotation: snapUtils.snapType === MM.SnapUtils.Other ? 0 : 45 + rotation: snapUtils.snapType === MM.SnapUtils.Other ? 0 : 45 - Behavior on rotation { - PropertyAnimation { - properties: "rotation" - duration: 50 - easing.type: Easing.InQuad + Behavior on rotation { + PropertyAnimation { + properties: "rotation" + duration: 50 + easing.type: Easing.InQuad + } } - } - height: root.innerDotSize * 2 - width: height - sourceSize.width: width - sourceSize.height: height + height: root.innerDotSize * 2 + width: height + sourceSize.width: width + sourceSize.height: height - // Important: must be same color as __style.snappingColor - source: __style.crosshairPlusImage + // Important: must be same color as __style.snappingColor + source: __style.crosshairPlusImage } Image { - id: crossCenterCircle // Center circle - visible when snapped to segment (purple) - - x: root.screenPoint.x - width / 2 - y: root.screenPoint.y - height / 2 - - Behavior on x { - PropertyAnimation { - properties: "x" - duration: 50 - easing.type: Easing.InQuad + id: crossCenterCircle // Center circle - visible when snapped to segment (purple) + + // Rectangle { + // anchors.fill: parent + // color: "lightsteelblue" + // } + + x: root.screenPoint.x - width / 2 + y: root.screenPoint.y - height / 2 + + Behavior on x { + PropertyAnimation { + properties: "x" + duration: 50 + easing.type: Easing.InQuad + } } - } - Behavior on y { - PropertyAnimation { - properties: "y" - duration: 50 - easing.type: Easing.InQuad + Behavior on y { + PropertyAnimation { + properties: "y" + duration: 50 + easing.type: Easing.InQuad + } } - } - opacity: snapUtils.snapped && snapUtils.snapType === MM.SnapUtils.Segment ? 100 : 0 + opacity: snapUtils.snapped && snapUtils.snapType === MM.SnapUtils.Segment ? 100 : 0 - Behavior on opacity { - PropertyAnimation { - properties: "opacity" - duration: 100 - easing.type: Easing.InQuad + Behavior on opacity { + PropertyAnimation { + properties: "opacity" + duration: 100 + easing.type: Easing.InQuad + } } - } - height: root.innerDotSize * 2 - width: height - sourceSize.width: width - sourceSize.height: height + height: root.innerDotSize * 2 + width: height + sourceSize.width: width + sourceSize.height: height - // Important: must be same color as __style.snappingColor - source: __style.crosshairCircleImage + // Important: must be same color as __style.snappingColor + source: __style.crosshairCircleImage + } + + MMMapLabel { + // Rectangle { + // anchors.fill: parent + // color: "lightgoldenrodyellow" + // } + + //height:50 + //width: 70 + visible: true //root.state !== "inactive" && root.isStreaming + //iconSource: __style.streamingIcon + + maxWidth: crosshairForeground.width + 6 * __dp + bgColor: __style.forestColor + textColor: __style.polarColor + textBgColorInverted: false + + text: qsTr( "Test" ) + + anchors.top: crosshairForeground.bottom + anchors.horizontalCenter: crosshairForeground.horizontalCenter + + onClicked: console.log("MapLabel") } Connections { - target: __activeProject - - function onProjectWillBeReloaded() { - snapUtils.clear() - } - - function onProjectReloaded( project ) { - // We need to re-assign qgs project to snaputils, because - // even though we loaded a different project, - // internally we keep the same pointer for QgsProject. - snapUtils.qgsProject = __activeProject.qgsProject - snapUtils.mapSettings = root.mapSettings - } + + target: __activeProject + + function onProjectWillBeReloaded() { + snapUtils.clear() + } + + function onProjectReloaded( project ) { + // We need to re-assign qgs project to snaputils, because + // even though we loaded a different project, + // internally we keep the same pointer for QgsProject. + snapUtils.qgsProject = __activeProject.qgsProject + snapUtils.mapSettings = root.mapSettings + } } } diff --git a/app/qml/map/components/MMMapLabel.qml b/app/qml/map/components/MMMapLabel.qml index 2127ddeea..ac58adf96 100644 --- a/app/qml/map/components/MMMapLabel.qml +++ b/app/qml/map/components/MMMapLabel.qml @@ -53,6 +53,7 @@ Item { source: control.iconSource ? control.iconSource : "" color: control.textColor size: __style.icon24 + visible: control.iconSource ? true : false } Rectangle { From e20055f03f80d313e8255b37b28ef45ac1f6a1b8 Mon Sep 17 00:00:00 2001 From: VitorVieiraZ Date: Wed, 14 Aug 2024 21:40:33 -0300 Subject: [PATCH 04/60] adding label support to MMCrosshair --- app/qml/map/MMRecordingTools.qml | 4 +++- app/qml/map/components/MMCrosshair.qml | 25 ++++++++++++++++++++++ app/qml/map/components/MMDataCrosshair.qml | 13 +---------- app/qml/map/components/MMMapLabel.qml | 4 ++-- 4 files changed, 31 insertions(+), 15 deletions(-) diff --git a/app/qml/map/MMRecordingTools.qml b/app/qml/map/MMRecordingTools.qml index 24d1b9a14..579042b15 100644 --- a/app/qml/map/MMRecordingTools.qml +++ b/app/qml/map/MMRecordingTools.qml @@ -144,7 +144,7 @@ Item { accuracyRingSize: positionMarkerComponent.accuracyRingSize } - MMDataCrosshair { + MMCrosshair { //labeled crosshair id: crosshair anchors.fill: parent @@ -154,6 +154,8 @@ Item { qgsProject: __activeProject.qgsProject mapSettings: root.map.mapSettings shouldUseSnapping: !mapTool.isUsingPosition + hasLabel: true + crosshairLabelText: "58.4 m" } MMHighlight { diff --git a/app/qml/map/components/MMCrosshair.qml b/app/qml/map/components/MMCrosshair.qml index a9c7ec465..8ae283ee1 100644 --- a/app/qml/map/components/MMCrosshair.qml +++ b/app/qml/map/components/MMCrosshair.qml @@ -19,6 +19,9 @@ Item { /*required*/ property var mapSettings property bool shouldUseSnapping: false + property bool hasLabel: false + property string crosshairLabelText: "" + property point center: Qt.point( root.width / 2, root.height / 2 ) property var recordPoint: snapUtils.recordPoint @@ -39,6 +42,14 @@ Item { } + Loader { + id: crosshairLabelLoader + active: root.hasLabel + sourceComponent: crosshairLabelComponent + anchors.top: crosshairForeground.bottom + anchors.horizontalCenter: crosshairForeground.horizontalCenter + } + Image { id: crosshairBackground // white background of the crosshair @@ -237,6 +248,20 @@ Item { source: __style.crosshairCircleImage } + Component { + id: crosshairLabelComponent + + MMMapLabel { + bgColor: __style.forestColor + textColor: __style.polarColor + textBgColorInverted: false + hasIcon: false + text: root.crosshairLabelText + + onClicked: console.log( "MapLabel" ) + } + } + Connections { target: __activeProject diff --git a/app/qml/map/components/MMDataCrosshair.qml b/app/qml/map/components/MMDataCrosshair.qml index ee3e5036c..9e59f3eaf 100644 --- a/app/qml/map/components/MMDataCrosshair.qml +++ b/app/qml/map/components/MMDataCrosshair.qml @@ -273,21 +273,10 @@ Item { } MMMapLabel { - // Rectangle { - // anchors.fill: parent - // color: "lightgoldenrodyellow" - // } - - //height:50 - //width: 70 - visible: true //root.state !== "inactive" && root.isStreaming - //iconSource: __style.streamingIcon - - maxWidth: crosshairForeground.width + 6 * __dp bgColor: __style.forestColor textColor: __style.polarColor textBgColorInverted: false - + hasIcon: false text: qsTr( "Test" ) anchors.top: crosshairForeground.bottom diff --git a/app/qml/map/components/MMMapLabel.qml b/app/qml/map/components/MMMapLabel.qml index ac58adf96..72a67365b 100644 --- a/app/qml/map/components/MMMapLabel.qml +++ b/app/qml/map/components/MMMapLabel.qml @@ -28,6 +28,7 @@ Item { property color bgColor: __style.positiveColor property color textColor: __style.forestColor property bool textBgColorInverted: false + property bool hasIcon: true Rectangle { width: row.width @@ -52,8 +53,7 @@ Item { anchors.verticalCenter: parent.verticalCenter source: control.iconSource ? control.iconSource : "" color: control.textColor - size: __style.icon24 - visible: control.iconSource ? true : false + size: control.hasIcon ? __style.icon24 : 0 } Rectangle { From 6b879bc65570290200c62f389d56017e48c7d47d Mon Sep 17 00:00:00 2001 From: VitorVieiraZ Date: Wed, 14 Aug 2024 21:42:36 -0300 Subject: [PATCH 05/60] removing unused datacrosshair --- app/qml/CMakeLists.txt | 1 - app/qml/map/components/MMDataCrosshair.qml | 304 --------------------- 2 files changed, 305 deletions(-) delete mode 100644 app/qml/map/components/MMDataCrosshair.qml diff --git a/app/qml/CMakeLists.txt b/app/qml/CMakeLists.txt index 59db38dce..ac5016cbf 100644 --- a/app/qml/CMakeLists.txt +++ b/app/qml/CMakeLists.txt @@ -138,7 +138,6 @@ set(MM_QML map/MMMeasurementTools.qml map/components/MMHidingBox.qml map/components/MMCrosshair.qml - map/components/MMDataCrosshair.qml map/components/MMMapHidingLabel.qml map/components/MMMapButton.qml map/components/MMMapLabel.qml diff --git a/app/qml/map/components/MMDataCrosshair.qml b/app/qml/map/components/MMDataCrosshair.qml deleted file mode 100644 index 9e59f3eaf..000000000 --- a/app/qml/map/components/MMDataCrosshair.qml +++ /dev/null @@ -1,304 +0,0 @@ -/*************************************************************************** - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - ***************************************************************************/ - -import QtQuick -import Qt5Compat.GraphicalEffects - -import mm 1.0 as MM - -Item { - id: root - - // Rectangle { //map - // anchors.fill: parent - // color: "lightblue" - // } - - /*required*/ property var qgsProject - /*required*/ property var mapSettings - property bool shouldUseSnapping: false - - property point center: Qt.point( root.width / 2, root.height / 2 ) - - property var recordPoint: snapUtils.recordPoint - - property point screenPoint: snapUtils.snapped && __activeLayer.vectorLayer ? __inputUtils.transformPointToScreenCoordinates(__activeLayer.vectorLayer.crs, mapSettings, recordPoint) : center - - property real outerSize: 60 * __dp - property real innerDotSize: 10 * __dp - - MM.SnapUtils { - id: snapUtils - - centerPosition: root.center - mapSettings: root.mapSettings - qgsProject: root.qgsProject - useSnapping: root.shouldUseSnapping - destinationLayer: __activeLayer.vectorLayer - - } - - Image { - id: crosshairBackground // white background of the crosshair - - // Rectangle { - // anchors.fill: parent - // color: "lightcoral" - // } - - x: root.screenPoint.x - width / 2 - y: root.screenPoint.y - height / 2 - - Behavior on x { - PropertyAnimation { - properties: "x" - duration: 50 - easing.type: Easing.InQuad - } - } - - Behavior on y { - PropertyAnimation { - properties: "y" - duration: 50 - easing.type: Easing.InQuad - } - } - - height: root.outerSize - width: height - - source: __style.crosshairBackgroundImage - sourceSize.width: width - sourceSize.height: height - } - - Image { - id: crosshairForeground // green / purple outer circle of the crosshair - - // Rectangle { - // anchors.fill: parent - // color: "lightyellow" - // } - - x: root.screenPoint.x - width / 2 - y: root.screenPoint.y - height / 2 - - Behavior on x { - PropertyAnimation { - properties: "x" - duration: 50 - easing.type: Easing.InQuad - } - } - - Behavior on y { - PropertyAnimation { - properties: "y" - duration: 50 - easing.type: Easing.InQuad - } - } - - height: root.outerSize - width: height - - source: __style.crosshairForegroundImage - sourceSize.width: width - sourceSize.height: height - } - - ColorOverlay { - anchors.fill: crosshairForeground - source: crosshairForeground - color: snapUtils.snapped ? __style.snappingColor : __style.forestColor - - // Rectangle { - // anchors.fill: parent - // color: "lightpink" - // } - } - - Image { - id: crossCenterDot // Center dot - visible when not snapped (green) - - // Rectangle { - // anchors.fill: parent - // color: "lightgrey" - // } - - x: root.screenPoint.x - width / 2 - y: root.screenPoint.y - height / 2 - - Behavior on x { - PropertyAnimation { - properties: "x" - duration: 50 - easing.type: Easing.InQuad - } - } - - Behavior on y { - PropertyAnimation { - properties: "y" - duration: 50 - easing.type: Easing.InQuad - } - } - - opacity: snapUtils.snapped ? 0 : 100 - - Behavior on opacity { - PropertyAnimation { - properties: "opacity" - duration: 100 - easing.type: Easing.InQuad - } - } - - height: root.innerDotSize - width: height - sourceSize.width: width - sourceSize.height: height - - source: __style.crosshairCenterImage - } - - Image { - id: crossCenterPlus // Center plus - visible when not snapped (purple) - - // Rectangle { - // anchors.fill: parent - // color: "lightseagreen" - // } - - x: root.screenPoint.x - width / 2 - y: root.screenPoint.y - height / 2 - - Behavior on x { - PropertyAnimation { - properties: "x" - duration: 50 - easing.type: Easing.InQuad - } - } - - Behavior on y { - PropertyAnimation { - properties: "y" - duration: 50 - easing.type: Easing.InQuad - } - } - - opacity: snapUtils.snapped && ( snapUtils.snapType === MM.SnapUtils.Vertex || snapUtils.snapType === MM.SnapUtils.Other ) ? 100 : 0 - - Behavior on opacity { - PropertyAnimation { - properties: "opacity" - duration: 100 - easing.type: Easing.InQuad - } - } - - rotation: snapUtils.snapType === MM.SnapUtils.Other ? 0 : 45 - - Behavior on rotation { - PropertyAnimation { - properties: "rotation" - duration: 50 - easing.type: Easing.InQuad - } - } - - height: root.innerDotSize * 2 - width: height - sourceSize.width: width - sourceSize.height: height - - // Important: must be same color as __style.snappingColor - source: __style.crosshairPlusImage - } - - Image { - id: crossCenterCircle // Center circle - visible when snapped to segment (purple) - - // Rectangle { - // anchors.fill: parent - // color: "lightsteelblue" - // } - - x: root.screenPoint.x - width / 2 - y: root.screenPoint.y - height / 2 - - Behavior on x { - PropertyAnimation { - properties: "x" - duration: 50 - easing.type: Easing.InQuad - } - } - - Behavior on y { - PropertyAnimation { - properties: "y" - duration: 50 - easing.type: Easing.InQuad - } - } - - opacity: snapUtils.snapped && snapUtils.snapType === MM.SnapUtils.Segment ? 100 : 0 - - Behavior on opacity { - PropertyAnimation { - properties: "opacity" - duration: 100 - easing.type: Easing.InQuad - } - } - - height: root.innerDotSize * 2 - width: height - sourceSize.width: width - sourceSize.height: height - - // Important: must be same color as __style.snappingColor - source: __style.crosshairCircleImage - } - - MMMapLabel { - bgColor: __style.forestColor - textColor: __style.polarColor - textBgColorInverted: false - hasIcon: false - text: qsTr( "Test" ) - - anchors.top: crosshairForeground.bottom - anchors.horizontalCenter: crosshairForeground.horizontalCenter - - onClicked: console.log("MapLabel") - } - - Connections { - - target: __activeProject - - function onProjectWillBeReloaded() { - snapUtils.clear() - } - - function onProjectReloaded( project ) { - // We need to re-assign qgs project to snaputils, because - // even though we loaded a different project, - // internally we keep the same pointer for QgsProject. - snapUtils.qgsProject = __activeProject.qgsProject - snapUtils.mapSettings = root.mapSettings - } - } -} From 6561eac437684c838ae57349bbe02777f90dcb96 Mon Sep 17 00:00:00 2001 From: VitorVieiraZ Date: Thu, 15 Aug 2024 17:09:40 -0300 Subject: [PATCH 06/60] top left button support for mmdrawer --- app/qml/CMakeLists.txt | 2 +- app/qml/components/MMDrawer.qml | 8 + app/qml/components/MMDrawerHeader.qml | 38 +++ app/qml/gps/MMMeasureDrawer.qml | 105 +++++++++ app/qml/gps/MMStakeoutDrawer.qml | 1 - app/qml/main.qml | 37 ++- app/qml/map/MMMapController.qml | 15 ++ app/qml/map/MMMeasurementTools.qml | 322 ++++++++++++++++++++++++++ app/qml/map/MMRecordingTools.qml | 4 +- 9 files changed, 526 insertions(+), 6 deletions(-) create mode 100644 app/qml/gps/MMMeasureDrawer.qml diff --git a/app/qml/CMakeLists.txt b/app/qml/CMakeLists.txt index ac5016cbf..7f8ab2349 100644 --- a/app/qml/CMakeLists.txt +++ b/app/qml/CMakeLists.txt @@ -116,6 +116,7 @@ set(MM_QML gps/MMGpsDataDrawer.qml gps/MMPositionProviderPage.qml gps/MMStakeoutDrawer.qml + gps/MMMeasureDrawer.qml gps/components/MMGpsDataText.qml inputs/MMComboboxInput.qml inputs/MMPasswordInput.qml @@ -135,7 +136,6 @@ set(MM_QML map/MMSplittingTools.qml map/MMStakeoutTools.qml map/MMRecordingTools.qml - map/MMMeasurementTools.qml map/components/MMHidingBox.qml map/components/MMCrosshair.qml map/components/MMMapHidingLabel.qml diff --git a/app/qml/components/MMDrawer.qml b/app/qml/components/MMDrawer.qml index 4badaa59f..fe8e1c270 100644 --- a/app/qml/components/MMDrawer.qml +++ b/app/qml/components/MMDrawer.qml @@ -28,6 +28,10 @@ Drawer { readonly property real drawerReservedVerticalSpace: topSpacer.height + mmDrawerHeader.height + contentSpacer.height + bottomSpacer.height readonly property real drawerContentAvailableHeight: maxHeight - drawerReservedVerticalSpace // max height for your custom content item + property string leftButtonIcon: "" + property string leftButtonText: "" + property string leftButtonType: MMButton.Types.Primary + implicitHeight: contentHeight > maxHeight ? maxHeight : contentHeight implicitWidth: ApplicationWindow.window?.width ?? 0 @@ -74,6 +78,10 @@ Drawer { width: parent.width + leftButtonIcon: root.leftButtonIcon + leftButtonText: root.leftButtonText + leftButtonType: root.leftButtonType + onCloseClicked: { root.close() } diff --git a/app/qml/components/MMDrawerHeader.qml b/app/qml/components/MMDrawerHeader.qml index 8d5a5cfc2..20c8aea36 100644 --- a/app/qml/components/MMDrawerHeader.qml +++ b/app/qml/components/MMDrawerHeader.qml @@ -22,15 +22,53 @@ Rectangle { property font titleFont: __style.t3 property bool hasCloseButton: true + + property string leftButtonIcon: "" + property string leftButtonText: "" + property string leftButtonType: MMButton.Types.Primary + property alias closeButton: closeBtn + property alias leftButton: leftBtn color: __style.transparentColor signal closeClicked + signal leftButtonClicked implicitHeight: 60 * __dp implicitWidth: ApplicationWindow.window?.width ?? 0 + // MMRoundButton { + // id: leftBtn + + // iconSource: __style.addIcon + // iconColor: __style.forestColor + + // bgndColor: __style.grassColor + // bgndHoverColor: __style.mediumGreenColor + + // onClicked: root.createWorkspaceRequested() + // } + + MMButton { + id: leftBtn + + type: root.leftButtonType + text: root.leftButtonText + iconSourceLeft: root.leftButtonIcon + bgndColor: __style.lightGreenColor + + visible: true //root.leftButtonIcon + + anchors { + left: parent.left + leftMargin: __style.pageMargins + __style.safeAreaLeft + verticalCenter: parent.verticalCenter + } + + onClicked: root.leftButtonClicked() + } + Text { // If the close button is visible, we need to properly center the text property real margin: internal.closeBtnRealWidth + internal.headerSpacing + __style.pageMargins diff --git a/app/qml/gps/MMMeasureDrawer.qml b/app/qml/gps/MMMeasureDrawer.qml new file mode 100644 index 000000000..01614d0bd --- /dev/null +++ b/app/qml/gps/MMMeasureDrawer.qml @@ -0,0 +1,105 @@ +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +import QtQuick +import QtQuick.Layouts +import QtQuick.Controls +import Qt5Compat.GraphicalEffects +import QtQuick.Shapes + +import mm 1.0 as MM + +import "../components" +import "../map/components" +import "./components" as MMGpsComponents + +MMDrawer { + id: root + + property var mapCanvas + + property var targetPair: null + // property real remainingDistance: targetPair ? __inputUtils.distanceBetweenGpsAndFeature( + // __positionKit.positionCoordinate, + // targetPair, + // mapCanvas.mapSettings ) : -1 + property bool closeShapeActive: true + + readonly property alias panelHeight: root.height + + signal panelHeightUpdated() + signal stakeoutFinished() + + Component.onCompleted: { + root.open() + } + + // function endStakeout() { + // if ( mapCanvas.state !== "stakeout" ) + // return; + + // stakeoutFinished() + // } + + // function hide() { + // root.close() + // } + + // function restore() { + // root.open() + // } + + // Behavior on height { + // SequentialAnimation { + // PropertyAnimation { properties: "height"; easing.type: Easing.InOutQuad } + // ScriptAction { script: root.panelHeightUpdated() } + // } + // } + + modal: false + + closePolicy: Popup.CloseOnEscape // prevents the drawer closing while moving canvas + + dropShadow: true + + //onClosed: root.endStakeout() + + leftButtonText: "Undo" + leftButtonIcon: __style.undoIcon + leftButtonType: MMButton.Types.Primary + + drawerHeader.title: qsTr("Measure") + + drawerContent: Column { + id: mainColumn + + width: parent.width + spacing: __style.margin12 + + Row { + width: parent.width + + MMGpsComponents.MMGpsDataText{ + width: ( parent.width + parent.spacing ) / 2 + + title: closeShapeActive ? qsTr( "Perimeter" ) : qsTr( "Length" ) + value: "58.4 m" //remainingDistance >= 0 ?__inputUtils.formatDistanceInProjectUnit( remainingDistance, 2 ) : qsTr( "N/A" ) + } + + MMGpsComponents.MMGpsDataText{ + width: ( parent.width + parent.spacing ) / 2 + + title: qsTr( "Area" ) + value: "0.00 m" + alignmentRight: true + visible: closeShapeActive + } + } + } +} diff --git a/app/qml/gps/MMStakeoutDrawer.qml b/app/qml/gps/MMStakeoutDrawer.qml index 918436976..b1f6fd657 100644 --- a/app/qml/gps/MMStakeoutDrawer.qml +++ b/app/qml/gps/MMStakeoutDrawer.qml @@ -97,7 +97,6 @@ MMDrawer { Row { width: parent.width - spacing: __style.margi8 MMGpsComponents.MMGpsDataText{ width: ( parent.width + parent.spacing ) / 2 diff --git a/app/qml/main.qml b/app/qml/main.qml index 746ef4327..cb6dc998d 100644 --- a/app/qml/main.qml +++ b/app/qml/main.qml @@ -219,6 +219,12 @@ ApplicationWindow { stakeoutPanelLoader.item.targetPair = pair } + onMeasureStarted: function( pair ) { + measurePanelLoader.active = true + measurePanelLoader.focus = true + measurePanelLoader.item.targetPair = pair + } + onLocalChangesPanelRequested: { stateManager.state = "projects" projectController.openChangesPanel( __activeProject.projectFullName(), true ) @@ -330,7 +336,13 @@ ApplicationWindow { text: qsTr("Measure") iconSource: __style.measurementToolIcon onClicked: { - console.log(" Measurement tool") + if ( __recordingLayersModel.rowCount() > 0 ) { + stateManager.state = "map" + map.measure() + } + else { + __notificationModel.addInfo( qsTr( "No editable layers found." ) ) + } } } @@ -604,6 +616,29 @@ ApplicationWindow { } } + Loader { + id: measurePanelLoader + + focus: true + active: false + asynchronous: true + + sourceComponent: measurePanelComponent + } + + Component { + id: measurePanelComponent + + MMMeasureDrawer { + id: measurePanel + + width: window.width + + mapCanvas: map + + } + } + MMFormStackController { id: formsStackManager diff --git a/app/qml/map/MMMapController.qml b/app/qml/map/MMMapController.qml index a1c8c7fb4..b340c9b19 100644 --- a/app/qml/map/MMMapController.qml +++ b/app/qml/map/MMMapController.qml @@ -60,6 +60,8 @@ Item { signal stakeoutStarted( var pair ) signal accuracyButtonClicked() + signal measureStarted() + signal localChangesPanelRequested() signal openTrackingPanel() @@ -86,6 +88,9 @@ Item { State { name: "stakeout" }, + State { + name: "measure" + }, State { name: "inactive" // ignores touch input } @@ -143,6 +148,12 @@ Item { break } + case "measure": { + root.hideHighlight() + root.measureStarted() + break + } + case "inactive": { break } @@ -1245,6 +1256,10 @@ Item { } } + function measure() { + state = "measure" + } + function showInfoTextMessage( message ) { hideInfoTextMessage() diff --git a/app/qml/map/MMMeasurementTools.qml b/app/qml/map/MMMeasurementTools.qml index 5560aee72..3e6431fcb 100644 --- a/app/qml/map/MMMeasurementTools.qml +++ b/app/qml/map/MMMeasurementTools.qml @@ -1,5 +1,327 @@ +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + import QtQuick +import QtQuick.Shapes + +import mm 1.0 as MM + +import "../components" +import "./components" +/** + * RecordingTools is a set of tools that are used during recording/editing of a geometry. + * These tools can be instantiated just for the time of recording and then destroyed. + */ Item { + id: root + + required property MMMapCanvas map + required property MMPositionMarker positionMarkerComponent + + property alias recordingMapTool: mapTool + + property var activeFeature + + signal canceled() + signal done( var featureLayerPair ) + + function toggleStreaming() { + if ( mapTool.recordingType === MM.RecordingMapTool.Manual ) + { + mapTool.recordingType = MM.RecordingMapTool.StreamMode + + // add first point immediately + mapTool.addPoint( crosshair.recordPoint ) + root.map.mapSettings.setCenter( mapPositionSource.mapPosition ) + } + else + { + mapTool.recordingType = MM.RecordingMapTool.Manual + } + } + + MM.RecordingMapTool { + id: mapTool + + property bool isUsingPosition: mapTool.centeredToGPS || mapTool.recordingType == MM.RecordingMapTool.StreamMode + + mapSettings: root.map.mapSettings + + recordPoint: crosshair.recordPoint + + recordingType: MM.RecordingMapTool.Manual + recordingInterval: __appSettings.lineRecordingInterval + recordingIntervalType: __appSettings.intervalType + + positionKit: __positionKit + activeLayer: __activeLayer.vectorLayer + activeFeature: root.activeFeature + + // Bind variables manager to know if we are centered to GPS or not when evaluating position variables + onIsUsingPositionChanged: __variablesManager.useGpsPoint = isUsingPosition + + onActiveVertexChanged: function( activeVertex ) { + if ( activeVertex.isValid() ) + { + // Center to clicked vertex + let newCenter = mapTool.vertexMapCoors( activeVertex ) + + if ( !isNaN( newCenter.x ) && !isNaN( newCenter.y ) ) + { + root.map.jumpTo( /*crosshair.screenPoint,*/ root.map.mapSettings.coordinateToScreen( newCenter ) ) + } + } + } + } + + MM.GuidelineController { + id: guidelineController + + allowed: mapTool.state !== MM.RecordingMapTool.View && mapTool.recordingType !== MM.RecordingMapTool.StreamMode + + mapSettings: root.map.mapSettings + insertPolicy: mapTool.insertPolicy + crosshairPosition: crosshair.screenPoint + realGeometry: __inputUtils.transformGeometryToMapWithLayer( mapTool.recordedGeometry, __activeLayer.vectorLayer, root.map.mapSettings ) + + activeVertex: mapTool.activeVertex + activePart: mapTool.activePart + activeRing: mapTool.activeRing + } + + MMHighlight { + id: highlight + + height: root.map.height + width: root.map.width + + visible: !__inputUtils.isPointLayer(__activeLayer.vectorLayer) + + mapSettings: root.map.mapSettings + geometry: __inputUtils.transformGeometryToMapWithLayer( mapTool.recordedGeometry, __activeLayer.vectorLayer, root.map.mapSettings ) + + lineBorderWidth: 0 + } + + MMHighlight { + id: handlesHighlight + + height: root.map.height + width: root.map.width + + mapSettings: root.map.mapSettings + geometry: __inputUtils.transformGeometryToMapWithLayer( mapTool.handles, __activeLayer.vectorLayer, root.map.mapSettings ) + + lineStrokeStyle: ShapePath.DashLine + lineWidth: MMHighlight.LineWidths.Narrow + } + + MMHighlight { + id: guideline + + height: root.map.height + width: root.map.width + + lineWidth: MMHighlight.LineWidths.Narrow + lineStrokeStyle: ShapePath.DashLine + + mapSettings: root.map.mapSettings + geometry: guidelineController.guidelineGeometry + } + + MMHighlight { + id: midSegmentsHighlight + + height: root.map.height + width: root.map.width + + mapSettings: root.map.mapSettings + geometry: __inputUtils.transformGeometryToMapWithLayer( mapTool.midPoints, __activeLayer.vectorLayer, root.map.mapSettings ) + + markerType: MMHighlight.MarkerTypes.Circle + markerBorderColor: __style.grapeColor + } + + MMHighlight { + id: existingVerticesHighlight + + height: root.map.height + width: root.map.width + + mapSettings: root.map.mapSettings + geometry: __inputUtils.transformGeometryToMapWithLayer( mapTool.existingVertices, __activeLayer.vectorLayer, root.map.mapSettings ) + + markerType: MMHighlight.MarkerTypes.Circle + markerSize: MMHighlight.MarkerSizes.Bigger + } + + // Duplicate position marker to be painted on the top of highlights + MMPositionMarker { + xPos: positionMarkerComponent.xPos + yPos: positionMarkerComponent.yPos + hasDirection: positionMarkerComponent.hasDirection + + direction: positionMarkerComponent.direction + hasPosition: positionMarkerComponent.hasPosition + + horizontalAccuracy: positionMarkerComponent.horizontalAccuracy + accuracyRingSize: positionMarkerComponent.accuracyRingSize + } + + MMCrosshair { //labeled crosshair + id: crosshair + + anchors.fill: parent + + visible: mapTool.state !== MM.RecordingMapTool.View && mapTool.recordingType !== MM.RecordingMapTool.StreamMode + + qgsProject: __activeProject.qgsProject + mapSettings: root.map.mapSettings + shouldUseSnapping: !mapTool.isUsingPosition + hasLabel: true + crosshairLabelText: "58.4 m" + } + + MMToolbar { + y: parent.height + + ObjectModel { + id: polygonToolbarButtons + + MMToolbarButton { + text: qsTr( "Undo" ) + iconSource: __style.undoIcon + onClicked: mapTool.undo() + enabled: mapTool.canUndo + } + + MMToolbarButton { + text: qsTr( "Remove" ) + iconSource: __style.minusIcon + onClicked: mapTool.removePoint() + + enabled: { + if ( mapTool.recordingType !== MM.RecordingMapTool.Manual ) return false; + if ( mapTool.state === MM.RecordingMapTool.View ) return false; + if ( __inputUtils.isEmptyGeometry( mapTool.recordedGeometry ) ) return false; + + return true; + } + } + + MMToolbarButton { + text: qsTr( "Release" ) + visible: mapTool.state === MM.RecordingMapTool.Grab + iconSource: __style.addIcon + onClicked: { + if ( mapTool.state === MM.RecordingMapTool.Grab ) { + mapTool.releaseVertex( crosshair.recordPoint ) + } + else { + mapTool.addPoint( crosshair.recordPoint ) + } + } + } + + MMToolbarButton { + text: qsTr( "Add" ) + + visible: mapTool.state === MM.RecordingMapTool.View || mapTool.state === MM.RecordingMapTool.Record + enabled: mapTool.recordingType === MM.RecordingMapTool.Manual && mapTool.state !== MM.RecordingMapTool.View + + iconSource: __style.addIcon + onClicked: { + if ( mapTool.state === MM.RecordingMapTool.Grab ) { + mapTool.releaseVertex( crosshair.recordPoint ) + } + else { + mapTool.addPoint( crosshair.recordPoint ) + } + } + } + + MMToolbarButton { + text: qsTr( "Record" ) + + iconSource: __style.doneCircleIcon + iconColor: __style.grassColor + onClicked: { + if ( mapTool.hasValidGeometry() ) + { + // If we currently grab a point + if ( mapTool.state === MM.RecordingMapTool.Grab ) + { + mapTool.releaseVertex( crosshair.recordPoint ) + } + + let pair = mapTool.getFeatureLayerPair() + root.done( pair ) + } + else + { + __notificationModel.addWarning( __inputUtils.invalidGeometryWarning( mapTool.activeLayer ) ) + } + } + } + } + + ObjectModel { + id: pointToolbarButtons + + MMToolbarButton { + text: qsTr( "Record" ); + iconSource: __style.doneCircleIcon; + iconColor: __style.forestColor + onClicked: { + if ( mapTool.state === MM.RecordingMapTool.Grab ) + { + // editing existing point geometry + mapTool.releaseVertex( crosshair.recordPoint ) + } else + { + // recording new point + mapTool.addPoint( crosshair.recordPoint ) + } + + let pair = mapTool.getFeatureLayerPair() + root.done( pair ) + } + } + } + + model: { + let pointLayerSelected = __inputUtils.isPointLayer( __activeLayer.vectorLayer ) + let isMultiPartLayerSelected = __inputUtils.isMultiPartLayer( __activeLayer.vectorLayer ) + + if ( pointLayerSelected && !isMultiPartLayerSelected ) { + return pointToolbarButtons + } + return polygonToolbarButtons + } + } + + Connections { + target: map + function onClicked( point ) { + let screenPoint = Qt.point( point.x, point.y ) + + mapTool.lookForVertex( screenPoint ) + } + } + + function discardChanges() { + mapTool.discardChanges() + root.canceled() + } + function hasChanges() { + return mapTool.hasChanges() + } } diff --git a/app/qml/map/MMRecordingTools.qml b/app/qml/map/MMRecordingTools.qml index 579042b15..babe68419 100644 --- a/app/qml/map/MMRecordingTools.qml +++ b/app/qml/map/MMRecordingTools.qml @@ -144,7 +144,7 @@ Item { accuracyRingSize: positionMarkerComponent.accuracyRingSize } - MMCrosshair { //labeled crosshair + MMCrosshair { id: crosshair anchors.fill: parent @@ -154,8 +154,6 @@ Item { qgsProject: __activeProject.qgsProject mapSettings: root.map.mapSettings shouldUseSnapping: !mapTool.isUsingPosition - hasLabel: true - crosshairLabelText: "58.4 m" } MMHighlight { From 04dca5d1f237234cc4cff07ed6dafdedac95b1bb Mon Sep 17 00:00:00 2001 From: VitorVieiraZ Date: Thu, 15 Aug 2024 17:40:44 -0300 Subject: [PATCH 07/60] close shape icon, new buttons for measure drawer, new connections --- app/icons/CloseShape.svg | 7 ++++ app/icons/icons.qrc | 1 + app/mmstyle.h | 2 ++ app/qml/CMakeLists.txt | 1 + app/qml/components/MMDrawerHeader.qml | 2 +- app/qml/gps/MMMeasureDrawer.qml | 52 ++++++++++++++++----------- app/qml/main.qml | 5 +++ gallery/qml/pages/IconsPage.qml | 1 + 8 files changed, 50 insertions(+), 21 deletions(-) create mode 100644 app/icons/CloseShape.svg diff --git a/app/icons/CloseShape.svg b/app/icons/CloseShape.svg new file mode 100644 index 000000000..594a3a78e --- /dev/null +++ b/app/icons/CloseShape.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/app/icons/icons.qrc b/app/icons/icons.qrc index 4166c8ae7..3f88e0ec6 100644 --- a/app/icons/icons.qrc +++ b/app/icons/icons.qrc @@ -98,5 +98,6 @@ StakeOut.svg Student.svg Measure.svg + CloseShape.svg diff --git a/app/mmstyle.h b/app/mmstyle.h index 98096c3fc..7529e9670 100644 --- a/app/mmstyle.h +++ b/app/mmstyle.h @@ -169,6 +169,7 @@ class MMStyle: public QObject Q_PROPERTY( QUrl redrawGeometryIcon READ redrawGeometryIcon CONSTANT ) Q_PROPERTY( QUrl cloudIcon READ cloudIcon CONSTANT ) Q_PROPERTY( QUrl measurementToolIcon READ measurementToolIcon CONSTANT ) + Q_PROPERTY( QUrl closeShapeIcon READ closeShapeIcon CONSTANT ) // Filled Icons - for visualizing of selected item in toolbar Q_PROPERTY( QUrl projectsFilledIcon READ projectsFilledIcon CONSTANT ) @@ -425,6 +426,7 @@ class MMStyle: public QObject QUrl morePhotosIcon() {return QUrl( "qrc:/MorePhotos.svg" );} QUrl mouthIcon() {return QUrl( "qrc:/Mouth.svg" );} QUrl measurementToolIcon() {return QUrl( "qrc:/Measure.svg" );} + QUrl closeShapeIcon() {return QUrl( "qrc:/CloseShape.svg" );} QUrl naturalResourcesIcon() {return QUrl( "qrc:/NaturalResources.svg" );} QUrl nextIcon() {return QUrl( "qrc:/Next.svg" );} QUrl otherIcon() {return QUrl( "qrc:/Other.svg" );} diff --git a/app/qml/CMakeLists.txt b/app/qml/CMakeLists.txt index 7f8ab2349..dc11cf9a4 100644 --- a/app/qml/CMakeLists.txt +++ b/app/qml/CMakeLists.txt @@ -77,6 +77,7 @@ set(MM_QML dialogs/MMDiscardGeometryChangesDialog.qml dialogs/MMProjectLoadErrorDialog.qml dialogs/MMProviderRemoveReceiverDialog.qml + dialogs/MMFinishMeasurementDialog.qml dialogs/components/MMDialogAdditionalText.qml form/MMFormPage.qml form/MMFormStackController.qml diff --git a/app/qml/components/MMDrawerHeader.qml b/app/qml/components/MMDrawerHeader.qml index 20c8aea36..bf930a1fe 100644 --- a/app/qml/components/MMDrawerHeader.qml +++ b/app/qml/components/MMDrawerHeader.qml @@ -58,7 +58,7 @@ Rectangle { iconSourceLeft: root.leftButtonIcon bgndColor: __style.lightGreenColor - visible: true //root.leftButtonIcon + visible: root.leftButtonIcon anchors { left: parent.left diff --git a/app/qml/gps/MMMeasureDrawer.qml b/app/qml/gps/MMMeasureDrawer.qml index 01614d0bd..c53541eaa 100644 --- a/app/qml/gps/MMMeasureDrawer.qml +++ b/app/qml/gps/MMMeasureDrawer.qml @@ -34,33 +34,27 @@ MMDrawer { readonly property alias panelHeight: root.height signal panelHeightUpdated() - signal stakeoutFinished() + signal measureFinished() + signal measureDone() Component.onCompleted: { root.open() } - // function endStakeout() { - // if ( mapCanvas.state !== "stakeout" ) - // return; + function endMeasurement() { + if ( mapCanvas.state !== "measure" ) + return; - // stakeoutFinished() - // } - - // function hide() { - // root.close() - // } + measureFinished() + } - // function restore() { - // root.open() - // } + function hide() { + root.close() + } - // Behavior on height { - // SequentialAnimation { - // PropertyAnimation { properties: "height"; easing.type: Easing.InOutQuad } - // ScriptAction { script: root.panelHeightUpdated() } - // } - // } + function restore() { + root.open() + } modal: false @@ -80,7 +74,7 @@ MMDrawer { id: mainColumn width: parent.width - spacing: __style.margin12 + spacing: __style.margin40 Row { width: parent.width @@ -101,5 +95,23 @@ MMDrawer { visible: closeShapeActive } } + + Row { + width: parent.width + spacing: __style.margin12 + + MMButton { + text: closeShapeActive ? qsTr( "Close shape" ) : qsTr( "Add point" ) + iconSourceLeft: closeShapeActive ? __style.closeShapeIcon : __style.plusIcon + onClicked: console.log(" Add point or Close Shape") + } + + MMButton { + type: MMButton.Types.Secondary + text: qsTr( "Done" ) + iconSourceLeft: __style.doneCircleIcon + onClicked: root.measureDone() + } + } } } diff --git a/app/qml/main.qml b/app/qml/main.qml index cb6dc998d..144aefd97 100644 --- a/app/qml/main.qml +++ b/app/qml/main.qml @@ -636,6 +636,7 @@ ApplicationWindow { mapCanvas: map + onMeasureDone: finishMeasurementDialog.open() } } @@ -770,6 +771,10 @@ ApplicationWindow { } } + MMFinishMeasurementDialog { + id: finishMeasurementDialog + } + MMNotificationView {} MMListDrawer { diff --git a/gallery/qml/pages/IconsPage.qml b/gallery/qml/pages/IconsPage.qml index 5a89348a0..999d34c26 100644 --- a/gallery/qml/pages/IconsPage.qml +++ b/gallery/qml/pages/IconsPage.qml @@ -77,6 +77,7 @@ ScrollView { GalleryComponents.IconLine { name: "plusIcon"; source: __style.plusIcon; showRect: checkboxBorder.checked; invertColors: checkboxColor.checked } GalleryComponents.IconLine { name: "positionTrackingIcon"; source: __style.positionTrackingIcon; showRect: checkboxBorder.checked; invertColors: checkboxColor.checked } GalleryComponents.IconLine { name: "measurementToolIcon"; source: __style.measurementToolIcon; showRect: checkboxBorder.checked; invertColors: checkboxColor.checked } + GalleryComponents.IconLine { name: "closeShapeIcon"; source: __style.closeShapeIcon; showRect: checkboxBorder.checked; invertColors: checkboxColor.checked } GalleryComponents.IconLine { name: "qrCodeIcon"; source: __style.qrCodeIcon; showRect: checkboxBorder.checked; invertColors: checkboxColor.checked } GalleryComponents.IconLine { name: "satelliteIcon"; source: __style.satelliteIcon; showRect: checkboxBorder.checked; invertColors: checkboxColor.checked } GalleryComponents.IconLine { name: "searchIcon"; source: __style.searchIcon; showRect: checkboxBorder.checked; invertColors: checkboxColor.checked } From c1317ed2dab92809713015e968ec8ee65150af39 Mon Sep 17 00:00:00 2001 From: VitorVieiraZ Date: Fri, 16 Aug 2024 00:35:59 -0300 Subject: [PATCH 08/60] measure crosshair added --- app/qml/CMakeLists.txt | 1 + app/qml/components/MMDrawer.qml | 2 + app/qml/components/MMDrawerHeader.qml | 12 -- app/qml/gps/MMMeasureDrawer.qml | 26 ++- app/qml/main.qml | 15 +- app/qml/map/MMMapController.qml | 42 ++++- app/qml/map/MMMeasurementTools.qml | 237 +------------------------- 7 files changed, 70 insertions(+), 265 deletions(-) diff --git a/app/qml/CMakeLists.txt b/app/qml/CMakeLists.txt index dc11cf9a4..b96f616de 100644 --- a/app/qml/CMakeLists.txt +++ b/app/qml/CMakeLists.txt @@ -137,6 +137,7 @@ set(MM_QML map/MMSplittingTools.qml map/MMStakeoutTools.qml map/MMRecordingTools.qml + map/MMMeasurementTools.qml map/components/MMHidingBox.qml map/components/MMCrosshair.qml map/components/MMMapHidingLabel.qml diff --git a/app/qml/components/MMDrawer.qml b/app/qml/components/MMDrawer.qml index fe8e1c270..44b42429b 100644 --- a/app/qml/components/MMDrawer.qml +++ b/app/qml/components/MMDrawer.qml @@ -31,6 +31,7 @@ Drawer { property string leftButtonIcon: "" property string leftButtonText: "" property string leftButtonType: MMButton.Types.Primary + signal leftButtonClicked implicitHeight: contentHeight > maxHeight ? maxHeight : contentHeight implicitWidth: ApplicationWindow.window?.width ?? 0 @@ -81,6 +82,7 @@ Drawer { leftButtonIcon: root.leftButtonIcon leftButtonText: root.leftButtonText leftButtonType: root.leftButtonType + onLeftButtonClicked: root.leftButtonClicked() onCloseClicked: { root.close() diff --git a/app/qml/components/MMDrawerHeader.qml b/app/qml/components/MMDrawerHeader.qml index bf930a1fe..38a8d2424 100644 --- a/app/qml/components/MMDrawerHeader.qml +++ b/app/qml/components/MMDrawerHeader.qml @@ -38,18 +38,6 @@ Rectangle { implicitHeight: 60 * __dp implicitWidth: ApplicationWindow.window?.width ?? 0 - // MMRoundButton { - // id: leftBtn - - // iconSource: __style.addIcon - // iconColor: __style.forestColor - - // bgndColor: __style.grassColor - // bgndHoverColor: __style.mediumGreenColor - - // onClicked: root.createWorkspaceRequested() - // } - MMButton { id: leftBtn diff --git a/app/qml/gps/MMMeasureDrawer.qml b/app/qml/gps/MMMeasureDrawer.qml index c53541eaa..ba5585eb6 100644 --- a/app/qml/gps/MMMeasureDrawer.qml +++ b/app/qml/gps/MMMeasureDrawer.qml @@ -30,6 +30,7 @@ MMDrawer { // targetPair, // mapCanvas.mapSettings ) : -1 property bool closeShapeActive: true + property bool closeShapeDone: true readonly property alias panelHeight: root.height @@ -56,6 +57,22 @@ MMDrawer { root.open() } + function closeShape() + { + console.log(" close shape clicked ") + root.closeShapeActive = false + } + + function addPoint() + { + console.log(" point added ") + } + + function repeatMeasure() + { + console.log(" repeat measure ") + } + modal: false closePolicy: Popup.CloseOnEscape // prevents the drawer closing while moving canvas @@ -64,11 +81,12 @@ MMDrawer { //onClosed: root.endStakeout() - leftButtonText: "Undo" - leftButtonIcon: __style.undoIcon + leftButtonText: closeShapeDone ? qsTr( "Repeat" ) : qsTr( "Undo" ) + leftButtonIcon: closeShapeDone ? __style.syncIcon : __style.undoIcon leftButtonType: MMButton.Types.Primary + onLeftButtonClicked: console.log("onLeftButtonClicked") - drawerHeader.title: qsTr("Measure") + drawerHeader.title: qsTr( "Measure" ) drawerContent: Column { id: mainColumn @@ -103,7 +121,7 @@ MMDrawer { MMButton { text: closeShapeActive ? qsTr( "Close shape" ) : qsTr( "Add point" ) iconSourceLeft: closeShapeActive ? __style.closeShapeIcon : __style.plusIcon - onClicked: console.log(" Add point or Close Shape") + onClicked: closeShapeActive ? root.closeShape() : root.addPoint() } MMButton { diff --git a/app/qml/main.qml b/app/qml/main.qml index 144aefd97..008414965 100644 --- a/app/qml/main.qml +++ b/app/qml/main.qml @@ -158,6 +158,10 @@ ApplicationWindow { // if stakeout panel is opened return stakeoutPanelLoader.item.panelHeight - mapToolbar.height } + else if ( measurePanelLoader.active ) + { + return measurePanelLoader.item.panelHeight - mapToolbar.height + } else if ( formsStackManager.takenVerticalSpace > 0 ) { // if feature preview panel is opened @@ -336,13 +340,8 @@ ApplicationWindow { text: qsTr("Measure") iconSource: __style.measurementToolIcon onClicked: { - if ( __recordingLayersModel.rowCount() > 0 ) { - stateManager.state = "map" - map.measure() - } - else { - __notificationModel.addInfo( qsTr( "No editable layers found." ) ) - } + stateManager.state = "map" + map.measure() } } @@ -773,6 +772,8 @@ ApplicationWindow { MMFinishMeasurementDialog { id: finishMeasurementDialog + + onFinishMeasurementRequested: measurePanelLoader.active = false } MMNotificationView {} diff --git a/app/qml/map/MMMapController.qml b/app/qml/map/MMMapController.qml index b340c9b19..6f7d3bb71 100644 --- a/app/qml/map/MMMapController.qml +++ b/app/qml/map/MMMapController.qml @@ -298,6 +298,17 @@ Item { sourceComponent: stakeoutToolsComponent } + Loader { + id: measureLoader + + anchors.fill: mapCanvas + + asynchronous: true + active: root.state === "measure" + + sourceComponent: measurementToolsComponent + } + Loader { id: tracking @@ -508,10 +519,10 @@ Item { anchors.bottom: parent.bottom - anchors.bottomMargin: root.state === "stakeout" ? root.mapExtentOffset : 0 + anchors.bottomMargin: root.state === "stakeout" || root.state === "measure" ? root.mapExtentOffset : 0 visible: { - if ( root.state === "stakeout" ) + if ( root.state === "stakeout" || root.state === "measure" ) return true else return root.mapExtentOffset > 0 ? false : true @@ -973,6 +984,17 @@ Item { } } + Component { + id: measurementToolsComponent + + MMMeasurementTools { + anchors.fill: parent + + map: mapCanvas + positionMarkerComponent: positionMarker + } + } + Component { id: splittingToolsComponent @@ -1122,6 +1144,12 @@ Item { state = "stakeout" } + function measure() { + internal.extentBeforeStakeout = mapCanvas.mapSettings.extent + + state = "measure" + } + function toggleStreaming() { // start/stop the streaming mode if ( recordingToolsLoader.active ) { @@ -1138,6 +1166,12 @@ Item { root.centeredToGPS = internal.centeredToGPSBeforeStakeout } + function stopMeasure() { + state = "view" + + mapCanvas.mapSettings.extent = internal.extentBeforeStakeout + } + function centerToPair( pair ) { __inputUtils.setExtentToFeature( pair, mapCanvas.mapSettings ) } @@ -1256,10 +1290,6 @@ Item { } } - function measure() { - state = "measure" - } - function showInfoTextMessage( message ) { hideInfoTextMessage() diff --git a/app/qml/map/MMMeasurementTools.qml b/app/qml/map/MMMeasurementTools.qml index 3e6431fcb..78ae4a885 100644 --- a/app/qml/map/MMMeasurementTools.qml +++ b/app/qml/map/MMMeasurementTools.qml @@ -32,21 +32,6 @@ Item { signal canceled() signal done( var featureLayerPair ) - function toggleStreaming() { - if ( mapTool.recordingType === MM.RecordingMapTool.Manual ) - { - mapTool.recordingType = MM.RecordingMapTool.StreamMode - - // add first point immediately - mapTool.addPoint( crosshair.recordPoint ) - root.map.mapSettings.setCenter( mapPositionSource.mapPosition ) - } - else - { - mapTool.recordingType = MM.RecordingMapTool.Manual - } - } - MM.RecordingMapTool { id: mapTool @@ -81,106 +66,12 @@ Item { } } - MM.GuidelineController { - id: guidelineController - - allowed: mapTool.state !== MM.RecordingMapTool.View && mapTool.recordingType !== MM.RecordingMapTool.StreamMode - - mapSettings: root.map.mapSettings - insertPolicy: mapTool.insertPolicy - crosshairPosition: crosshair.screenPoint - realGeometry: __inputUtils.transformGeometryToMapWithLayer( mapTool.recordedGeometry, __activeLayer.vectorLayer, root.map.mapSettings ) - - activeVertex: mapTool.activeVertex - activePart: mapTool.activePart - activeRing: mapTool.activeRing - } - - MMHighlight { - id: highlight - - height: root.map.height - width: root.map.width - - visible: !__inputUtils.isPointLayer(__activeLayer.vectorLayer) - - mapSettings: root.map.mapSettings - geometry: __inputUtils.transformGeometryToMapWithLayer( mapTool.recordedGeometry, __activeLayer.vectorLayer, root.map.mapSettings ) - - lineBorderWidth: 0 - } - - MMHighlight { - id: handlesHighlight - - height: root.map.height - width: root.map.width - - mapSettings: root.map.mapSettings - geometry: __inputUtils.transformGeometryToMapWithLayer( mapTool.handles, __activeLayer.vectorLayer, root.map.mapSettings ) - - lineStrokeStyle: ShapePath.DashLine - lineWidth: MMHighlight.LineWidths.Narrow - } - - MMHighlight { - id: guideline - - height: root.map.height - width: root.map.width - - lineWidth: MMHighlight.LineWidths.Narrow - lineStrokeStyle: ShapePath.DashLine - - mapSettings: root.map.mapSettings - geometry: guidelineController.guidelineGeometry - } - - MMHighlight { - id: midSegmentsHighlight - - height: root.map.height - width: root.map.width - - mapSettings: root.map.mapSettings - geometry: __inputUtils.transformGeometryToMapWithLayer( mapTool.midPoints, __activeLayer.vectorLayer, root.map.mapSettings ) - - markerType: MMHighlight.MarkerTypes.Circle - markerBorderColor: __style.grapeColor - } - - MMHighlight { - id: existingVerticesHighlight - - height: root.map.height - width: root.map.width - - mapSettings: root.map.mapSettings - geometry: __inputUtils.transformGeometryToMapWithLayer( mapTool.existingVertices, __activeLayer.vectorLayer, root.map.mapSettings ) - - markerType: MMHighlight.MarkerTypes.Circle - markerSize: MMHighlight.MarkerSizes.Bigger - } - - // Duplicate position marker to be painted on the top of highlights - MMPositionMarker { - xPos: positionMarkerComponent.xPos - yPos: positionMarkerComponent.yPos - hasDirection: positionMarkerComponent.hasDirection - - direction: positionMarkerComponent.direction - hasPosition: positionMarkerComponent.hasPosition - - horizontalAccuracy: positionMarkerComponent.horizontalAccuracy - accuracyRingSize: positionMarkerComponent.accuracyRingSize - } - MMCrosshair { //labeled crosshair id: crosshair anchors.fill: parent - visible: mapTool.state !== MM.RecordingMapTool.View && mapTool.recordingType !== MM.RecordingMapTool.StreamMode + visible: true //mapTool.state !== MM.RecordingMapTool.View && mapTool.recordingType !== MM.RecordingMapTool.StreamMode qgsProject: __activeProject.qgsProject mapSettings: root.map.mapSettings @@ -189,132 +80,6 @@ Item { crosshairLabelText: "58.4 m" } - MMToolbar { - y: parent.height - - ObjectModel { - id: polygonToolbarButtons - - MMToolbarButton { - text: qsTr( "Undo" ) - iconSource: __style.undoIcon - onClicked: mapTool.undo() - enabled: mapTool.canUndo - } - - MMToolbarButton { - text: qsTr( "Remove" ) - iconSource: __style.minusIcon - onClicked: mapTool.removePoint() - - enabled: { - if ( mapTool.recordingType !== MM.RecordingMapTool.Manual ) return false; - if ( mapTool.state === MM.RecordingMapTool.View ) return false; - if ( __inputUtils.isEmptyGeometry( mapTool.recordedGeometry ) ) return false; - - return true; - } - } - - MMToolbarButton { - text: qsTr( "Release" ) - visible: mapTool.state === MM.RecordingMapTool.Grab - iconSource: __style.addIcon - onClicked: { - if ( mapTool.state === MM.RecordingMapTool.Grab ) { - mapTool.releaseVertex( crosshair.recordPoint ) - } - else { - mapTool.addPoint( crosshair.recordPoint ) - } - } - } - - MMToolbarButton { - text: qsTr( "Add" ) - - visible: mapTool.state === MM.RecordingMapTool.View || mapTool.state === MM.RecordingMapTool.Record - enabled: mapTool.recordingType === MM.RecordingMapTool.Manual && mapTool.state !== MM.RecordingMapTool.View - - iconSource: __style.addIcon - onClicked: { - if ( mapTool.state === MM.RecordingMapTool.Grab ) { - mapTool.releaseVertex( crosshair.recordPoint ) - } - else { - mapTool.addPoint( crosshair.recordPoint ) - } - } - } - - MMToolbarButton { - text: qsTr( "Record" ) - - iconSource: __style.doneCircleIcon - iconColor: __style.grassColor - onClicked: { - if ( mapTool.hasValidGeometry() ) - { - // If we currently grab a point - if ( mapTool.state === MM.RecordingMapTool.Grab ) - { - mapTool.releaseVertex( crosshair.recordPoint ) - } - - let pair = mapTool.getFeatureLayerPair() - root.done( pair ) - } - else - { - __notificationModel.addWarning( __inputUtils.invalidGeometryWarning( mapTool.activeLayer ) ) - } - } - } - } - - ObjectModel { - id: pointToolbarButtons - - MMToolbarButton { - text: qsTr( "Record" ); - iconSource: __style.doneCircleIcon; - iconColor: __style.forestColor - onClicked: { - if ( mapTool.state === MM.RecordingMapTool.Grab ) - { - // editing existing point geometry - mapTool.releaseVertex( crosshair.recordPoint ) - } else - { - // recording new point - mapTool.addPoint( crosshair.recordPoint ) - } - - let pair = mapTool.getFeatureLayerPair() - root.done( pair ) - } - } - } - - model: { - let pointLayerSelected = __inputUtils.isPointLayer( __activeLayer.vectorLayer ) - let isMultiPartLayerSelected = __inputUtils.isMultiPartLayer( __activeLayer.vectorLayer ) - - if ( pointLayerSelected && !isMultiPartLayerSelected ) { - return pointToolbarButtons - } - return polygonToolbarButtons - } - } - - Connections { - target: map - function onClicked( point ) { - let screenPoint = Qt.point( point.x, point.y ) - - mapTool.lookForVertex( screenPoint ) - } - } function discardChanges() { mapTool.discardChanges() From d4a21fcad193a4ad16883b2cfdf498c2c3554102 Mon Sep 17 00:00:00 2001 From: VitorVieiraZ Date: Fri, 16 Aug 2024 16:48:06 -0300 Subject: [PATCH 09/60] cpp files for measurement tool + moving MMMeasureDrawer to MMMeasurementTools --- app/CMakeLists.txt | 2 + app/main.cpp | 2 + app/maptools/measurementmaptool.cpp | 86 +++++++++++++++++++++++ app/maptools/measurementmaptool.h | 51 ++++++++++++++ app/qml/gps/MMMeasureDrawer.qml | 2 + app/qml/main.qml | 5 +- app/qml/map/MMMeasurementTools.qml | 103 ++++++++++++++-------------- 7 files changed, 195 insertions(+), 56 deletions(-) create mode 100644 app/maptools/measurementmaptool.cpp create mode 100644 app/maptools/measurementmaptool.h diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index f371e92eb..7d8400e9d 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -27,6 +27,7 @@ set(MM_SRCS maptools/abstractmaptool.cpp maptools/recordingmaptool.cpp maptools/splittingmaptool.cpp + maptools/measurementmaptool.cpp ios/iosimagepicker.cpp ios/iosutils.cpp position/providers/abstractpositionprovider.cpp @@ -110,6 +111,7 @@ set(MM_HDRS maptools/abstractmaptool.h maptools/recordingmaptool.h maptools/splittingmaptool.h + maptools/measurementmaptool.h ios/iosimagepicker.h ios/iosutils.h position/providers/abstractpositionprovider.h diff --git a/app/main.cpp b/app/main.cpp index 2fcd9b137..148e00c6c 100644 --- a/app/main.cpp +++ b/app/main.cpp @@ -115,6 +115,7 @@ #include "maptools/abstractmaptool.h" #include "maptools/recordingmaptool.h" #include "maptools/splittingmaptool.h" +#include "maptools/measurementmaptool.h" #include "layer/layertreemodel.h" #include "layer/layertreemodelpixmapprovider.h" @@ -350,6 +351,7 @@ void initDeclarative() qmlRegisterUncreatableType< AbstractMapTool >( "mm", 1, 0, "AbstractMapTool", "Instantiate one of child map tools instead" ); qmlRegisterType< RecordingMapTool >( "mm", 1, 0, "RecordingMapTool" ); qmlRegisterType< SplittingMapTool >( "mm", 1, 0, "SplittingMapTool" ); + qmlRegisterType< MeasurementMapTool >( "mm", 1, 0, "MeasurementMapTool" ); } void addQmlImportPath( QQmlEngine &engine ) diff --git a/app/maptools/measurementmaptool.cpp b/app/maptools/measurementmaptool.cpp new file mode 100644 index 000000000..72a1ccd96 --- /dev/null +++ b/app/maptools/measurementmaptool.cpp @@ -0,0 +1,86 @@ +#include "measurementmaptool.h" + +#include +#include +#include "qgspointxy.h" +#include "qgsgeometryutils.h" + +MeasurementMapTool::MeasurementMapTool( QObject *parent ) + : AbstractMapTool{parent} +{ + + +} + +MeasurementMapTool::~MeasurementMapTool() = default; + +// void MeasurementMapTool::addPoint( const QgsPointXY &point ) +// { +// if (mPoints.isEmpty()) { +// mPoints.append(point); +// return; +// } + +// // Calculate distance from the last point to the new one +// QgsPointXY lastPoint = mPoints.last(); +// double distance = QgsGeometryUtils::sqrDistance2D(lastPoint, point); +// mDistances.append(distance); + +// mPoints.append(point); + +// emit distanceMeasured(distance); + +// // Check if a polygon can be formed +// if (mPoints.size() > 2) { +// mIsPolygon = true; +// emit polygonCanBeFormed(true); +// } +// } + +// double MeasurementMapTool::totalDistance() const +// { +// double total = 0.0; +// for (const double &d : mDistances) { +// total += d; +// } +// return total; +// } + +// double MeasurementMapTool::calculatePerimeter() const +// { +// if (mIsPolygon) { +// double perimeter = totalDistance(); +// // Closing the polygon (last point to the first point) +// perimeter += QgsGeometryUtils::sqrDistance2D(mPoints.last(), mPoints.first()); +// return perimeter; +// } +// return 0.0; +// } + +// double MeasurementMapTool::calculateArea() const +// { +// if (mIsPolygon) { +// QgsPolygonXY polygon; +// polygon.setExteriorRing(QgsLineString(mPoints)); +// return polygon.area(); +// } +// return 0.0; +// } + +// void MeasurementMapTool::clearMeasurements() +// { +// mPoints.clear(); +// mDistances.clear(); +// mIsPolygon = false; +// emit polygonCanBeFormed(false); +// } + +// QList MeasurementMapTool::points() const +// { +// return mPoints; +// } + +// bool MeasurementMapTool::isPolygon() const +// { +// return mIsPolygon; +// } diff --git a/app/maptools/measurementmaptool.h b/app/maptools/measurementmaptool.h new file mode 100644 index 000000000..1c94102bb --- /dev/null +++ b/app/maptools/measurementmaptool.h @@ -0,0 +1,51 @@ +#ifndef MEASUREMENTMAPTOOL_H +#define MEASUREMENTMAPTOOL_H + +#include "abstractmaptool.h" + +#include +#include +#include "qgspolygon.h" +#include "qgsvectorlayerutils.h" +#include "qgsmultipoint.h" +#include "qgsmultilinestring.h" +#include "qgspolygon.h" +#include "qgsmultipolygon.h" +#include "qgsrendercontext.h" +#include "qgsvectorlayereditbuffer.h" + +#include "qgsvectorlayer.h" + +class MeasurementMapTool : public AbstractMapTool +{ + Q_OBJECT +public: + explicit MeasurementMapTool( QObject *parent = nullptr ); + virtual ~MeasurementMapTool() override; + +// Q_INVOKABLE void addPoint( const QgsPoint &point ); + +// Q_INVOKABLE double totalDistance() const; + +// Q_INVOKABLE double calculatePerimeter() const; + +// Q_INVOKABLE double calculateArea() const; + +// Q_INVOKABLE void clearMeasurements(); + +// Q_INVOKABLE QList points() const; + +// Q_INVOKABLE bool isPolygon() const; + + +// signals: +// void distanceMeasured(double distance); +// void polygonCanBeFormed(bool canForm); + +// private: +// QList mPoints; +// QList mDistances; +// bool mIsPolygon; +}; + +#endif // MEASUREMENTMAPTOOL_H diff --git a/app/qml/gps/MMMeasureDrawer.qml b/app/qml/gps/MMMeasureDrawer.qml index ba5585eb6..38206f7f7 100644 --- a/app/qml/gps/MMMeasureDrawer.qml +++ b/app/qml/gps/MMMeasureDrawer.qml @@ -35,6 +35,7 @@ MMDrawer { readonly property alias panelHeight: root.height signal panelHeightUpdated() + signal addMeasurePoint() signal measureFinished() signal measureDone() @@ -65,6 +66,7 @@ MMDrawer { function addPoint() { + root.addMeasurePoint() console.log(" point added ") } diff --git a/app/qml/main.qml b/app/qml/main.qml index 008414965..012ca3e45 100644 --- a/app/qml/main.qml +++ b/app/qml/main.qml @@ -224,9 +224,7 @@ ApplicationWindow { } onMeasureStarted: function( pair ) { - measurePanelLoader.active = true - measurePanelLoader.focus = true - measurePanelLoader.item.targetPair = pair + console.log(" measure started") } onLocalChangesPanelRequested: { @@ -635,6 +633,7 @@ ApplicationWindow { mapCanvas: map + onAddMeasurePoint: measurePanel.addMeasurePoint.connect(map.measurementTools.onAddMeasurePoint) onMeasureDone: finishMeasurementDialog.open() } } diff --git a/app/qml/map/MMMeasurementTools.qml b/app/qml/map/MMMeasurementTools.qml index 78ae4a885..0a90ad708 100644 --- a/app/qml/map/MMMeasurementTools.qml +++ b/app/qml/map/MMMeasurementTools.qml @@ -14,79 +14,76 @@ import mm 1.0 as MM import "../components" import "./components" +import "../gps" -/** - * RecordingTools is a set of tools that are used during recording/editing of a geometry. - * These tools can be instantiated just for the time of recording and then destroyed. - */ Item { - id: root + id: root - required property MMMapCanvas map - required property MMPositionMarker positionMarkerComponent + required property MMMapCanvas map + required property MMPositionMarker positionMarkerComponent - property alias recordingMapTool: mapTool + property alias recordingMapTool: mapTool + property var activeFeature - property var activeFeature + signal canceled() + signal addMeasurePoint() + signal done(var featureLayerPair) - signal canceled() - signal done( var featureLayerPair ) - - MM.RecordingMapTool { - id: mapTool + MM.MeasurementMapTool { + id: mapTool + } - property bool isUsingPosition: mapTool.centeredToGPS || mapTool.recordingType == MM.RecordingMapTool.StreamMode + MM.GuidelineController { + id: guidelineController - mapSettings: root.map.mapSettings + allowed: true //mapTool.state !== MM.RecordingMapTool.View && mapTool.recordingType !== MM.RecordingMapTool.StreamMode - recordPoint: crosshair.recordPoint + mapSettings: root.map.mapSettings + insertPolicy: mapTool.insertPolicy + crosshairPosition: crosshair.screenPoint + realGeometry: __inputUtils.transformGeometryToMapWithLayer(mapTool.recordedGeometry, __activeLayer.vectorLayer, root.map.mapSettings) - recordingType: MM.RecordingMapTool.Manual - recordingInterval: __appSettings.lineRecordingInterval - recordingIntervalType: __appSettings.intervalType + activeVertex: mapTool.activeVertex + activePart: mapTool.activePart + activeRing: mapTool.activeRing + } - positionKit: __positionKit - activeLayer: __activeLayer.vectorLayer - activeFeature: root.activeFeature + MMCrosshair { + id: crosshair - // Bind variables manager to know if we are centered to GPS or not when evaluating position variables - onIsUsingPositionChanged: __variablesManager.useGpsPoint = isUsingPosition + anchors.fill: parent - onActiveVertexChanged: function( activeVertex ) { - if ( activeVertex.isValid() ) - { - // Center to clicked vertex - let newCenter = mapTool.vertexMapCoors( activeVertex ) + visible: true //mapTool.state !== MM.RecordingMapTool.View && mapTool.recordingType !== MM.RecordingMapTool.StreamMode - if ( !isNaN( newCenter.x ) && !isNaN( newCenter.y ) ) - { - root.map.jumpTo( /*crosshair.screenPoint,*/ root.map.mapSettings.coordinateToScreen( newCenter ) ) - } - } + qgsProject: __activeProject.qgsProject + mapSettings: root.map.mapSettings + shouldUseSnapping: !mapTool.isUsingPosition + hasLabel: true + crosshairLabelText: "58.4 m" } - } - MMCrosshair { //labeled crosshair - id: crosshair + MMMeasureDrawer { + id: measurePanel + + width: window.width - anchors.fill: parent + mapCanvas: map - visible: true //mapTool.state !== MM.RecordingMapTool.View && mapTool.recordingType !== MM.RecordingMapTool.StreamMode + onAddMeasurePoint: console.log(" Add measure ") + onMeasureDone: finishMeasurementDialog.open() + } - qgsProject: __activeProject.qgsProject - mapSettings: root.map.mapSettings - shouldUseSnapping: !mapTool.isUsingPosition - hasLabel: true - crosshairLabelText: "58.4 m" - } + function discardChanges() { + mapTool.discardChanges() + root.canceled() + } - function discardChanges() { - mapTool.discardChanges() - root.canceled() - } + function hasChanges() { + return mapTool.hasChanges() + } - function hasChanges() { - return mapTool.hasChanges() - } + function onAddMeasurePoint() { + console.log("Ponto de medição adicionado") + } } From 947347e6f87ef3ce2d441163ab0309ee82805736 Mon Sep 17 00:00:00 2001 From: VitorVieiraZ Date: Fri, 16 Aug 2024 16:52:44 -0300 Subject: [PATCH 10/60] finish measure dialog moved and connected to measurement tools --- app/qml/main.qml | 35 ------------------------------ app/qml/map/MMMapController.qml | 4 +++- app/qml/map/MMMeasurementTools.qml | 7 ++++++ 3 files changed, 10 insertions(+), 36 deletions(-) diff --git a/app/qml/main.qml b/app/qml/main.qml index 012ca3e45..a738a1c70 100644 --- a/app/qml/main.qml +++ b/app/qml/main.qml @@ -158,10 +158,6 @@ ApplicationWindow { // if stakeout panel is opened return stakeoutPanelLoader.item.panelHeight - mapToolbar.height } - else if ( measurePanelLoader.active ) - { - return measurePanelLoader.item.panelHeight - mapToolbar.height - } else if ( formsStackManager.takenVerticalSpace > 0 ) { // if feature preview panel is opened @@ -613,31 +609,6 @@ ApplicationWindow { } } - Loader { - id: measurePanelLoader - - focus: true - active: false - asynchronous: true - - sourceComponent: measurePanelComponent - } - - Component { - id: measurePanelComponent - - MMMeasureDrawer { - id: measurePanel - - width: window.width - - mapCanvas: map - - onAddMeasurePoint: measurePanel.addMeasurePoint.connect(map.measurementTools.onAddMeasurePoint) - onMeasureDone: finishMeasurementDialog.open() - } - } - MMFormStackController { id: formsStackManager @@ -769,12 +740,6 @@ ApplicationWindow { } } - MMFinishMeasurementDialog { - id: finishMeasurementDialog - - onFinishMeasurementRequested: measurePanelLoader.active = false - } - MMNotificationView {} MMListDrawer { diff --git a/app/qml/map/MMMapController.qml b/app/qml/map/MMMapController.qml index 6f7d3bb71..45591bb46 100644 --- a/app/qml/map/MMMapController.qml +++ b/app/qml/map/MMMapController.qml @@ -992,6 +992,7 @@ Item { map: mapCanvas positionMarkerComponent: positionMarker + onFinishMeasurement: root.finishMeasure() } } @@ -1166,9 +1167,10 @@ Item { root.centeredToGPS = internal.centeredToGPSBeforeStakeout } - function stopMeasure() { + function finishMeasure() { state = "view" + mapCanvas.mapSettings.extent = internal.extentBeforeStakeout } diff --git a/app/qml/map/MMMeasurementTools.qml b/app/qml/map/MMMeasurementTools.qml index 0a90ad708..e0379414a 100644 --- a/app/qml/map/MMMeasurementTools.qml +++ b/app/qml/map/MMMeasurementTools.qml @@ -15,6 +15,7 @@ import mm 1.0 as MM import "../components" import "./components" import "../gps" +import "../dialogs" Item { id: root @@ -27,6 +28,7 @@ Item { signal canceled() signal addMeasurePoint() + signal finishMeasurement() signal done(var featureLayerPair) MM.MeasurementMapTool { @@ -73,6 +75,11 @@ Item { onMeasureDone: finishMeasurementDialog.open() } + MMFinishMeasurementDialog { + id: finishMeasurementDialog + + onFinishMeasurementRequested: root.finishMeasurement() + } function discardChanges() { mapTool.discardChanges() From b91b67cf0ea17c3e331d851950097c7a2c00d1d3 Mon Sep 17 00:00:00 2001 From: VitorVieiraZ Date: Fri, 16 Aug 2024 18:06:54 -0300 Subject: [PATCH 11/60] fixing measurement tools drawer onClosed --- app/qml/gps/MMMeasureDrawer.qml | 2 +- app/qml/map/MMMeasurementTools.qml | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/app/qml/gps/MMMeasureDrawer.qml b/app/qml/gps/MMMeasureDrawer.qml index 38206f7f7..95c5ba0a1 100644 --- a/app/qml/gps/MMMeasureDrawer.qml +++ b/app/qml/gps/MMMeasureDrawer.qml @@ -81,7 +81,7 @@ MMDrawer { dropShadow: true - //onClosed: root.endStakeout() + onClosed: root.measureFinished() leftButtonText: closeShapeDone ? qsTr( "Repeat" ) : qsTr( "Undo" ) leftButtonIcon: closeShapeDone ? __style.syncIcon : __style.undoIcon diff --git a/app/qml/map/MMMeasurementTools.qml b/app/qml/map/MMMeasurementTools.qml index e0379414a..8e7c45746 100644 --- a/app/qml/map/MMMeasurementTools.qml +++ b/app/qml/map/MMMeasurementTools.qml @@ -73,6 +73,7 @@ Item { onAddMeasurePoint: console.log(" Add measure ") onMeasureDone: finishMeasurementDialog.open() + onMeasureFinished:root.finishMeasurement() } MMFinishMeasurementDialog { From b5911993164df17f986e300fc10719f3ef8e55e1 Mon Sep 17 00:00:00 2001 From: VitorVieiraZ Date: Tue, 20 Aug 2024 12:09:15 -0300 Subject: [PATCH 12/60] first working version --- app/maptools/measurementmaptool.cpp | 146 +++++++++++++--------------- app/maptools/measurementmaptool.h | 68 +++++++------ app/qml/gps/MMMeasureDrawer.qml | 42 +++----- app/qml/map/MMMapController.qml | 7 +- app/qml/map/MMMeasurementTools.qml | 119 +++++++++++++---------- 5 files changed, 189 insertions(+), 193 deletions(-) diff --git a/app/maptools/measurementmaptool.cpp b/app/maptools/measurementmaptool.cpp index 72a1ccd96..b6a914447 100644 --- a/app/maptools/measurementmaptool.cpp +++ b/app/maptools/measurementmaptool.cpp @@ -1,86 +1,78 @@ -#include "measurementmaptool.h" +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ -#include -#include -#include "qgspointxy.h" -#include "qgsgeometryutils.h" +#include "measurementmaptool.h" MeasurementMapTool::MeasurementMapTool( QObject *parent ) : AbstractMapTool{parent} { + qDebug() << "MeasurementMapTool constructor called"; +} + +MeasurementMapTool::~MeasurementMapTool() +{ + qDebug() << "MeasurementMapTool destructor called"; +} + +void MeasurementMapTool::addPoint( const QgsPoint &point ) +{ + mPoints.push_back( point ); + rebuildGeometry(); +} + +void MeasurementMapTool::removePoint() +{ + if ( !mPoints.isEmpty() ) + { + mPoints.pop_back(); + rebuildGeometry(); + } +} + +bool MeasurementMapTool::hasValidGeometry() const +{ + return mPoints.count() >= 2; +} + +void MeasurementMapTool::rebuildGeometry() +{ + QgsGeometry geometry; + + if ( mPoints.count() > 0 ) + geometry = QgsGeometry::fromPolyline( mPoints ); + + setRecordedGeometry( geometry ); + +} + +const QgsGeometry &MeasurementMapTool::recordedGeometry() const +{ + return mRecordedGeometry; +} + +void MeasurementMapTool::setRecordedGeometry( const QgsGeometry &newRecordedGeometry ) +{ + if ( mRecordedGeometry.equals( newRecordedGeometry ) ) + return; + mRecordedGeometry = newRecordedGeometry; + emit recordedGeometryChanged( mRecordedGeometry ); +} + +double MeasurementMapTool::updateDistance( const QgsPoint &crosshairPoint ) +{ + if ( mPoints.isEmpty() ) + return 0.0; + + QgsPoint lastPoint = mPoints.last(); + double distance = QgsDistanceArea().measureLine( crosshairPoint, lastPoint ); + return distance; } -MeasurementMapTool::~MeasurementMapTool() = default; - -// void MeasurementMapTool::addPoint( const QgsPointXY &point ) -// { -// if (mPoints.isEmpty()) { -// mPoints.append(point); -// return; -// } - -// // Calculate distance from the last point to the new one -// QgsPointXY lastPoint = mPoints.last(); -// double distance = QgsGeometryUtils::sqrDistance2D(lastPoint, point); -// mDistances.append(distance); - -// mPoints.append(point); - -// emit distanceMeasured(distance); - -// // Check if a polygon can be formed -// if (mPoints.size() > 2) { -// mIsPolygon = true; -// emit polygonCanBeFormed(true); -// } -// } - -// double MeasurementMapTool::totalDistance() const -// { -// double total = 0.0; -// for (const double &d : mDistances) { -// total += d; -// } -// return total; -// } - -// double MeasurementMapTool::calculatePerimeter() const -// { -// if (mIsPolygon) { -// double perimeter = totalDistance(); -// // Closing the polygon (last point to the first point) -// perimeter += QgsGeometryUtils::sqrDistance2D(mPoints.last(), mPoints.first()); -// return perimeter; -// } -// return 0.0; -// } - -// double MeasurementMapTool::calculateArea() const -// { -// if (mIsPolygon) { -// QgsPolygonXY polygon; -// polygon.setExteriorRing(QgsLineString(mPoints)); -// return polygon.area(); -// } -// return 0.0; -// } - -// void MeasurementMapTool::clearMeasurements() -// { -// mPoints.clear(); -// mDistances.clear(); -// mIsPolygon = false; -// emit polygonCanBeFormed(false); -// } - -// QList MeasurementMapTool::points() const -// { -// return mPoints; -// } - -// bool MeasurementMapTool::isPolygon() const -// { -// return mIsPolygon; -// } diff --git a/app/maptools/measurementmaptool.h b/app/maptools/measurementmaptool.h index 1c94102bb..aa7c61de8 100644 --- a/app/maptools/measurementmaptool.h +++ b/app/maptools/measurementmaptool.h @@ -1,51 +1,61 @@ +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + #ifndef MEASUREMENTMAPTOOL_H #define MEASUREMENTMAPTOOL_H +#include "inputconfig.h" #include "abstractmaptool.h" - -#include #include -#include "qgspolygon.h" -#include "qgsvectorlayerutils.h" -#include "qgsmultipoint.h" -#include "qgsmultilinestring.h" -#include "qgspolygon.h" -#include "qgsmultipolygon.h" -#include "qgsrendercontext.h" -#include "qgsvectorlayereditbuffer.h" - -#include "qgsvectorlayer.h" +#include "qgsdistancearea.h" +#include "qgsgeometry.h" class MeasurementMapTool : public AbstractMapTool { Q_OBJECT -public: - explicit MeasurementMapTool( QObject *parent = nullptr ); - virtual ~MeasurementMapTool() override; -// Q_INVOKABLE void addPoint( const QgsPoint &point ); + Q_PROPERTY( QgsGeometry recordedGeometry READ recordedGeometry WRITE setRecordedGeometry NOTIFY recordedGeometryChanged ) -// Q_INVOKABLE double totalDistance() const; + public: + explicit MeasurementMapTool( QObject *parent = nullptr ); + virtual ~MeasurementMapTool() override; -// Q_INVOKABLE double calculatePerimeter() const; + /** + * Adds point to the end of the recorded geometry; updates recordedGeometry afterwards + * Passed point needs to be in active vector layer CRS + */ + Q_INVOKABLE void addPoint( const QgsPoint &point ); -// Q_INVOKABLE double calculateArea() const; + /** + * Removes last point from recorded geometry if there is at least one point + * Updates recordedGeometry afterwards + */ + Q_INVOKABLE void removePoint(); -// Q_INVOKABLE void clearMeasurements(); + //! Returns true if the captured geometry has enought points for the specified layer + Q_INVOKABLE bool hasValidGeometry() const; -// Q_INVOKABLE QList points() const; + const QgsGeometry &recordedGeometry() const; + void setRecordedGeometry( const QgsGeometry &newRecordedGeometry ); -// Q_INVOKABLE bool isPolygon() const; + signals: + void recordedGeometryChanged( const QgsGeometry &recordedGeometry ); + protected: + void rebuildGeometry(); -// signals: -// void distanceMeasured(double distance); -// void polygonCanBeFormed(bool canForm); + public slots: + double updateDistance( const QgsPoint &crosshairPoint ); // Slot to update distance -// private: -// QList mPoints; -// QList mDistances; -// bool mIsPolygon; + private: + QVector mPoints; + QgsGeometry mRecordedGeometry; }; #endif // MEASUREMENTMAPTOOL_H diff --git a/app/qml/gps/MMMeasureDrawer.qml b/app/qml/gps/MMMeasureDrawer.qml index 95c5ba0a1..d7c92a4dd 100644 --- a/app/qml/gps/MMMeasureDrawer.qml +++ b/app/qml/gps/MMMeasureDrawer.qml @@ -24,20 +24,18 @@ MMDrawer { property var mapCanvas - property var targetPair: null - // property real remainingDistance: targetPair ? __inputUtils.distanceBetweenGpsAndFeature( - // __positionKit.positionCoordinate, - // targetPair, - // mapCanvas.mapSettings ) : -1 - property bool closeShapeActive: true - property bool closeShapeDone: true + property bool closeShapeActive: false + property bool closeShapeDone: false - readonly property alias panelHeight: root.height + property string length: qsTr( "N/A" ) + property string perimeter: qsTr( "N/A" ) + property string area: qsTr( "N/A" ) - signal panelHeightUpdated() signal addMeasurePoint() signal measureFinished() signal measureDone() + signal undo() + signal repeat() Component.onCompleted: { root.open() @@ -50,34 +48,18 @@ MMDrawer { measureFinished() } - function hide() { - root.close() - } - function restore() { root.open() } function closeShape() { - console.log(" close shape clicked ") root.closeShapeActive = false } - function addPoint() - { - root.addMeasurePoint() - console.log(" point added ") - } - - function repeatMeasure() - { - console.log(" repeat measure ") - } - modal: false - closePolicy: Popup.CloseOnEscape // prevents the drawer closing while moving canvas + closePolicy: Popup.CloseOnEscape dropShadow: true @@ -86,7 +68,7 @@ MMDrawer { leftButtonText: closeShapeDone ? qsTr( "Repeat" ) : qsTr( "Undo" ) leftButtonIcon: closeShapeDone ? __style.syncIcon : __style.undoIcon leftButtonType: MMButton.Types.Primary - onLeftButtonClicked: console.log("onLeftButtonClicked") + onLeftButtonClicked: closeShapeDone ? root.repeat() : root.undo() drawerHeader.title: qsTr( "Measure" ) @@ -103,14 +85,14 @@ MMDrawer { width: ( parent.width + parent.spacing ) / 2 title: closeShapeActive ? qsTr( "Perimeter" ) : qsTr( "Length" ) - value: "58.4 m" //remainingDistance >= 0 ?__inputUtils.formatDistanceInProjectUnit( remainingDistance, 2 ) : qsTr( "N/A" ) + value: closeShapeActive ? root.perimeter : root.length } MMGpsComponents.MMGpsDataText{ width: ( parent.width + parent.spacing ) / 2 title: qsTr( "Area" ) - value: "0.00 m" + value: root.area alignmentRight: true visible: closeShapeActive } @@ -123,7 +105,7 @@ MMDrawer { MMButton { text: closeShapeActive ? qsTr( "Close shape" ) : qsTr( "Add point" ) iconSourceLeft: closeShapeActive ? __style.closeShapeIcon : __style.plusIcon - onClicked: closeShapeActive ? root.closeShape() : root.addPoint() + onClicked: closeShapeActive ? root.closeShape() : root.addMeasurePoint() } MMButton { diff --git a/app/qml/map/MMMapController.qml b/app/qml/map/MMMapController.qml index 45591bb46..5f356253e 100644 --- a/app/qml/map/MMMapController.qml +++ b/app/qml/map/MMMapController.qml @@ -909,7 +909,10 @@ Item { mapSettings: mapCanvas.mapSettings positionKit: __positionKit - onScreenPositionChanged: root.updatePosition() + onScreenPositionChanged: { + //console.log("AA") + root.updatePosition() + } } MM.PositionDirection { @@ -1169,8 +1172,6 @@ Item { function finishMeasure() { state = "view" - - mapCanvas.mapSettings.extent = internal.extentBeforeStakeout } diff --git a/app/qml/map/MMMeasurementTools.qml b/app/qml/map/MMMeasurementTools.qml index 8e7c45746..1e6a74afa 100644 --- a/app/qml/map/MMMeasurementTools.qml +++ b/app/qml/map/MMMeasurementTools.qml @@ -18,80 +18,91 @@ import "../gps" import "../dialogs" Item { - id: root + id: root - required property MMMapCanvas map - required property MMPositionMarker positionMarkerComponent + required property MMMapCanvas map + required property MMPositionMarker positionMarkerComponent - property alias recordingMapTool: mapTool - property var activeFeature + signal finishMeasurement() - signal canceled() - signal addMeasurePoint() - signal finishMeasurement() - signal done(var featureLayerPair) + MMCrosshair { + id: crosshair + anchors.fill: parent + qgsProject: __activeProject.qgsProject + mapSettings: root.map.mapSettings + hasLabel: true + crosshairLabelText: "N/A" + } - MM.MeasurementMapTool { - id: mapTool - } + MM.MeasurementMapTool { + id: mapTool + mapSettings: root.map.mapSettings + } - MM.GuidelineController { - id: guidelineController + MM.GuidelineController { + id: guidelineController - allowed: true //mapTool.state !== MM.RecordingMapTool.View && mapTool.recordingType !== MM.RecordingMapTool.StreamMode + mapSettings: root.map.mapSettings + crosshairPosition: crosshair.screenPoint + realGeometry: __inputUtils.transformGeometryToMapWithLayer( mapTool.recordedGeometry, __activeLayer.vectorLayer, root.map.mapSettings ) + } - mapSettings: root.map.mapSettings - insertPolicy: mapTool.insertPolicy - crosshairPosition: crosshair.screenPoint - realGeometry: __inputUtils.transformGeometryToMapWithLayer(mapTool.recordedGeometry, __activeLayer.vectorLayer, root.map.mapSettings) + MMHighlight { + id: guideline - activeVertex: mapTool.activeVertex - activePart: mapTool.activePart - activeRing: mapTool.activeRing - } + height: root.map.height + width: root.map.width - MMCrosshair { - id: crosshair + markerColor: __style.deepOceanColor + lineColor: __style.deepOceanColor + lineStrokeStyle: ShapePath.DashLine + lineWidth: MMHighlight.LineWidths.Narrow - anchors.fill: parent + mapSettings: root.map.mapSettings + geometry: guidelineController.guidelineGeometry + } - visible: true //mapTool.state !== MM.RecordingMapTool.View && mapTool.recordingType !== MM.RecordingMapTool.StreamMode + MMHighlight { + id: highlight - qgsProject: __activeProject.qgsProject - mapSettings: root.map.mapSettings - shouldUseSnapping: !mapTool.isUsingPosition - hasLabel: true - crosshairLabelText: "58.4 m" - } + height: map.height + width: map.width - MMMeasureDrawer { - id: measurePanel + markerColor: __style.deepOceanColor + lineColor: __style.deepOceanColor + lineWidth: MMHighlight.LineWidths.Narrow - width: window.width + mapSettings: root.map.mapSettings + geometry: __inputUtils.transformGeometryToMapWithLayer( mapTool.recordedGeometry, __activeLayer.vectorLayer, root.map.mapSettings ) + } - mapCanvas: map + MMMeasureDrawer { + id: measurePanel - onAddMeasurePoint: console.log(" Add measure ") - onMeasureDone: finishMeasurementDialog.open() - onMeasureFinished:root.finishMeasurement() - } + width: window.width + mapCanvas: map - MMFinishMeasurementDialog { - id: finishMeasurementDialog + onAddMeasurePoint: mapTool.addPoint( crosshair.recordPoint ) + onMeasureDone: finishMeasurementDialog.open() + onMeasureFinished: root.finishMeasurement() + } - onFinishMeasurementRequested: root.finishMeasurement() - } + MMFinishMeasurementDialog { + id: finishMeasurementDialog + onFinishMeasurementRequested: root.finishMeasurement() + } - function discardChanges() { - mapTool.discardChanges() - root.canceled() - } + function onScreenPositionChanged() { + let distance = mapTool.updateDistance( crosshair.recordPoint ); - function hasChanges() { - return mapTool.hasChanges() + if (distance === 0.0 ) { + measurePanel.length = "N/A"; + } else { + measurePanel.length = distance.toFixed( 1 ) + " m"; } - function onAddMeasurePoint() { - console.log("Ponto de medição adicionado") - } + crosshair.crosshairLabelText = measurePanel.length; + } + + Component.onCompleted: map.mapSettings.extentChanged.connect( onScreenPositionChanged ) } From ce1a6d351f4438eaf1407d0e92e8707ef9fc1be5 Mon Sep 17 00:00:00 2001 From: VitorVieiraZ Date: Tue, 20 Aug 2024 20:29:20 -0300 Subject: [PATCH 13/60] close shape procedures first part --- app/maptools/measurementmaptool.cpp | 30 ++++++++++++++++++++++++----- app/maptools/measurementmaptool.h | 9 ++++++--- app/qml/gps/MMMeasureDrawer.qml | 6 +----- app/qml/map/MMMeasurementTools.qml | 6 +++++- 4 files changed, 37 insertions(+), 14 deletions(-) diff --git a/app/maptools/measurementmaptool.cpp b/app/maptools/measurementmaptool.cpp index b6a914447..00ad7cae9 100644 --- a/app/maptools/measurementmaptool.cpp +++ b/app/maptools/measurementmaptool.cpp @@ -23,6 +23,10 @@ MeasurementMapTool::~MeasurementMapTool() void MeasurementMapTool::addPoint( const QgsPoint &point ) { mPoints.push_back( point ); + + if ( mPoints.count() >= 3 ) + emit canCloseShape( true ); + rebuildGeometry(); } @@ -31,15 +35,14 @@ void MeasurementMapTool::removePoint() if ( !mPoints.isEmpty() ) { mPoints.pop_back(); + + if ( mPoints.count() < 3 ) + emit canCloseShape( false ); + rebuildGeometry(); } } -bool MeasurementMapTool::hasValidGeometry() const -{ - return mPoints.count() >= 2; -} - void MeasurementMapTool::rebuildGeometry() { QgsGeometry geometry; @@ -76,3 +79,20 @@ double MeasurementMapTool::updateDistance( const QgsPoint &crosshairPoint ) return distance; } +void MeasurementMapTool::closeShape() +{ + if ( mPoints.count() < 3 ) + return; + + QList pointList; + for ( const QgsPoint &point : mPoints ) + { + pointList.append( QgsPointXY( point.x(), point.y() ) ); + } + + QgsGeometry polygonGeometry = QgsGeometry::fromPolygonXY( QList>() << pointList ); + + setRecordedGeometry( polygonGeometry ); + +} + diff --git a/app/maptools/measurementmaptool.h b/app/maptools/measurementmaptool.h index aa7c61de8..8e8e5178b 100644 --- a/app/maptools/measurementmaptool.h +++ b/app/maptools/measurementmaptool.h @@ -15,6 +15,9 @@ #include #include "qgsdistancearea.h" #include "qgsgeometry.h" +#include +#include +#include class MeasurementMapTool : public AbstractMapTool { @@ -38,20 +41,20 @@ class MeasurementMapTool : public AbstractMapTool */ Q_INVOKABLE void removePoint(); - //! Returns true if the captured geometry has enought points for the specified layer - Q_INVOKABLE bool hasValidGeometry() const; + Q_INVOKABLE void closeShape(); const QgsGeometry &recordedGeometry() const; void setRecordedGeometry( const QgsGeometry &newRecordedGeometry ); signals: void recordedGeometryChanged( const QgsGeometry &recordedGeometry ); + void canCloseShape( bool canClose ); protected: void rebuildGeometry(); public slots: - double updateDistance( const QgsPoint &crosshairPoint ); // Slot to update distance + double updateDistance( const QgsPoint &crosshairPoint ); private: QVector mPoints; diff --git a/app/qml/gps/MMMeasureDrawer.qml b/app/qml/gps/MMMeasureDrawer.qml index d7c92a4dd..f19c34bd9 100644 --- a/app/qml/gps/MMMeasureDrawer.qml +++ b/app/qml/gps/MMMeasureDrawer.qml @@ -34,6 +34,7 @@ MMDrawer { signal addMeasurePoint() signal measureFinished() signal measureDone() + signal closeShape() signal undo() signal repeat() @@ -52,11 +53,6 @@ MMDrawer { root.open() } - function closeShape() - { - root.closeShapeActive = false - } - modal: false closePolicy: Popup.CloseOnEscape diff --git a/app/qml/map/MMMeasurementTools.qml b/app/qml/map/MMMeasurementTools.qml index 1e6a74afa..c75fda61c 100644 --- a/app/qml/map/MMMeasurementTools.qml +++ b/app/qml/map/MMMeasurementTools.qml @@ -37,6 +37,8 @@ Item { MM.MeasurementMapTool { id: mapTool mapSettings: root.map.mapSettings + + onCanCloseShape: measurePanel.closeShapeActive = canClose } MM.GuidelineController { @@ -80,11 +82,13 @@ Item { id: measurePanel width: window.width - mapCanvas: map + mapCanvas: root.map onAddMeasurePoint: mapTool.addPoint( crosshair.recordPoint ) onMeasureDone: finishMeasurementDialog.open() onMeasureFinished: root.finishMeasurement() + onCloseShape: mapTool.closeShape() + } MMFinishMeasurementDialog { From 91376bdb351ba915d42a9da9dd462e900426a340 Mon Sep 17 00:00:00 2001 From: VitorVieiraZ Date: Thu, 22 Aug 2024 20:52:48 -0300 Subject: [PATCH 14/60] new enhancements and tool development steps --- app/maptools/measurementmaptool.cpp | 37 ++++++++++-- app/maptools/measurementmaptool.h | 8 +++ app/qml/components/MMDrawer.qml | 2 + app/qml/components/MMDrawerHeader.qml | 3 + app/qml/gps/MMMeasureDrawer.qml | 58 ++++++++++-------- app/qml/map/MMMeasurementTools.qml | 82 +++++++++++++++++++++----- app/qml/map/components/MMCrosshair.qml | 25 -------- app/qml/map/components/MMMapLabel.qml | 2 +- 8 files changed, 148 insertions(+), 69 deletions(-) diff --git a/app/maptools/measurementmaptool.cpp b/app/maptools/measurementmaptool.cpp index 00ad7cae9..8ae172067 100644 --- a/app/maptools/measurementmaptool.cpp +++ b/app/maptools/measurementmaptool.cpp @@ -23,10 +23,6 @@ MeasurementMapTool::~MeasurementMapTool() void MeasurementMapTool::addPoint( const QgsPoint &point ) { mPoints.push_back( point ); - - if ( mPoints.count() >= 3 ) - emit canCloseShape( true ); - rebuildGeometry(); } @@ -48,7 +44,12 @@ void MeasurementMapTool::rebuildGeometry() QgsGeometry geometry; if ( mPoints.count() > 0 ) + { geometry = QgsGeometry::fromPolyline( mPoints ); + emit canUndo( true ); + } + else + emit canUndo( false ); setRecordedGeometry( geometry ); @@ -72,6 +73,17 @@ double MeasurementMapTool::updateDistance( const QgsPoint &crosshairPoint ) if ( mPoints.isEmpty() ) return 0.0; + if ( mPoints.count() >= 3 ) + { + QgsPoint firstPoint = mPoints.first(); + double distanceToFirstPoint = QgsDistanceArea().measureLine( crosshairPoint, firstPoint ); + + if ( distanceToFirstPoint <= CLOSE_THRESHOLD ) + emit canCloseShape( true ); + else + emit canCloseShape( false ); + } + QgsPoint lastPoint = mPoints.last(); double distance = QgsDistanceArea().measureLine( crosshairPoint, lastPoint ); @@ -94,5 +106,22 @@ void MeasurementMapTool::closeShape() setRecordedGeometry( polygonGeometry ); + QgsDistanceArea distanceArea; + double area = distanceArea.measureArea( polygonGeometry ); + double perimeter = distanceArea.measureLength( polygonGeometry ); + + emit shapeArea( area ); + emit shapePerimeter( perimeter ); + emit canCloseShape( false ); } +void MeasurementMapTool::repeat() +{ + mPoints.clear(); + + emit canCloseShape( false ); + + rebuildGeometry(); +} + + diff --git a/app/maptools/measurementmaptool.h b/app/maptools/measurementmaptool.h index 8e8e5178b..d50dfd00e 100644 --- a/app/maptools/measurementmaptool.h +++ b/app/maptools/measurementmaptool.h @@ -19,6 +19,8 @@ #include #include +const double CLOSE_THRESHOLD = 100.0; + class MeasurementMapTool : public AbstractMapTool { Q_OBJECT @@ -42,13 +44,19 @@ class MeasurementMapTool : public AbstractMapTool Q_INVOKABLE void removePoint(); Q_INVOKABLE void closeShape(); + Q_INVOKABLE void repeat(); const QgsGeometry &recordedGeometry() const; void setRecordedGeometry( const QgsGeometry &newRecordedGeometry ); signals: void recordedGeometryChanged( const QgsGeometry &recordedGeometry ); + void canCloseShape( bool canClose ); + void canUndo( bool canUndo ); + + void shapeArea( double area ); + void shapePerimeter( double perimeter ); protected: void rebuildGeometry(); diff --git a/app/qml/components/MMDrawer.qml b/app/qml/components/MMDrawer.qml index 44b42429b..3b0b0e762 100644 --- a/app/qml/components/MMDrawer.qml +++ b/app/qml/components/MMDrawer.qml @@ -31,6 +31,7 @@ Drawer { property string leftButtonIcon: "" property string leftButtonText: "" property string leftButtonType: MMButton.Types.Primary + property bool leftButtonEnabled: true signal leftButtonClicked implicitHeight: contentHeight > maxHeight ? maxHeight : contentHeight @@ -82,6 +83,7 @@ Drawer { leftButtonIcon: root.leftButtonIcon leftButtonText: root.leftButtonText leftButtonType: root.leftButtonType + leftButtonEnabled: root.leftButtonEnabled onLeftButtonClicked: root.leftButtonClicked() onCloseClicked: { diff --git a/app/qml/components/MMDrawerHeader.qml b/app/qml/components/MMDrawerHeader.qml index 38a8d2424..2d0042c4c 100644 --- a/app/qml/components/MMDrawerHeader.qml +++ b/app/qml/components/MMDrawerHeader.qml @@ -26,6 +26,7 @@ Rectangle { property string leftButtonIcon: "" property string leftButtonText: "" property string leftButtonType: MMButton.Types.Primary + property bool leftButtonEnabled: true property alias closeButton: closeBtn property alias leftButton: leftBtn @@ -48,6 +49,8 @@ Rectangle { visible: root.leftButtonIcon + enabled: root.leftButtonEnabled + anchors { left: parent.left leftMargin: __style.pageMargins + __style.safeAreaLeft diff --git a/app/qml/gps/MMMeasureDrawer.qml b/app/qml/gps/MMMeasureDrawer.qml index f19c34bd9..170bc84af 100644 --- a/app/qml/gps/MMMeasureDrawer.qml +++ b/app/qml/gps/MMMeasureDrawer.qml @@ -24,12 +24,13 @@ MMDrawer { property var mapCanvas - property bool closeShapeActive: false + property bool canCloseShape: false property bool closeShapeDone: false + property bool canUndo: false - property string length: qsTr( "N/A" ) - property string perimeter: qsTr( "N/A" ) - property string area: qsTr( "N/A" ) + property string length: qsTr( "0.0 m" ) + property string perimeter: qsTr( "0.0 m" ) + property string area: qsTr( "0.0 m" ) signal addMeasurePoint() signal measureFinished() @@ -42,17 +43,6 @@ MMDrawer { root.open() } - function endMeasurement() { - if ( mapCanvas.state !== "measure" ) - return; - - measureFinished() - } - - function restore() { - root.open() - } - modal: false closePolicy: Popup.CloseOnEscape @@ -64,9 +54,10 @@ MMDrawer { leftButtonText: closeShapeDone ? qsTr( "Repeat" ) : qsTr( "Undo" ) leftButtonIcon: closeShapeDone ? __style.syncIcon : __style.undoIcon leftButtonType: MMButton.Types.Primary - onLeftButtonClicked: closeShapeDone ? root.repeat() : root.undo() + leftButtonEnabled: closeShapeDone || canUndo + onLeftButtonClicked: closeShapeDone ? root.repeatMeasure() : root.undo() - drawerHeader.title: qsTr( "Measure" ) + drawerHeader.title: qsTr( "Measurement" ) drawerContent: Column { id: mainColumn @@ -80,8 +71,8 @@ MMDrawer { MMGpsComponents.MMGpsDataText{ width: ( parent.width + parent.spacing ) / 2 - title: closeShapeActive ? qsTr( "Perimeter" ) : qsTr( "Length" ) - value: closeShapeActive ? root.perimeter : root.length + title: closeShapeDone ? qsTr( "Perimeter" ) : qsTr( "Length" ) + value: closeShapeDone ? root.perimeter : root.length } MMGpsComponents.MMGpsDataText{ @@ -90,18 +81,19 @@ MMDrawer { title: qsTr( "Area" ) value: root.area alignmentRight: true - visible: closeShapeActive + visible: closeShapeDone } } Row { width: parent.width spacing: __style.margin12 + visible: !root.closeShapeDone MMButton { - text: closeShapeActive ? qsTr( "Close shape" ) : qsTr( "Add point" ) - iconSourceLeft: closeShapeActive ? __style.closeShapeIcon : __style.plusIcon - onClicked: closeShapeActive ? root.closeShape() : root.addMeasurePoint() + text: root.canCloseShape ? qsTr( "Close shape" ) : qsTr( "Add point" ) + iconSourceLeft: canCloseShape ? __style.closeShapeIcon : __style.plusIcon + onClicked: canCloseShape ? root.closeShape() : root.addMeasurePoint() } MMButton { @@ -112,4 +104,24 @@ MMDrawer { } } } + + function endMeasurement() + { + if ( mapCanvas.state !== "measure" ) + return; + + measureFinished() + } + + function restore() + { + root.open() + } + + function repeatMeasure() + { + root.closeShapeDone = false + root.canCloseShape = false + root.repeat() + } } diff --git a/app/qml/map/MMMeasurementTools.qml b/app/qml/map/MMMeasurementTools.qml index c75fda61c..b0cf2ab79 100644 --- a/app/qml/map/MMMeasurementTools.qml +++ b/app/qml/map/MMMeasurementTools.qml @@ -25,20 +25,25 @@ Item { signal finishMeasurement() - MMCrosshair { - id: crosshair - anchors.fill: parent - qgsProject: __activeProject.qgsProject - mapSettings: root.map.mapSettings - hasLabel: true - crosshairLabelText: "N/A" - } - MM.MeasurementMapTool { id: mapTool mapSettings: root.map.mapSettings - onCanCloseShape: measurePanel.closeShapeActive = canClose + onCanCloseShape: function( canClose ) { + measurePanel.canCloseShape = canClose; + } + + onShapeArea: function( area ) { + measurePanel.area = area; + } + + onShapePerimeter: function( perimeter ) { + measurePanel.perimeter = perimeter; + } + + onCanUndo: function( canUndo ) { + measurePanel.canUndo = canUndo; + } } MM.GuidelineController { @@ -87,8 +92,32 @@ Item { onAddMeasurePoint: mapTool.addPoint( crosshair.recordPoint ) onMeasureDone: finishMeasurementDialog.open() onMeasureFinished: root.finishMeasurement() - onCloseShape: mapTool.closeShape() + onCloseShape: root.closeShape() + onRepeat: root.repeatMeasure() + onUndo: mapTool.removePoint() + } + MMCrosshair { + id: crosshair + anchors.fill: parent + qgsProject: __activeProject.qgsProject + mapSettings: root.map.mapSettings + //hasLabel: true + //crosshairLabelText: qsTr( "N/A") + //crosshairLabelIcon: measurePanel.canCloseShape ? __style.closeShapeIcon : "" + } + + MMMapLabel { + id: mapLabel + + anchors.top: crosshair.bottom + anchors.horizontalCenter: crosshair.horizontalCenter + + text: qsTr( "0.0 m" ) + bgColor: __style.forestColor + textColor: __style.polarColor + textBgColorInverted: false + onClicked: console.log( "MapLabel" ) } MMFinishMeasurementDialog { @@ -99,14 +128,35 @@ Item { function onScreenPositionChanged() { let distance = mapTool.updateDistance( crosshair.recordPoint ); - if (distance === 0.0 ) { - measurePanel.length = "N/A"; - } else { - measurePanel.length = distance.toFixed( 1 ) + " m"; + measurePanel.length = distance.toFixed( 1 ) + " m"; + + if ( measurePanel.canCloseShape ) { + mapLabel.text = qsTr( "Close shape" ) + mapLabel.iconSource = __style.closeShapeIcon } + else { + mapLabel.text = measurePanel.length; + mapLabel.iconSource = "" + } + } - crosshair.crosshairLabelText = measurePanel.length; + function closeShape() + { + guidelineController.allowed = false + crosshair.visible = false + measurePanel.closeShapeDone = true + mapTool.closeShape() } + function repeatMeasure() + { + guidelineController.allowed = true + crosshair.visible = true + measurePanel.closeShapeDone = false + measurePanel.canCloseShape = false + mapTool.repeat() + } + + Component.onCompleted: map.mapSettings.extentChanged.connect( onScreenPositionChanged ) } diff --git a/app/qml/map/components/MMCrosshair.qml b/app/qml/map/components/MMCrosshair.qml index 8ae283ee1..a9c7ec465 100644 --- a/app/qml/map/components/MMCrosshair.qml +++ b/app/qml/map/components/MMCrosshair.qml @@ -19,9 +19,6 @@ Item { /*required*/ property var mapSettings property bool shouldUseSnapping: false - property bool hasLabel: false - property string crosshairLabelText: "" - property point center: Qt.point( root.width / 2, root.height / 2 ) property var recordPoint: snapUtils.recordPoint @@ -42,14 +39,6 @@ Item { } - Loader { - id: crosshairLabelLoader - active: root.hasLabel - sourceComponent: crosshairLabelComponent - anchors.top: crosshairForeground.bottom - anchors.horizontalCenter: crosshairForeground.horizontalCenter - } - Image { id: crosshairBackground // white background of the crosshair @@ -248,20 +237,6 @@ Item { source: __style.crosshairCircleImage } - Component { - id: crosshairLabelComponent - - MMMapLabel { - bgColor: __style.forestColor - textColor: __style.polarColor - textBgColorInverted: false - hasIcon: false - text: root.crosshairLabelText - - onClicked: console.log( "MapLabel" ) - } - } - Connections { target: __activeProject diff --git a/app/qml/map/components/MMMapLabel.qml b/app/qml/map/components/MMMapLabel.qml index 72a67365b..d5ef423bb 100644 --- a/app/qml/map/components/MMMapLabel.qml +++ b/app/qml/map/components/MMMapLabel.qml @@ -53,7 +53,7 @@ Item { anchors.verticalCenter: parent.verticalCenter source: control.iconSource ? control.iconSource : "" color: control.textColor - size: control.hasIcon ? __style.icon24 : 0 + size: control.iconSource !== "" ? __style.icon24 : 0 } Rectangle { From 012dbd6fc7f38f925bf9f54b63073cf38a9f7fc0 Mon Sep 17 00:00:00 2001 From: VitorVieiraZ Date: Thu, 22 Aug 2024 22:48:20 -0300 Subject: [PATCH 15/60] fixing perimeter and area --- app/maptools/measurementmaptool.cpp | 5 ++--- app/maptools/measurementmaptool.h | 3 +-- app/qml/gps/MMMeasureDrawer.qml | 2 +- app/qml/map/MMMeasurementTools.qml | 15 +++------------ 4 files changed, 7 insertions(+), 18 deletions(-) diff --git a/app/maptools/measurementmaptool.cpp b/app/maptools/measurementmaptool.cpp index 8ae172067..f1db80c7a 100644 --- a/app/maptools/measurementmaptool.cpp +++ b/app/maptools/measurementmaptool.cpp @@ -108,10 +108,9 @@ void MeasurementMapTool::closeShape() QgsDistanceArea distanceArea; double area = distanceArea.measureArea( polygonGeometry ); - double perimeter = distanceArea.measureLength( polygonGeometry ); + double perimeter = distanceArea.measurePerimeter( polygonGeometry ); - emit shapeArea( area ); - emit shapePerimeter( perimeter ); + emit shapeAreaAndPerimeter( area , perimeter ); emit canCloseShape( false ); } diff --git a/app/maptools/measurementmaptool.h b/app/maptools/measurementmaptool.h index d50dfd00e..d56e9bf93 100644 --- a/app/maptools/measurementmaptool.h +++ b/app/maptools/measurementmaptool.h @@ -55,8 +55,7 @@ class MeasurementMapTool : public AbstractMapTool void canCloseShape( bool canClose ); void canUndo( bool canUndo ); - void shapeArea( double area ); - void shapePerimeter( double perimeter ); + void shapeAreaAndPerimeter( double area , double perimeter ); protected: void rebuildGeometry(); diff --git a/app/qml/gps/MMMeasureDrawer.qml b/app/qml/gps/MMMeasureDrawer.qml index 170bc84af..eee67eec8 100644 --- a/app/qml/gps/MMMeasureDrawer.qml +++ b/app/qml/gps/MMMeasureDrawer.qml @@ -30,7 +30,7 @@ MMDrawer { property string length: qsTr( "0.0 m" ) property string perimeter: qsTr( "0.0 m" ) - property string area: qsTr( "0.0 m" ) + property string area: qsTr( "0.0 m²" ) signal addMeasurePoint() signal measureFinished() diff --git a/app/qml/map/MMMeasurementTools.qml b/app/qml/map/MMMeasurementTools.qml index b0cf2ab79..3bb9f55fc 100644 --- a/app/qml/map/MMMeasurementTools.qml +++ b/app/qml/map/MMMeasurementTools.qml @@ -33,12 +33,9 @@ Item { measurePanel.canCloseShape = canClose; } - onShapeArea: function( area ) { - measurePanel.area = area; - } - - onShapePerimeter: function( perimeter ) { - measurePanel.perimeter = perimeter; + onShapeAreaAndPerimeter: function( area, perimeter) { + measurePanel.area = area.toFixed( 1 ) + " m²";; + measurePanel.perimeter = perimeter.toFixed( 1 ) + " m";; } onCanUndo: function( canUndo ) { @@ -102,17 +99,11 @@ Item { anchors.fill: parent qgsProject: __activeProject.qgsProject mapSettings: root.map.mapSettings - //hasLabel: true - //crosshairLabelText: qsTr( "N/A") - //crosshairLabelIcon: measurePanel.canCloseShape ? __style.closeShapeIcon : "" } MMMapLabel { id: mapLabel - anchors.top: crosshair.bottom - anchors.horizontalCenter: crosshair.horizontalCenter - text: qsTr( "0.0 m" ) bgColor: __style.forestColor textColor: __style.polarColor From 15b6e863313a40ec281417ea438b2155dd170a78 Mon Sep 17 00:00:00 2001 From: VitorVieiraZ Date: Fri, 23 Aug 2024 11:12:49 -0300 Subject: [PATCH 16/60] new properties --- app/maptools/measurementmaptool.cpp | 15 ++++++++++----- app/maptools/measurementmaptool.h | 3 +++ app/qml/map/MMMeasurementTools.qml | 20 +++++++------------- 3 files changed, 20 insertions(+), 18 deletions(-) diff --git a/app/maptools/measurementmaptool.cpp b/app/maptools/measurementmaptool.cpp index f1db80c7a..a95419141 100644 --- a/app/maptools/measurementmaptool.cpp +++ b/app/maptools/measurementmaptool.cpp @@ -86,9 +86,11 @@ double MeasurementMapTool::updateDistance( const QgsPoint &crosshairPoint ) QgsPoint lastPoint = mPoints.last(); - double distance = QgsDistanceArea().measureLine( crosshairPoint, lastPoint ); + QgsDistanceArea mDistanceArea; + mDistanceArea.setEllipsoid( QStringLiteral( "WGS84" ) ); + mDistanceArea.setSourceCrs( mapSettings()->destinationCrs(), mapSettings()->transformContext() ); - return distance; + return mDistanceArea.measureLine( crosshairPoint, lastPoint ); } void MeasurementMapTool::closeShape() @@ -106,9 +108,12 @@ void MeasurementMapTool::closeShape() setRecordedGeometry( polygonGeometry ); - QgsDistanceArea distanceArea; - double area = distanceArea.measureArea( polygonGeometry ); - double perimeter = distanceArea.measurePerimeter( polygonGeometry ); + QgsDistanceArea mDistanceArea; + mDistanceArea.setEllipsoid( QStringLiteral( "WGS84" ) ); + mDistanceArea.setSourceCrs( mapSettings()->destinationCrs(), mapSettings()->transformContext() ); + + double area = mDistanceArea.measureArea( polygonGeometry ); + double perimeter = mDistanceArea.measurePerimeter( polygonGeometry ); emit shapeAreaAndPerimeter( area , perimeter ); emit canCloseShape( false ); diff --git a/app/maptools/measurementmaptool.h b/app/maptools/measurementmaptool.h index d56e9bf93..01904ad8f 100644 --- a/app/maptools/measurementmaptool.h +++ b/app/maptools/measurementmaptool.h @@ -49,6 +49,9 @@ class MeasurementMapTool : public AbstractMapTool const QgsGeometry &recordedGeometry() const; void setRecordedGeometry( const QgsGeometry &newRecordedGeometry ); + QgsVectorLayer *activeLayer() const; + void setActiveLayer( QgsVectorLayer *newActiveLayer ); + signals: void recordedGeometryChanged( const QgsGeometry &recordedGeometry ); diff --git a/app/qml/map/MMMeasurementTools.qml b/app/qml/map/MMMeasurementTools.qml index 3bb9f55fc..32e52a1f9 100644 --- a/app/qml/map/MMMeasurementTools.qml +++ b/app/qml/map/MMMeasurementTools.qml @@ -25,21 +25,18 @@ Item { signal finishMeasurement() + Component.onCompleted: map.mapSettings.extentChanged.connect( onScreenPositionChanged ) + Component.onDestruction: map.mapSettings.extentChanged.disconnect( onScreenPositionChanged ) + MM.MeasurementMapTool { id: mapTool mapSettings: root.map.mapSettings - onCanCloseShape: function( canClose ) { - measurePanel.canCloseShape = canClose; - } - + onCanCloseShape: function( canClose ) { measurePanel.canCloseShape = canClose; } + onCanUndo: function( canUndo ) { measurePanel.canUndo = canUndo; } onShapeAreaAndPerimeter: function( area, perimeter) { - measurePanel.area = area.toFixed( 1 ) + " m²";; - measurePanel.perimeter = perimeter.toFixed( 1 ) + " m";; - } - - onCanUndo: function( canUndo ) { - measurePanel.canUndo = canUndo; + measurePanel.area = area.toFixed( 1 ) + " m²"; + measurePanel.perimeter = perimeter.toFixed( 1 ) + " m"; } } @@ -147,7 +144,4 @@ Item { measurePanel.canCloseShape = false mapTool.repeat() } - - - Component.onCompleted: map.mapSettings.extentChanged.connect( onScreenPositionChanged ) } From af44ea9217324900809e94646e0be44300fe5cfe Mon Sep 17 00:00:00 2001 From: VitorVieiraZ Date: Fri, 23 Aug 2024 19:52:33 -0300 Subject: [PATCH 17/60] fixing crs and ellipsoid --- app/maptools/measurementmaptool.cpp | 8 ++++++-- app/qml/map/MMMeasurementTools.qml | 5 ++--- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/app/maptools/measurementmaptool.cpp b/app/maptools/measurementmaptool.cpp index a95419141..4d68c1f2f 100644 --- a/app/maptools/measurementmaptool.cpp +++ b/app/maptools/measurementmaptool.cpp @@ -88,7 +88,9 @@ double MeasurementMapTool::updateDistance( const QgsPoint &crosshairPoint ) QgsDistanceArea mDistanceArea; mDistanceArea.setEllipsoid( QStringLiteral( "WGS84" ) ); - mDistanceArea.setSourceCrs( mapSettings()->destinationCrs(), mapSettings()->transformContext() ); + //mDistanceArea.setSourceCrs( mapSettings()->destinationCrs(), mapSettings()->transformContext() ); + + mDistanceArea.setSourceCrs( QgsCoordinateReferenceSystem::fromEpsgId( 4326 ), QgsCoordinateTransformContext() ); return mDistanceArea.measureLine( crosshairPoint, lastPoint ); } @@ -110,7 +112,9 @@ void MeasurementMapTool::closeShape() QgsDistanceArea mDistanceArea; mDistanceArea.setEllipsoid( QStringLiteral( "WGS84" ) ); - mDistanceArea.setSourceCrs( mapSettings()->destinationCrs(), mapSettings()->transformContext() ); + //mDistanceArea.setSourceCrs( mapSettings()->destinationCrs(), mapSettings()->transformContext() ); + + mDistanceArea.setSourceCrs( QgsCoordinateReferenceSystem::fromEpsgId( 4326 ), QgsCoordinateTransformContext() ); double area = mDistanceArea.measureArea( polygonGeometry ); double perimeter = mDistanceArea.measurePerimeter( polygonGeometry ); diff --git a/app/qml/map/MMMeasurementTools.qml b/app/qml/map/MMMeasurementTools.qml index 32e52a1f9..f256fef0d 100644 --- a/app/qml/map/MMMeasurementTools.qml +++ b/app/qml/map/MMMeasurementTools.qml @@ -36,7 +36,7 @@ Item { onCanUndo: function( canUndo ) { measurePanel.canUndo = canUndo; } onShapeAreaAndPerimeter: function( area, perimeter) { measurePanel.area = area.toFixed( 1 ) + " m²"; - measurePanel.perimeter = perimeter.toFixed( 1 ) + " m"; + measurePanel.perimeter = __inputUtils.formatDistanceInProjectUnit( perimeter, 1 ) //perimeter.toFixed( 1 ) + " m"; } } @@ -116,8 +116,7 @@ Item { function onScreenPositionChanged() { let distance = mapTool.updateDistance( crosshair.recordPoint ); - measurePanel.length = distance.toFixed( 1 ) + " m"; - + measurePanel.length = __inputUtils.formatDistanceInProjectUnit( distance, 1 ); //distance.toFixed( 1 ) + " m"; if ( measurePanel.canCloseShape ) { mapLabel.text = qsTr( "Close shape" ) mapLabel.iconSource = __style.closeShapeIcon From 8a963fc85aec15300cb660cd25a7648745985e5c Mon Sep 17 00:00:00 2001 From: VitorVieiraZ Date: Fri, 23 Aug 2024 20:09:10 -0300 Subject: [PATCH 18/60] converting area to project area units --- app/inpututils.cpp | 22 ++++++++++++++++++++++ app/inpututils.h | 2 ++ app/maptools/measurementmaptool.cpp | 2 +- app/maptools/measurementmaptool.h | 2 +- app/qml/map/MMMeasurementTools.qml | 4 ++-- 5 files changed, 28 insertions(+), 4 deletions(-) diff --git a/app/inpututils.cpp b/app/inpututils.cpp index 5b40e14c0..9904308f4 100644 --- a/app/inpututils.cpp +++ b/app/inpututils.cpp @@ -189,6 +189,28 @@ QString InputUtils::formatDistanceInProjectUnit( const double distanceInMeters, return QString( "%1 %2" ).arg( QString::number( distance, 'f', precision ), abbreviation ); } +QString InputUtils::formatAreaInProjectUnit( const double areaInSquareMeters, int precision, Qgis::AreaUnit destUnit ) +{ + Qgis::AreaUnit areaUnit = destUnit; + + if ( areaUnit == Qgis::AreaUnit::Unknown ) + { + areaUnit = QgsProject::instance()->areaUnits(); + } + + if ( areaUnit == Qgis::AreaUnit::Unknown ) + { + return QString::number( areaInSquareMeters, 'f', precision ); + } + + double factor = QgsUnitTypes::fromUnitToUnitFactor( Qgis::AreaUnit::SquareMeters, areaUnit ); + double area = areaInSquareMeters * factor; + + QString abbreviation = QgsUnitTypes::toAbbreviatedString( areaUnit ); + + return QString( "%1 %2" ).arg( QString::number( area, 'f', precision ), abbreviation ); +} + QString InputUtils::formatDateTimeDiff( const QDateTime &tMin, const QDateTime &tMax ) { qint64 daysDiff = tMin.daysTo( tMax ); diff --git a/app/inpututils.h b/app/inpututils.h index 2ba463900..1fffb70ac 100644 --- a/app/inpututils.h +++ b/app/inpututils.h @@ -76,6 +76,8 @@ class InputUtils: public QObject Q_INVOKABLE QString formatProjectName( const QString &fullProjectName ); Q_INVOKABLE QString formatNumber( const double number, int precision = 1 ); Q_INVOKABLE QString formatDistanceInProjectUnit( const double distanceInMeters, int precision = 1, Qgis::DistanceUnit destUnit = Qgis::DistanceUnit::Unknown ); + Q_INVOKABLE QString formatAreaInProjectUnit( const double areaInSquareMeters, int precision = 1, Qgis::AreaUnit destUnit = Qgis::AreaUnit::Unknown ); + Q_INVOKABLE void setExtentToFeature( const FeatureLayerPair &pair, InputMapSettings *mapSettings ); /** diff --git a/app/maptools/measurementmaptool.cpp b/app/maptools/measurementmaptool.cpp index 4d68c1f2f..8300421bc 100644 --- a/app/maptools/measurementmaptool.cpp +++ b/app/maptools/measurementmaptool.cpp @@ -119,7 +119,7 @@ void MeasurementMapTool::closeShape() double area = mDistanceArea.measureArea( polygonGeometry ); double perimeter = mDistanceArea.measurePerimeter( polygonGeometry ); - emit shapeAreaAndPerimeter( area , perimeter ); + emit shapeAreaAndPerimeter( area, perimeter ); emit canCloseShape( false ); } diff --git a/app/maptools/measurementmaptool.h b/app/maptools/measurementmaptool.h index 01904ad8f..7c1466608 100644 --- a/app/maptools/measurementmaptool.h +++ b/app/maptools/measurementmaptool.h @@ -58,7 +58,7 @@ class MeasurementMapTool : public AbstractMapTool void canCloseShape( bool canClose ); void canUndo( bool canUndo ); - void shapeAreaAndPerimeter( double area , double perimeter ); + void shapeAreaAndPerimeter( double area, double perimeter ); protected: void rebuildGeometry(); diff --git a/app/qml/map/MMMeasurementTools.qml b/app/qml/map/MMMeasurementTools.qml index f256fef0d..b6da19087 100644 --- a/app/qml/map/MMMeasurementTools.qml +++ b/app/qml/map/MMMeasurementTools.qml @@ -35,8 +35,8 @@ Item { onCanCloseShape: function( canClose ) { measurePanel.canCloseShape = canClose; } onCanUndo: function( canUndo ) { measurePanel.canUndo = canUndo; } onShapeAreaAndPerimeter: function( area, perimeter) { - measurePanel.area = area.toFixed( 1 ) + " m²"; - measurePanel.perimeter = __inputUtils.formatDistanceInProjectUnit( perimeter, 1 ) //perimeter.toFixed( 1 ) + " m"; + measurePanel.area = __inputUtils.formatAreaInProjectUnit( area, 1 ) + measurePanel.perimeter = __inputUtils.formatDistanceInProjectUnit( perimeter, 1 ) } } From 03d3a987cf0bd5c0829683b11decf8d3f8f6baca Mon Sep 17 00:00:00 2001 From: VitorVieiraZ Date: Mon, 26 Aug 2024 10:46:16 -0300 Subject: [PATCH 19/60] on development --- app/map/inputmapsettings.cpp | 20 ++++++++--- app/maptools/measurementmaptool.cpp | 31 ++++++++++++----- app/maptools/measurementmaptool.h | 2 +- app/qml/gps/MMMeasureDrawer.qml | 2 ++ app/qml/main.qml | 33 ++++++++++++++++++ app/qml/map/MMMapController.qml | 2 +- app/qml/map/MMMeasurementTools.qml | 47 ++++++++++++++------------ app/qml/map/components/MMCrosshair.qml | 3 +- 8 files changed, 102 insertions(+), 38 deletions(-) diff --git a/app/map/inputmapsettings.cpp b/app/map/inputmapsettings.cpp index a529313e3..991047c57 100644 --- a/app/map/inputmapsettings.cpp +++ b/app/map/inputmapsettings.cpp @@ -135,11 +135,21 @@ QgsRectangle InputMapSettings::visibleExtent() const QPointF InputMapSettings::coordinateToScreen( const QgsPoint &point ) const { - QgsPointXY pt( point.x(), point.y() ); - QgsPointXY pp = mMapSettings.mapToPixel().transform( pt ); - pp.setX( pp.x() / devicePixelRatio() ); - pp.setY( pp.y() / devicePixelRatio() ); - return pp.toQPointF(); + QgsPointXY pt( point.x(), point.y() ); + + QgsPointXY pp = mMapSettings.mapToPixel().transform( pt ); + + pp.setX( pp.x() / devicePixelRatio() ); + qDebug() << "DEBUG: devicePixelRatio=" << devicePixelRatio(); + qDebug() << "DEBUG: pp.setX =" << pp.x(); + + pp.setY( pp.y() / devicePixelRatio() ); + qDebug() << "DEBUG: pp.setY =" << pp.y(); + + QPointF result = pp.toQPointF(); + qDebug() << "DEBUG: Returning QPointF result =" << result; + + return result; } QgsPoint InputMapSettings::screenToCoordinate( const QPointF &point ) const diff --git a/app/maptools/measurementmaptool.cpp b/app/maptools/measurementmaptool.cpp index 8300421bc..8d32888d6 100644 --- a/app/maptools/measurementmaptool.cpp +++ b/app/maptools/measurementmaptool.cpp @@ -22,6 +22,7 @@ MeasurementMapTool::~MeasurementMapTool() void MeasurementMapTool::addPoint( const QgsPoint &point ) { + //transforming crs to map crs mPoints.push_back( point ); rebuildGeometry(); } @@ -75,24 +76,36 @@ double MeasurementMapTool::updateDistance( const QgsPoint &crosshairPoint ) if ( mPoints.count() >= 3 ) { - QgsPoint firstPoint = mPoints.first(); - double distanceToFirstPoint = QgsDistanceArea().measureLine( crosshairPoint, firstPoint ); + qDebug() << "DEBUG: mPoints.count() >= 3"; - if ( distanceToFirstPoint <= CLOSE_THRESHOLD ) - emit canCloseShape( true ); - else - emit canCloseShape( false ); + QgsPoint firstPoint = mPoints.first(); + //qDebug() << "DEBUG: firstPoint =" << firstPoint; + + QPointF firstPointScreen = mapSettings()->coordinateToScreen( firstPoint ); + qDebug() << "DEBUG: firstPointScreen =" << firstPointScreen; + + QPointF crosshairScreen = mapSettings()->coordinateToScreen( crosshairPoint ); + qDebug() << "DEBUG: crosshairScreen =" << crosshairScreen; + + double distanceToFirstPoint = std::hypot( crosshairScreen.x() - firstPointScreen.x(), crosshairScreen.y() - firstPointScreen.y() ); + qDebug() << "DEBUG: distanceToFirstPoint =" << distanceToFirstPoint; + + if ( distanceToFirstPoint <= CLOSE_THRESHOLD ) //points to map crs -> addPoint + emit canCloseShape( true ); + else + emit canCloseShape( false ); } QgsPoint lastPoint = mPoints.last(); QgsDistanceArea mDistanceArea; mDistanceArea.setEllipsoid( QStringLiteral( "WGS84" ) ); - //mDistanceArea.setSourceCrs( mapSettings()->destinationCrs(), mapSettings()->transformContext() ); + mDistanceArea.setSourceCrs( mapSettings()->destinationCrs(), mapSettings()->transformContext() ); - mDistanceArea.setSourceCrs( QgsCoordinateReferenceSystem::fromEpsgId( 4326 ), QgsCoordinateTransformContext() ); + //mDistanceArea.setSourceCrs( QgsCoordinateReferenceSystem::fromEpsgId( 4326 ), QgsCoordinateTransformContext() ); - return mDistanceArea.measureLine( crosshairPoint, lastPoint ); + //measureLength + return mDistanceArea.measureLine( crosshairPoint, lastPoint );//or transform points crs here } void MeasurementMapTool::closeShape() diff --git a/app/maptools/measurementmaptool.h b/app/maptools/measurementmaptool.h index 7c1466608..cc1a1d8a0 100644 --- a/app/maptools/measurementmaptool.h +++ b/app/maptools/measurementmaptool.h @@ -19,7 +19,7 @@ #include #include -const double CLOSE_THRESHOLD = 100.0; +const double CLOSE_THRESHOLD = 5.0; // in pixels class MeasurementMapTool : public AbstractMapTool { diff --git a/app/qml/gps/MMMeasureDrawer.qml b/app/qml/gps/MMMeasureDrawer.qml index eee67eec8..168d27f88 100644 --- a/app/qml/gps/MMMeasureDrawer.qml +++ b/app/qml/gps/MMMeasureDrawer.qml @@ -24,6 +24,8 @@ MMDrawer { property var mapCanvas + readonly property alias panelHeight: root.height + property bool canCloseShape: false property bool closeShapeDone: false property bool canUndo: false diff --git a/app/qml/main.qml b/app/qml/main.qml index a738a1c70..08133e4cd 100644 --- a/app/qml/main.qml +++ b/app/qml/main.qml @@ -158,6 +158,10 @@ ApplicationWindow { // if stakeout panel is opened return stakeoutPanelLoader.item.panelHeight - mapToolbar.height } + else if ( map.measureLoader.active ) + { + return map.measureLoader.item.measurePanel.panelHeight - mapToolbar.height + } else if ( formsStackManager.takenVerticalSpace > 0 ) { // if feature preview panel is opened @@ -609,6 +613,35 @@ ApplicationWindow { } } + Loader { + id: stakeoutPanelLoader + + focus: true + active: false + asynchronous: true + + sourceComponent: stakeoutPanelComponent + } + + Component { + id: stakeoutPanelComponent + + MMMeasureDrawer { + id: measurePanel + + width: window.width + mapCanvas: root.map + + //bind length and area to mapTool.length and mapTool.area / iconSource === or closeShape + onAddMeasurePoint: mapTool.addPoint( crosshair.recordPoint ) + onMeasureDone: finishMeasurementDialog.open() + onMeasureFinished: root.finishMeasurement() + onCloseShape: root.closeShape() + onRepeat: root.repeatMeasure() + onUndo: mapTool.removePoint() + } + } + MMFormStackController { id: formsStackManager diff --git a/app/qml/map/MMMapController.qml b/app/qml/map/MMMapController.qml index 5f356253e..2884cc926 100644 --- a/app/qml/map/MMMapController.qml +++ b/app/qml/map/MMMapController.qml @@ -592,7 +592,7 @@ Item { } visible: { - if ( root.mapExtentOffset > 0 && root.state !== "stakeout" ) return false + if ( root.mapExtentOffset > 0 && ( root.state !== "stakeout" || root.state !== "measure" ) ) return false if ( __positionKit.positionProvider && __positionKit.positionProvider.type() === "external" ) { // for external receivers we want to show gps panel and accuracy button diff --git a/app/qml/map/MMMeasurementTools.qml b/app/qml/map/MMMeasurementTools.qml index b6da19087..74d6c60f8 100644 --- a/app/qml/map/MMMeasurementTools.qml +++ b/app/qml/map/MMMeasurementTools.qml @@ -34,7 +34,7 @@ Item { onCanCloseShape: function( canClose ) { measurePanel.canCloseShape = canClose; } onCanUndo: function( canUndo ) { measurePanel.canUndo = canUndo; } - onShapeAreaAndPerimeter: function( area, perimeter) { + onShapeAreaAndPerimeter: function( area, perimeter ) { measurePanel.area = __inputUtils.formatAreaInProjectUnit( area, 1 ) measurePanel.perimeter = __inputUtils.formatDistanceInProjectUnit( perimeter, 1 ) } @@ -77,36 +77,41 @@ Item { geometry: __inputUtils.transformGeometryToMapWithLayer( mapTool.recordedGeometry, __activeLayer.vectorLayer, root.map.mapSettings ) } - MMMeasureDrawer { - id: measurePanel + // MMMeasureDrawer { + // id: measurePanel - width: window.width - mapCanvas: root.map + // width: window.width + // mapCanvas: root.map - onAddMeasurePoint: mapTool.addPoint( crosshair.recordPoint ) - onMeasureDone: finishMeasurementDialog.open() - onMeasureFinished: root.finishMeasurement() - onCloseShape: root.closeShape() - onRepeat: root.repeatMeasure() - onUndo: mapTool.removePoint() - } + // //bind length and area to mapTool.length and mapTool.area / iconSource === or closeShape + // onAddMeasurePoint: mapTool.addPoint( crosshair.recordPoint ) + // onMeasureDone: finishMeasurementDialog.open() + // onMeasureFinished: root.finishMeasurement() + // onCloseShape: root.closeShape() + // onRepeat: root.repeatMeasure() + // onUndo: mapTool.removePoint() + // } MMCrosshair { id: crosshair + anchors.fill: parent qgsProject: __activeProject.qgsProject mapSettings: root.map.mapSettings } - MMMapLabel { - id: mapLabel + // MMMapLabel { + // id: mapLabel - text: qsTr( "0.0 m" ) - bgColor: __style.forestColor - textColor: __style.polarColor - textBgColorInverted: false - onClicked: console.log( "MapLabel" ) - } + // text: qsTr( "0.0 m" ) + // bgColor: __style.forestColor + // textColor: __style.polarColor + // textBgColorInverted: false + // onClicked: console.log( "MapLabel: ", crosshair.height ) + + // y: crosshair.crosshairForeground.y + // anchors.horizontalCenter: crosshair.horizontalCenter + // } MMFinishMeasurementDialog { id: finishMeasurementDialog @@ -116,7 +121,7 @@ Item { function onScreenPositionChanged() { let distance = mapTool.updateDistance( crosshair.recordPoint ); - measurePanel.length = __inputUtils.formatDistanceInProjectUnit( distance, 1 ); //distance.toFixed( 1 ) + " m"; + measurePanel.length = __inputUtils.formatDistanceInProjectUnit( distance, 1 ); if ( measurePanel.canCloseShape ) { mapLabel.text = qsTr( "Close shape" ) mapLabel.iconSource = __style.closeShapeIcon diff --git a/app/qml/map/components/MMCrosshair.qml b/app/qml/map/components/MMCrosshair.qml index a9c7ec465..326b00868 100644 --- a/app/qml/map/components/MMCrosshair.qml +++ b/app/qml/map/components/MMCrosshair.qml @@ -28,6 +28,8 @@ Item { property real outerSize: 60 * __dp property real innerDotSize: 10 * __dp + property alias crosshairForeground: crosshairForeground + MM.SnapUtils { id: snapUtils @@ -36,7 +38,6 @@ Item { qgsProject: root.qgsProject useSnapping: root.shouldUseSnapping destinationLayer: __activeLayer.vectorLayer - } Image { From 8c54e59a840e24b0ba6ae4ca8faed10524f652e2 Mon Sep 17 00:00:00 2001 From: VitorVieiraZ Date: Tue, 27 Aug 2024 13:40:26 -0300 Subject: [PATCH 20/60] temp crs handling --- app/maptools/measurementmaptool.cpp | 65 +++++++++++++++++------------ app/maptools/measurementmaptool.h | 6 +++ 2 files changed, 44 insertions(+), 27 deletions(-) diff --git a/app/maptools/measurementmaptool.cpp b/app/maptools/measurementmaptool.cpp index 8d32888d6..60e89bf0e 100644 --- a/app/maptools/measurementmaptool.cpp +++ b/app/maptools/measurementmaptool.cpp @@ -22,11 +22,11 @@ MeasurementMapTool::~MeasurementMapTool() void MeasurementMapTool::addPoint( const QgsPoint &point ) { - //transforming crs to map crs mPoints.push_back( point ); rebuildGeometry(); } + void MeasurementMapTool::removePoint() { if ( !mPoints.isEmpty() ) @@ -76,36 +76,30 @@ double MeasurementMapTool::updateDistance( const QgsPoint &crosshairPoint ) if ( mPoints.count() >= 3 ) { - qDebug() << "DEBUG: mPoints.count() >= 3"; - - QgsPoint firstPoint = mPoints.first(); - //qDebug() << "DEBUG: firstPoint =" << firstPoint; - - QPointF firstPointScreen = mapSettings()->coordinateToScreen( firstPoint ); - qDebug() << "DEBUG: firstPointScreen =" << firstPointScreen; - - QPointF crosshairScreen = mapSettings()->coordinateToScreen( crosshairPoint ); - qDebug() << "DEBUG: crosshairScreen =" << crosshairScreen; - - double distanceToFirstPoint = std::hypot( crosshairScreen.x() - firstPointScreen.x(), crosshairScreen.y() - firstPointScreen.y() ); - qDebug() << "DEBUG: distanceToFirstPoint =" << distanceToFirstPoint; - - if ( distanceToFirstPoint <= CLOSE_THRESHOLD ) //points to map crs -> addPoint - emit canCloseShape( true ); - else - emit canCloseShape( false ); + QgsPoint firstPoint = mPoints.first(); + QPointF firstPointScreen = mapSettings()->coordinateToScreen( firstPoint ); + QPointF crosshairScreen = mapSettings()->coordinateToScreen( crosshairPoint ); + + double distanceToFirstPoint = std::hypot( crosshairScreen.x() - firstPointScreen.x(), crosshairScreen.y() - firstPointScreen.y() ); + + if ( distanceToFirstPoint <= CLOSE_THRESHOLD ) + { + emit canCloseShape( true ); + } + else + { + emit canCloseShape( false ); + } } QgsPoint lastPoint = mPoints.last(); QgsDistanceArea mDistanceArea; mDistanceArea.setEllipsoid( QStringLiteral( "WGS84" ) ); - mDistanceArea.setSourceCrs( mapSettings()->destinationCrs(), mapSettings()->transformContext() ); - - //mDistanceArea.setSourceCrs( QgsCoordinateReferenceSystem::fromEpsgId( 4326 ), QgsCoordinateTransformContext() ); + mDistanceArea.setSourceCrs( mActiveLayer->crs(), QgsCoordinateTransformContext() ); + //mDistanceArea.setSourceCrs(mapSettings()->destinationCrs(), QgsCoordinateTransformContext() ); - //measureLength - return mDistanceArea.measureLine( crosshairPoint, lastPoint );//or transform points crs here + return mDistanceArea.measureLength( mRecordedGeometry ) + mDistanceArea.measureLine( crosshairPoint, lastPoint ); } void MeasurementMapTool::closeShape() @@ -125,9 +119,7 @@ void MeasurementMapTool::closeShape() QgsDistanceArea mDistanceArea; mDistanceArea.setEllipsoid( QStringLiteral( "WGS84" ) ); - //mDistanceArea.setSourceCrs( mapSettings()->destinationCrs(), mapSettings()->transformContext() ); - - mDistanceArea.setSourceCrs( QgsCoordinateReferenceSystem::fromEpsgId( 4326 ), QgsCoordinateTransformContext() ); + mDistanceArea.setSourceCrs( mActiveLayer->crs(), QgsCoordinateTransformContext() ); double area = mDistanceArea.measureArea( polygonGeometry ); double perimeter = mDistanceArea.measurePerimeter( polygonGeometry ); @@ -145,4 +137,23 @@ void MeasurementMapTool::repeat() rebuildGeometry(); } +void MeasurementMapTool::setActiveLayer( QgsVectorLayer *newActiveLayer ) +{ + if ( mActiveLayer == newActiveLayer ) + return; + + if ( mActiveLayer && mActiveLayer->isEditable() ) + { + mActiveLayer->rollBack(); + mActiveLayer->triggerRepaint(); + } + + mActiveLayer = newActiveLayer; + emit activeLayerChanged( mActiveLayer ); +} + +QgsVectorLayer *MeasurementMapTool::activeLayer() const +{ + return mActiveLayer; +} diff --git a/app/maptools/measurementmaptool.h b/app/maptools/measurementmaptool.h index cc1a1d8a0..3d495e93f 100644 --- a/app/maptools/measurementmaptool.h +++ b/app/maptools/measurementmaptool.h @@ -15,6 +15,7 @@ #include #include "qgsdistancearea.h" #include "qgsgeometry.h" +#include "inpututils.h" #include #include #include @@ -26,6 +27,7 @@ class MeasurementMapTool : public AbstractMapTool Q_OBJECT Q_PROPERTY( QgsGeometry recordedGeometry READ recordedGeometry WRITE setRecordedGeometry NOTIFY recordedGeometryChanged ) + Q_PROPERTY( QgsVectorLayer *activeLayer READ activeLayer WRITE setActiveLayer NOTIFY activeLayerChanged ) public: explicit MeasurementMapTool( QObject *parent = nullptr ); @@ -51,6 +53,7 @@ class MeasurementMapTool : public AbstractMapTool QgsVectorLayer *activeLayer() const; void setActiveLayer( QgsVectorLayer *newActiveLayer ); + void fixZM( QgsPoint &point ) const; signals: void recordedGeometryChanged( const QgsGeometry &recordedGeometry ); @@ -60,6 +63,8 @@ class MeasurementMapTool : public AbstractMapTool void shapeAreaAndPerimeter( double area, double perimeter ); + void activeLayerChanged( QgsVectorLayer *activeLayer ); + protected: void rebuildGeometry(); @@ -69,6 +74,7 @@ class MeasurementMapTool : public AbstractMapTool private: QVector mPoints; QgsGeometry mRecordedGeometry; + QgsVectorLayer *mActiveLayer = nullptr; // not owned }; #endif // MEASUREMENTMAPTOOL_H From 467f904fa0f6f0ef358202eb7460b55af0cfb8f6 Mon Sep 17 00:00:00 2001 From: VitorVieiraZ Date: Tue, 27 Aug 2024 14:37:41 -0300 Subject: [PATCH 21/60] in progress --- app/inpututils.cpp | 12 ++++++ app/map/inputmapsettings.cpp | 16 +++----- app/qml/main.qml | 56 +++++++++++++-------------- app/qml/map/MMMeasurementTools.qml | 49 ++++++++++++----------- app/qml/map/components/MMMapLabel.qml | 8 ++-- 5 files changed, 77 insertions(+), 64 deletions(-) diff --git a/app/inpututils.cpp b/app/inpututils.cpp index 9904308f4..eed98bc2e 100644 --- a/app/inpututils.cpp +++ b/app/inpututils.cpp @@ -843,35 +843,47 @@ QgsPoint InputUtils::transformPoint( const QgsCoordinateReferenceSystem &srcCrs, const QgsCoordinateTransformContext &context, const QgsPoint &srcPoint ) { + // we do not want to transform empty points, // QGIS would convert them to a valid (0, 0) points if ( srcPoint.isEmpty() ) { + qDebug() << "Source point is empty, returning an empty QgsPoint."; return QgsPoint(); } try { + qDebug() << "Creating QgsCoordinateTransform with srcCrs, destCrs, and context."; QgsCoordinateTransform ct( srcCrs, destCrs, context ); if ( ct.isValid() ) { + qDebug() << "CoordinateTransform is valid."; if ( !ct.isShortCircuited() ) { + qDebug() << "Transform is not short-circuited, transforming point."; const QgsPointXY transformed = ct.transform( srcPoint.x(), srcPoint.y() ); const QgsPoint pt( transformed.x(), transformed.y(), srcPoint.z(), srcPoint.m() ); return pt; } else { + qDebug() << "Transform is short-circuited, returning source point."; return srcPoint; } } + else + { + qDebug() << "CoordinateTransform is not valid."; + } } catch ( QgsCsException &cse ) { + qDebug() << "Caught QgsCsException during transformation:" << cse.what(); Q_UNUSED( cse ) } + qDebug() << "Returning an empty QgsPoint due to unsuccessful transformation."; return QgsPoint(); } diff --git a/app/map/inputmapsettings.cpp b/app/map/inputmapsettings.cpp index 991047c57..0f6654b7f 100644 --- a/app/map/inputmapsettings.cpp +++ b/app/map/inputmapsettings.cpp @@ -135,21 +135,17 @@ QgsRectangle InputMapSettings::visibleExtent() const QPointF InputMapSettings::coordinateToScreen( const QgsPoint &point ) const { - QgsPointXY pt( point.x(), point.y() ); + QgsPointXY pt( point.x(), point.y() ); - QgsPointXY pp = mMapSettings.mapToPixel().transform( pt ); + QgsPointXY pp = mMapSettings.mapToPixel().transform( pt ); - pp.setX( pp.x() / devicePixelRatio() ); - qDebug() << "DEBUG: devicePixelRatio=" << devicePixelRatio(); - qDebug() << "DEBUG: pp.setX =" << pp.x(); + pp.setX( pp.x() / devicePixelRatio() ); - pp.setY( pp.y() / devicePixelRatio() ); - qDebug() << "DEBUG: pp.setY =" << pp.y(); + pp.setY( pp.y() / devicePixelRatio() ); - QPointF result = pp.toQPointF(); - qDebug() << "DEBUG: Returning QPointF result =" << result; + QPointF result = pp.toQPointF(); - return result; + return result; } QgsPoint InputMapSettings::screenToCoordinate( const QPointF &point ) const diff --git a/app/qml/main.qml b/app/qml/main.qml index 08133e4cd..c93e5566c 100644 --- a/app/qml/main.qml +++ b/app/qml/main.qml @@ -613,34 +613,34 @@ ApplicationWindow { } } - Loader { - id: stakeoutPanelLoader - - focus: true - active: false - asynchronous: true - - sourceComponent: stakeoutPanelComponent - } - - Component { - id: stakeoutPanelComponent - - MMMeasureDrawer { - id: measurePanel - - width: window.width - mapCanvas: root.map - - //bind length and area to mapTool.length and mapTool.area / iconSource === or closeShape - onAddMeasurePoint: mapTool.addPoint( crosshair.recordPoint ) - onMeasureDone: finishMeasurementDialog.open() - onMeasureFinished: root.finishMeasurement() - onCloseShape: root.closeShape() - onRepeat: root.repeatMeasure() - onUndo: mapTool.removePoint() - } - } + // Loader { + // id: stakeoutPanelLoader + + // focus: true + // active: false + // asynchronous: true + + // sourceComponent: stakeoutPanelComponent + // } + + // Component { + // id: stakeoutPanelComponent + + // MMMeasureDrawer { + // id: measurePanel + + // width: window.width + // mapCanvas: root.map + + // //bind length and area to mapTool.length and mapTool.area / iconSource === or closeShape + // onAddMeasurePoint: mapTool.addPoint( crosshair.recordPoint ) + // onMeasureDone: finishMeasurementDialog.open() + // onMeasureFinished: root.finishMeasurement() + // onCloseShape: root.closeShape() + // onRepeat: root.repeatMeasure() + // onUndo: mapTool.removePoint() + // } + // } MMFormStackController { id: formsStackManager diff --git a/app/qml/map/MMMeasurementTools.qml b/app/qml/map/MMMeasurementTools.qml index 74d6c60f8..a61e8af2d 100644 --- a/app/qml/map/MMMeasurementTools.qml +++ b/app/qml/map/MMMeasurementTools.qml @@ -31,6 +31,7 @@ Item { MM.MeasurementMapTool { id: mapTool mapSettings: root.map.mapSettings + activeLayer: __activeLayer.vectorLayer onCanCloseShape: function( canClose ) { measurePanel.canCloseShape = canClose; } onCanUndo: function( canUndo ) { measurePanel.canUndo = canUndo; } @@ -77,20 +78,20 @@ Item { geometry: __inputUtils.transformGeometryToMapWithLayer( mapTool.recordedGeometry, __activeLayer.vectorLayer, root.map.mapSettings ) } - // MMMeasureDrawer { - // id: measurePanel + MMMeasureDrawer { + id: measurePanel - // width: window.width - // mapCanvas: root.map + width: window.width + mapCanvas: root.map - // //bind length and area to mapTool.length and mapTool.area / iconSource === or closeShape - // onAddMeasurePoint: mapTool.addPoint( crosshair.recordPoint ) - // onMeasureDone: finishMeasurementDialog.open() - // onMeasureFinished: root.finishMeasurement() - // onCloseShape: root.closeShape() - // onRepeat: root.repeatMeasure() - // onUndo: mapTool.removePoint() - // } + //bind length and area to mapTool.length and mapTool.area / iconSource === or closeShape + onAddMeasurePoint: mapTool.addPoint( crosshair.recordPoint ) + onMeasureDone: finishMeasurementDialog.open() + onMeasureFinished: root.finishMeasurement() + onCloseShape: root.closeShape() + onRepeat: root.repeatMeasure() + onUndo: mapTool.removePoint() + } MMCrosshair { id: crosshair @@ -98,20 +99,24 @@ Item { anchors.fill: parent qgsProject: __activeProject.qgsProject mapSettings: root.map.mapSettings + } - // MMMapLabel { - // id: mapLabel + MMMapLabel { + id: mapLabel - // text: qsTr( "0.0 m" ) - // bgColor: __style.forestColor - // textColor: __style.polarColor - // textBgColorInverted: false - // onClicked: console.log( "MapLabel: ", crosshair.height ) + text: qsTr( "0.0 m" ) - // y: crosshair.crosshairForeground.y - // anchors.horizontalCenter: crosshair.horizontalCenter - // } + //implicitWidth: crosshair.width + //implicitHeight: crosshair.crosshairForeground.height - 10 + bgColor: __style.forestColor + textColor: __style.polarColor + textBgColorInverted: false + onClicked: console.log( "MapLabel: ", crosshair.height ) + + y: crosshair.crosshairForeground.y + crosshair.crosshairForeground.height + anchors.horizontalCenter: crosshair.crosshairForeground.horizontalCenter + } MMFinishMeasurementDialog { id: finishMeasurementDialog diff --git a/app/qml/map/components/MMMapLabel.qml b/app/qml/map/components/MMMapLabel.qml index d5ef423bb..f2e179544 100644 --- a/app/qml/map/components/MMMapLabel.qml +++ b/app/qml/map/components/MMMapLabel.qml @@ -24,7 +24,7 @@ Item { required property string text property real maxWidth: implicitWidth - property url iconSource: "" + property string iconSource property color bgColor: __style.positiveColor property color textColor: __style.forestColor property bool textBgColorInverted: false @@ -43,7 +43,7 @@ Item { id: row anchors.centerIn: parent - leftPadding: 20 * __dp + leftPadding: 8 * __dp rightPadding: leftPadding spacing: 4 * __dp height: parent.height @@ -53,7 +53,7 @@ Item { anchors.verticalCenter: parent.verticalCenter source: control.iconSource ? control.iconSource : "" color: control.textColor - size: control.iconSource !== "" ? __style.icon24 : 0 + size: control.iconSource ? __style.icon24 : 0 } Rectangle { @@ -74,7 +74,7 @@ Item { anchors.centerIn: parent color: control.textBgColorInverted ? control.bgColor : control.textColor text: control.text - font: __style.t3 + font: __style.t5 elide: Text.ElideRight } } From 01d647be08ff7d1e8c1f06e036143115f80f5cca Mon Sep 17 00:00:00 2001 From: VitorVieiraZ Date: Wed, 28 Aug 2024 13:46:14 -0300 Subject: [PATCH 22/60] binding values to cpp measurement tool --- app/maptools/measurementmaptool.cpp | 49 +++++++++++++++- app/maptools/measurementmaptool.h | 29 ++++++++-- app/qml/gps/MMMeasureDrawer.qml | 18 +++--- app/qml/main.qml | 61 +++++++++++--------- app/qml/map/MMMapController.qml | 30 ++++++---- app/qml/map/MMMeasurementTools.qml | 83 +++++++++++++-------------- app/qml/map/components/MMMapLabel.qml | 9 ++- 7 files changed, 177 insertions(+), 102 deletions(-) diff --git a/app/maptools/measurementmaptool.cpp b/app/maptools/measurementmaptool.cpp index 60e89bf0e..9e921e89c 100644 --- a/app/maptools/measurementmaptool.cpp +++ b/app/maptools/measurementmaptool.cpp @@ -61,6 +61,21 @@ const QgsGeometry &MeasurementMapTool::recordedGeometry() const return mRecordedGeometry; } +double MeasurementMapTool::area() const +{ + return mArea; +} + +double MeasurementMapTool::perimeter() const +{ + return mPerimeter; +} + +double MeasurementMapTool::length() const +{ + return mLength; +} + void MeasurementMapTool::setRecordedGeometry( const QgsGeometry &newRecordedGeometry ) { if ( mRecordedGeometry.equals( newRecordedGeometry ) ) @@ -69,10 +84,10 @@ void MeasurementMapTool::setRecordedGeometry( const QgsGeometry &newRecordedGeom emit recordedGeometryChanged( mRecordedGeometry ); } -double MeasurementMapTool::updateDistance( const QgsPoint &crosshairPoint ) +void MeasurementMapTool::updateDistance( const QgsPoint &crosshairPoint ) { if ( mPoints.isEmpty() ) - return 0.0; + setLength(0.0); if ( mPoints.count() >= 3 ) { @@ -99,7 +114,9 @@ double MeasurementMapTool::updateDistance( const QgsPoint &crosshairPoint ) mDistanceArea.setSourceCrs( mActiveLayer->crs(), QgsCoordinateTransformContext() ); //mDistanceArea.setSourceCrs(mapSettings()->destinationCrs(), QgsCoordinateTransformContext() ); - return mDistanceArea.measureLength( mRecordedGeometry ) + mDistanceArea.measureLine( crosshairPoint, lastPoint ); + double calculatedLength = mDistanceArea.measureLength( mRecordedGeometry ) + mDistanceArea.measureLine( crosshairPoint, lastPoint ); + + setLength(calculatedLength); } void MeasurementMapTool::closeShape() @@ -152,6 +169,32 @@ void MeasurementMapTool::setActiveLayer( QgsVectorLayer *newActiveLayer ) emit activeLayerChanged( mActiveLayer ); } +void MeasurementMapTool::setLength( const double &length ) { + if ( mLength == length ) + return; + + mLength = length; + emit lengthChanged( length ); +} + +void MeasurementMapTool::setArea( const double &area ) { + if ( mArea == area ) + return; + + mArea = area; + emit areaChanged( area ); +} + +void MeasurementMapTool::setPerimeter( const double &perimeter ) { + if ( mPerimeter == perimeter ) + return; + + mPerimeter = perimeter; + emit perimeterChanged( perimeter ); +} + + + QgsVectorLayer *MeasurementMapTool::activeLayer() const { return mActiveLayer; diff --git a/app/maptools/measurementmaptool.h b/app/maptools/measurementmaptool.h index 3d495e93f..f67b5ae15 100644 --- a/app/maptools/measurementmaptool.h +++ b/app/maptools/measurementmaptool.h @@ -28,6 +28,9 @@ class MeasurementMapTool : public AbstractMapTool Q_PROPERTY( QgsGeometry recordedGeometry READ recordedGeometry WRITE setRecordedGeometry NOTIFY recordedGeometryChanged ) Q_PROPERTY( QgsVectorLayer *activeLayer READ activeLayer WRITE setActiveLayer NOTIFY activeLayerChanged ) + Q_PROPERTY( double length READ length WRITE setLength NOTIFY lengthChanged) + Q_PROPERTY( double perimeter READ perimeter WRITE setPerimeter NOTIFY perimeterChanged) + Q_PROPERTY( double area READ area WRITE setArea NOTIFY areaChanged) public: explicit MeasurementMapTool( QObject *parent = nullptr ); @@ -46,7 +49,17 @@ class MeasurementMapTool : public AbstractMapTool Q_INVOKABLE void removePoint(); Q_INVOKABLE void closeShape(); - Q_INVOKABLE void repeat(); + Q_INVOKABLE void repeat(); + + double length() const; + void setLength(const double &length); + + double perimeter() const; + void setPerimeter(const double &perimeter); + + double area() const; + void setArea(const double &area); + const QgsGeometry &recordedGeometry() const; void setRecordedGeometry( const QgsGeometry &newRecordedGeometry ); @@ -56,6 +69,11 @@ class MeasurementMapTool : public AbstractMapTool void fixZM( QgsPoint &point ) const; signals: + void lengthChanged(const double &length); + void perimeterChanged(const double &perimeter); + void areaChanged(const double &area); + + void activeLayerChanged( QgsVectorLayer *activeLayer ); void recordedGeometryChanged( const QgsGeometry &recordedGeometry ); void canCloseShape( bool canClose ); @@ -63,18 +81,19 @@ class MeasurementMapTool : public AbstractMapTool void shapeAreaAndPerimeter( double area, double perimeter ); - void activeLayerChanged( QgsVectorLayer *activeLayer ); - protected: void rebuildGeometry(); public slots: - double updateDistance( const QgsPoint &crosshairPoint ); + void updateDistance( const QgsPoint &crosshairPoint ); private: QVector mPoints; QgsGeometry mRecordedGeometry; - QgsVectorLayer *mActiveLayer = nullptr; // not owned + QgsVectorLayer *mActiveLayer = nullptr; + double mLength = 0; + double mPerimeter = 0; + double mArea = 0; }; #endif // MEASUREMENTMAPTOOL_H diff --git a/app/qml/gps/MMMeasureDrawer.qml b/app/qml/gps/MMMeasureDrawer.qml index 168d27f88..c55a0f2d5 100644 --- a/app/qml/gps/MMMeasureDrawer.qml +++ b/app/qml/gps/MMMeasureDrawer.qml @@ -26,15 +26,15 @@ MMDrawer { readonly property alias panelHeight: root.height - property bool canCloseShape: false - property bool closeShapeDone: false - property bool canUndo: false + property bool canCloseShape: mapCanvas.mapToolComponent.mapTool.canCloseShape + property bool closeShapeDone: mapCanvas.mapToolComponent.mapTool.closeShapeDone + property bool canUndo: mapCanvas.mapToolComponent.mapTool.canUndo - property string length: qsTr( "0.0 m" ) - property string perimeter: qsTr( "0.0 m" ) - property string area: qsTr( "0.0 m²" ) + property string length: __inputUtils.formatDistanceInProjectUnit( mapCanvas.mapToolComponent.mapTool.length, 1 ) + property string perimeter: __inputUtils.formatDistanceInProjectUnit( mapCanvas.mapToolComponent.mapTool.perimeter, 1 ) + property string area: __inputUtils.formatAreaInProjectUnit( mapCanvas.mapToolComponent.mapTool.area, 1 ) - signal addMeasurePoint() + //signal addMeasurePoint() signal measureFinished() signal measureDone() signal closeShape() @@ -57,7 +57,7 @@ MMDrawer { leftButtonIcon: closeShapeDone ? __style.syncIcon : __style.undoIcon leftButtonType: MMButton.Types.Primary leftButtonEnabled: closeShapeDone || canUndo - onLeftButtonClicked: closeShapeDone ? root.repeatMeasure() : root.undo() + onLeftButtonClicked: closeShapeDone ? root.mapCanvas.mapToolComponent.repeatMeasure() : root.mapCanvas.mapToolComponent.removePoint() drawerHeader.title: qsTr( "Measurement" ) @@ -95,7 +95,7 @@ MMDrawer { MMButton { text: root.canCloseShape ? qsTr( "Close shape" ) : qsTr( "Add point" ) iconSourceLeft: canCloseShape ? __style.closeShapeIcon : __style.plusIcon - onClicked: canCloseShape ? root.closeShape() : root.addMeasurePoint() + onClicked: canCloseShape ? root.mapCanvas.mapToolComponent.closeShape() : root.mapCanvas.mapToolComponent.addPoint() } MMButton { diff --git a/app/qml/main.qml b/app/qml/main.qml index c93e5566c..677acd71e 100644 --- a/app/qml/main.qml +++ b/app/qml/main.qml @@ -158,9 +158,9 @@ ApplicationWindow { // if stakeout panel is opened return stakeoutPanelLoader.item.panelHeight - mapToolbar.height } - else if ( map.measureLoader.active ) + else if ( measurePanelLoader.active ) { - return map.measureLoader.item.measurePanel.panelHeight - mapToolbar.height + return measurePanelLoader.item.panelHeight - mapToolbar.height } else if ( formsStackManager.takenVerticalSpace > 0 ) { @@ -224,7 +224,8 @@ ApplicationWindow { } onMeasureStarted: function( pair ) { - console.log(" measure started") + measurePanelLoader.active = true + measurePanelLoader.focus = true } onLocalChangesPanelRequested: { @@ -467,7 +468,7 @@ ApplicationWindow { mapSettings: map.mapSettings // disable the receivers button when staking out - showReceiversButton: !stakeoutPanelLoader.active + showReceiversButton: !stakeoutPanelLoader.active || !measurePanelLoader.active onManageReceiversClicked: { gpsDataDrawer.close() @@ -613,34 +614,33 @@ ApplicationWindow { } } - // Loader { - // id: stakeoutPanelLoader + Loader { + id: measurePanelLoader + + focus: true + active: false + asynchronous: true - // focus: true - // active: false - // asynchronous: true + sourceComponent: measurePanelComponent + } - // sourceComponent: stakeoutPanelComponent - // } + Component { + id: measurePanelComponent - // Component { - // id: stakeoutPanelComponent + MMMeasureDrawer { + id: measurePanel - // MMMeasureDrawer { - // id: measurePanel + width: window.width + mapCanvas: map - // width: window.width - // mapCanvas: root.map + onMeasureDone: finishMeasurementDialog.open() - // //bind length and area to mapTool.length and mapTool.area / iconSource === or closeShape - // onAddMeasurePoint: mapTool.addPoint( crosshair.recordPoint ) - // onMeasureDone: finishMeasurementDialog.open() - // onMeasureFinished: root.finishMeasurement() - // onCloseShape: root.closeShape() - // onRepeat: root.repeatMeasure() - // onUndo: mapTool.removePoint() - // } - // } + onMeasureFinished: { + measurePanelLoader.active = false + map.finishMeasure() + } + } + } MMFormStackController { id: formsStackManager @@ -773,6 +773,15 @@ ApplicationWindow { } } + MMFinishMeasurementDialog { + id: finishMeasurementDialog + + onFinishMeasurementRequested: { + measurePanelLoader.active = false + map.finishMeasure() + } + } + MMNotificationView {} MMListDrawer { diff --git a/app/qml/map/MMMapController.qml b/app/qml/map/MMMapController.qml index 2884cc926..8ec9ac712 100644 --- a/app/qml/map/MMMapController.qml +++ b/app/qml/map/MMMapController.qml @@ -35,6 +35,10 @@ Item { property bool isStreaming: recordingToolsLoader.active ? recordingToolsLoader.item.recordingMapTool.recordingType === MM.RecordingMapTool.StreamMode : false property bool centeredToGPS: false + property var mapToolComponent: { + state === "measure" ? measurementToolsLoader.item : null + } + property MM.PositionTrackingManager trackingManager: tracking.item?.manager ?? null signal featureIdentified( var pair ) @@ -298,17 +302,6 @@ Item { sourceComponent: stakeoutToolsComponent } - Loader { - id: measureLoader - - anchors.fill: mapCanvas - - asynchronous: true - active: root.state === "measure" - - sourceComponent: measurementToolsComponent - } - Loader { id: tracking @@ -403,6 +396,17 @@ Item { sourceComponent: splittingToolsComponent } + Loader { + id: measurementToolsLoader + + anchors.fill: mapCanvas + + asynchronous: true + active: root.state === "measure" + + sourceComponent: measurementToolsComponent + } + // map available content within safe area Item { anchors { @@ -1150,8 +1154,10 @@ Item { function measure() { internal.extentBeforeStakeout = mapCanvas.mapSettings.extent - state = "measure" + console.log(" MAP TOOL: ", root.mapTool) + root.mapToolComponent = measurementToolsLoader.item + console.log(" MAP TOOL: ", root.mapTool) } function toggleStreaming() { diff --git a/app/qml/map/MMMeasurementTools.qml b/app/qml/map/MMMeasurementTools.qml index a61e8af2d..736467189 100644 --- a/app/qml/map/MMMeasurementTools.qml +++ b/app/qml/map/MMMeasurementTools.qml @@ -23,6 +23,8 @@ Item { required property MMMapCanvas map required property MMPositionMarker positionMarkerComponent + property var mapTool: mapTool + signal finishMeasurement() Component.onCompleted: map.mapSettings.extentChanged.connect( onScreenPositionChanged ) @@ -30,14 +32,16 @@ Item { MM.MeasurementMapTool { id: mapTool + mapSettings: root.map.mapSettings activeLayer: __activeLayer.vectorLayer - onCanCloseShape: function( canClose ) { measurePanel.canCloseShape = canClose; } - onCanUndo: function( canUndo ) { measurePanel.canUndo = canUndo; } + onCanCloseShape: function( canClose ) { console.log("A") }//measurePanel.canCloseShape = canClose; } + onCanUndo: function( canUndo ) { console.log("A") } //measurePanel.canUndo = canUndo; } onShapeAreaAndPerimeter: function( area, perimeter ) { - measurePanel.area = __inputUtils.formatAreaInProjectUnit( area, 1 ) - measurePanel.perimeter = __inputUtils.formatDistanceInProjectUnit( perimeter, 1 ) + console.log("A") + //measurePanel.area = __inputUtils.formatAreaInProjectUnit( area, 1 ) + //measurePanel.perimeter = __inputUtils.formatDistanceInProjectUnit( perimeter, 1 ) } } @@ -78,20 +82,20 @@ Item { geometry: __inputUtils.transformGeometryToMapWithLayer( mapTool.recordedGeometry, __activeLayer.vectorLayer, root.map.mapSettings ) } - MMMeasureDrawer { - id: measurePanel + // MMMeasureDrawer { + // id: measurePanel - width: window.width - mapCanvas: root.map + // width: window.width + // mapCanvas: root.map - //bind length and area to mapTool.length and mapTool.area / iconSource === or closeShape - onAddMeasurePoint: mapTool.addPoint( crosshair.recordPoint ) - onMeasureDone: finishMeasurementDialog.open() - onMeasureFinished: root.finishMeasurement() - onCloseShape: root.closeShape() - onRepeat: root.repeatMeasure() - onUndo: mapTool.removePoint() - } + // //bind length and area to mapTool.length and mapTool.area / iconSource === or closeShape + // onAddMeasurePoint: mapTool.addPoint( crosshair.recordPoint ) + // onMeasureDone: finishMeasurementDialog.open() + // onMeasureFinished: root.finishMeasurement() + // onCloseShape: root.closeShape() + // onRepeat: root.repeatMeasure() + // onUndo: mapTool.removePoint() + // } MMCrosshair { id: crosshair @@ -102,46 +106,41 @@ Item { } - MMMapLabel { - id: mapLabel + // MMMapLabel { + // id: mapLabel - text: qsTr( "0.0 m" ) + // text: qsTr( "0.0 m" ) - //implicitWidth: crosshair.width - //implicitHeight: crosshair.crosshairForeground.height - 10 - bgColor: __style.forestColor - textColor: __style.polarColor - textBgColorInverted: false - onClicked: console.log( "MapLabel: ", crosshair.height ) + // //implicitWidth: crosshair.width + // //implicitHeight: crosshair.crosshairForeground.height - 10 + // bgColor: __style.forestColor + // textColor: __style.polarColor + // textBgColorInverted: false + // onClicked: console.log( "MapLabel: ", crosshair.height ) - y: crosshair.crosshairForeground.y + crosshair.crosshairForeground.height - anchors.horizontalCenter: crosshair.crosshairForeground.horizontalCenter - } + // y: crosshair.crosshairForeground.y + crosshair.crosshairForeground.height + // anchors.horizontalCenter: crosshair.crosshairForeground.horizontalCenter + // } MMFinishMeasurementDialog { id: finishMeasurementDialog onFinishMeasurementRequested: root.finishMeasurement() } - function onScreenPositionChanged() { - let distance = mapTool.updateDistance( crosshair.recordPoint ); + function addPoint() + { + mapTool.addPoint( crosshair.recordPoint ) + } - measurePanel.length = __inputUtils.formatDistanceInProjectUnit( distance, 1 ); - if ( measurePanel.canCloseShape ) { - mapLabel.text = qsTr( "Close shape" ) - mapLabel.iconSource = __style.closeShapeIcon - } - else { - mapLabel.text = measurePanel.length; - mapLabel.iconSource = "" - } + function onScreenPositionChanged() { + mapTool.updateDistance( crosshair.recordPoint ); } function closeShape() { guidelineController.allowed = false crosshair.visible = false - measurePanel.closeShapeDone = true + //measurePanel.closeShapeDone = true mapTool.closeShape() } @@ -149,8 +148,8 @@ Item { { guidelineController.allowed = true crosshair.visible = true - measurePanel.closeShapeDone = false - measurePanel.canCloseShape = false + // measurePanel.closeShapeDone = false + // measurePanel.canCloseShape = false mapTool.repeat() } } diff --git a/app/qml/map/components/MMMapLabel.qml b/app/qml/map/components/MMMapLabel.qml index f2e179544..2127ddeea 100644 --- a/app/qml/map/components/MMMapLabel.qml +++ b/app/qml/map/components/MMMapLabel.qml @@ -24,11 +24,10 @@ Item { required property string text property real maxWidth: implicitWidth - property string iconSource + property url iconSource: "" property color bgColor: __style.positiveColor property color textColor: __style.forestColor property bool textBgColorInverted: false - property bool hasIcon: true Rectangle { width: row.width @@ -43,7 +42,7 @@ Item { id: row anchors.centerIn: parent - leftPadding: 8 * __dp + leftPadding: 20 * __dp rightPadding: leftPadding spacing: 4 * __dp height: parent.height @@ -53,7 +52,7 @@ Item { anchors.verticalCenter: parent.verticalCenter source: control.iconSource ? control.iconSource : "" color: control.textColor - size: control.iconSource ? __style.icon24 : 0 + size: __style.icon24 } Rectangle { @@ -74,7 +73,7 @@ Item { anchors.centerIn: parent color: control.textBgColorInverted ? control.bgColor : control.textColor text: control.text - font: __style.t5 + font: __style.t3 elide: Text.ElideRight } } From ba2eaaec1279a3cbb71e0e1ba7832b0e38438803 Mon Sep 17 00:00:00 2001 From: VitorVieiraZ Date: Wed, 28 Aug 2024 14:03:12 -0300 Subject: [PATCH 23/60] binding values to cpp class --- app/maptools/measurementmaptool.cpp | 103 ++++++++++++++++++++-------- app/maptools/measurementmaptool.h | 42 +++++++++--- app/qml/gps/MMMeasureDrawer.qml | 2 +- app/qml/map/MMMeasurementTools.qml | 2 +- 4 files changed, 107 insertions(+), 42 deletions(-) diff --git a/app/maptools/measurementmaptool.cpp b/app/maptools/measurementmaptool.cpp index 9e921e89c..95d121be6 100644 --- a/app/maptools/measurementmaptool.cpp +++ b/app/maptools/measurementmaptool.cpp @@ -34,7 +34,7 @@ void MeasurementMapTool::removePoint() mPoints.pop_back(); if ( mPoints.count() < 3 ) - emit canCloseShape( false ); + setCanCloseShape( false ); rebuildGeometry(); } @@ -47,10 +47,10 @@ void MeasurementMapTool::rebuildGeometry() if ( mPoints.count() > 0 ) { geometry = QgsGeometry::fromPolyline( mPoints ); - emit canUndo( true ); + setCanUndo( true ); } else - emit canUndo( false ); + setCanUndo( false ); setRecordedGeometry( geometry ); @@ -63,17 +63,57 @@ const QgsGeometry &MeasurementMapTool::recordedGeometry() const double MeasurementMapTool::area() const { - return mArea; + return mArea; } double MeasurementMapTool::perimeter() const { - return mPerimeter; + return mPerimeter; } double MeasurementMapTool::length() const { - return mLength; + return mLength; +} + +bool MeasurementMapTool::canUndo() const +{ + return mCanUndo; +} + +void MeasurementMapTool::setCanUndo( bool newCanUndo ) +{ + if ( mCanUndo == newCanUndo ) + return; + mCanUndo = newCanUndo; + emit canUndoChanged( mCanUndo ); +} + + +bool MeasurementMapTool::canCloseShape() const +{ + return mCanCloseShape; +} + +void MeasurementMapTool::setCanCloseShape( bool newCanCloseShape ) +{ + if ( mCanCloseShape == newCanCloseShape ) + return; + mCanCloseShape = newCanCloseShape; + emit canCloseShapeChanged( mCanCloseShape ); +} + +bool MeasurementMapTool::closeShapeDone() const +{ + return mCloseShapeDone; +} + +void MeasurementMapTool::setCloseShapeDone( bool newCloseShapeDone ) +{ + if ( mCloseShapeDone == newCloseShapeDone ) + return; + mCloseShapeDone = newCloseShapeDone; + emit closeShapeDoneChanged( mCloseShapeDone ); } void MeasurementMapTool::setRecordedGeometry( const QgsGeometry &newRecordedGeometry ) @@ -87,7 +127,7 @@ void MeasurementMapTool::setRecordedGeometry( const QgsGeometry &newRecordedGeom void MeasurementMapTool::updateDistance( const QgsPoint &crosshairPoint ) { if ( mPoints.isEmpty() ) - setLength(0.0); + setLength( 0.0 ); if ( mPoints.count() >= 3 ) { @@ -99,11 +139,11 @@ void MeasurementMapTool::updateDistance( const QgsPoint &crosshairPoint ) if ( distanceToFirstPoint <= CLOSE_THRESHOLD ) { - emit canCloseShape( true ); + setCanCloseShape( true ); } else { - emit canCloseShape( false ); + setCanCloseShape( false ); } } @@ -116,7 +156,7 @@ void MeasurementMapTool::updateDistance( const QgsPoint &crosshairPoint ) double calculatedLength = mDistanceArea.measureLength( mRecordedGeometry ) + mDistanceArea.measureLine( crosshairPoint, lastPoint ); - setLength(calculatedLength); + setLength( calculatedLength ); } void MeasurementMapTool::closeShape() @@ -141,15 +181,18 @@ void MeasurementMapTool::closeShape() double area = mDistanceArea.measureArea( polygonGeometry ); double perimeter = mDistanceArea.measurePerimeter( polygonGeometry ); - emit shapeAreaAndPerimeter( area, perimeter ); - emit canCloseShape( false ); + setArea( area ); + setPerimeter( perimeter ); + setCanCloseShape( false ); + setCloseShapeDone( true ); } void MeasurementMapTool::repeat() { mPoints.clear(); - emit canCloseShape( false ); + setCanCloseShape( false ); + setCloseShapeDone( false ); rebuildGeometry(); } @@ -169,32 +212,34 @@ void MeasurementMapTool::setActiveLayer( QgsVectorLayer *newActiveLayer ) emit activeLayerChanged( mActiveLayer ); } -void MeasurementMapTool::setLength( const double &length ) { - if ( mLength == length ) - return; +void MeasurementMapTool::setLength( const double &length ) +{ + if ( mLength == length ) + return; - mLength = length; - emit lengthChanged( length ); + mLength = length; + emit lengthChanged( length ); } -void MeasurementMapTool::setArea( const double &area ) { - if ( mArea == area ) - return; +void MeasurementMapTool::setArea( const double &area ) +{ + if ( mArea == area ) + return; - mArea = area; - emit areaChanged( area ); + mArea = area; + emit areaChanged( area ); } -void MeasurementMapTool::setPerimeter( const double &perimeter ) { - if ( mPerimeter == perimeter ) - return; +void MeasurementMapTool::setPerimeter( const double &perimeter ) +{ + if ( mPerimeter == perimeter ) + return; - mPerimeter = perimeter; - emit perimeterChanged( perimeter ); + mPerimeter = perimeter; + emit perimeterChanged( perimeter ); } - QgsVectorLayer *MeasurementMapTool::activeLayer() const { return mActiveLayer; diff --git a/app/maptools/measurementmaptool.h b/app/maptools/measurementmaptool.h index f67b5ae15..1e180c338 100644 --- a/app/maptools/measurementmaptool.h +++ b/app/maptools/measurementmaptool.h @@ -28,9 +28,14 @@ class MeasurementMapTool : public AbstractMapTool Q_PROPERTY( QgsGeometry recordedGeometry READ recordedGeometry WRITE setRecordedGeometry NOTIFY recordedGeometryChanged ) Q_PROPERTY( QgsVectorLayer *activeLayer READ activeLayer WRITE setActiveLayer NOTIFY activeLayerChanged ) - Q_PROPERTY( double length READ length WRITE setLength NOTIFY lengthChanged) - Q_PROPERTY( double perimeter READ perimeter WRITE setPerimeter NOTIFY perimeterChanged) - Q_PROPERTY( double area READ area WRITE setArea NOTIFY areaChanged) + + Q_PROPERTY( double length READ length WRITE setLength NOTIFY lengthChanged ) + Q_PROPERTY( double perimeter READ perimeter WRITE setPerimeter NOTIFY perimeterChanged ) + Q_PROPERTY( double area READ area WRITE setArea NOTIFY areaChanged ) + + Q_PROPERTY( bool canUndo READ canUndo WRITE setCanUndo NOTIFY canUndoChanged ) + Q_PROPERTY( bool canCloseShape READ canCloseShape WRITE setCanCloseShape NOTIFY canCloseShapeChanged ) + Q_PROPERTY( bool closeShapeDone READ closeShapeDone WRITE setCloseShapeDone NOTIFY closeShapeDoneChanged ) public: explicit MeasurementMapTool( QObject *parent = nullptr ); @@ -51,27 +56,39 @@ class MeasurementMapTool : public AbstractMapTool Q_INVOKABLE void closeShape(); Q_INVOKABLE void repeat(); + // Getter and Setters + double length() const; - void setLength(const double &length); + void setLength( const double &length ); double perimeter() const; - void setPerimeter(const double &perimeter); + void setPerimeter( const double &perimeter ); double area() const; - void setArea(const double &area); - + void setArea( const double &area ); const QgsGeometry &recordedGeometry() const; void setRecordedGeometry( const QgsGeometry &newRecordedGeometry ); QgsVectorLayer *activeLayer() const; void setActiveLayer( QgsVectorLayer *newActiveLayer ); - void fixZM( QgsPoint &point ) const; + + bool canUndo() const; + void setCanUndo( bool newCanUndo ); + + bool canCloseShape() const; + void setCanCloseShape( bool newCanCloseShape ); + + bool closeShapeDone() const; + void setCloseShapeDone( bool newCloseShapeDone ); signals: - void lengthChanged(const double &length); - void perimeterChanged(const double &perimeter); - void areaChanged(const double &area); + void lengthChanged( const double &length ); + void perimeterChanged( const double &perimeter ); + void areaChanged( const double &area ); + void canUndoChanged( bool canUndo ); + void canCloseShapeChanged( bool canUndo ); + void closeShapeDoneChanged( bool canUndo ); void activeLayerChanged( QgsVectorLayer *activeLayer ); void recordedGeometryChanged( const QgsGeometry &recordedGeometry ); @@ -94,6 +111,9 @@ class MeasurementMapTool : public AbstractMapTool double mLength = 0; double mPerimeter = 0; double mArea = 0; + bool mCanUndo = false; + bool mCanCloseShape = false; + bool mCloseShapeDone = false; }; #endif // MEASUREMENTMAPTOOL_H diff --git a/app/qml/gps/MMMeasureDrawer.qml b/app/qml/gps/MMMeasureDrawer.qml index c55a0f2d5..678aeca56 100644 --- a/app/qml/gps/MMMeasureDrawer.qml +++ b/app/qml/gps/MMMeasureDrawer.qml @@ -57,7 +57,7 @@ MMDrawer { leftButtonIcon: closeShapeDone ? __style.syncIcon : __style.undoIcon leftButtonType: MMButton.Types.Primary leftButtonEnabled: closeShapeDone || canUndo - onLeftButtonClicked: closeShapeDone ? root.mapCanvas.mapToolComponent.repeatMeasure() : root.mapCanvas.mapToolComponent.removePoint() + onLeftButtonClicked: closeShapeDone ? root.mapCanvas.mapToolComponent.repeatMeasure() : root.mapCanvas.mapToolComponent.mapTool.removePoint() drawerHeader.title: qsTr( "Measurement" ) diff --git a/app/qml/map/MMMeasurementTools.qml b/app/qml/map/MMMeasurementTools.qml index 736467189..f5a1943c5 100644 --- a/app/qml/map/MMMeasurementTools.qml +++ b/app/qml/map/MMMeasurementTools.qml @@ -133,7 +133,7 @@ Item { } function onScreenPositionChanged() { - mapTool.updateDistance( crosshair.recordPoint ); + //mapTool.updateDistance( crosshair.recordPoint ); } function closeShape() From 86ce8c96ffb63fd9f5d05122514e62c280d08c4d Mon Sep 17 00:00:00 2001 From: VitorVieiraZ Date: Wed, 28 Aug 2024 14:11:23 -0300 Subject: [PATCH 24/60] binding properties to cpp class --- app/maptools/measurementmaptool.cpp | 28 ++++++++++++++++++++++++++++ app/qml/map/MMMeasurementTools.qml | 2 +- 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/app/maptools/measurementmaptool.cpp b/app/maptools/measurementmaptool.cpp index 95d121be6..fbb9fec2a 100644 --- a/app/maptools/measurementmaptool.cpp +++ b/app/maptools/measurementmaptool.cpp @@ -126,39 +126,67 @@ void MeasurementMapTool::setRecordedGeometry( const QgsGeometry &newRecordedGeom void MeasurementMapTool::updateDistance( const QgsPoint &crosshairPoint ) { + qDebug() << "Entered updateDistance function"; + qDebug() << "Crosshair point:"; + if ( mPoints.isEmpty() ) + { + qDebug() << "mPoints is empty, setting length to 0.0"; setLength( 0.0 ); + return; + } + + qDebug() << "Number of points:" << mPoints.count(); if ( mPoints.count() >= 3 ) { QgsPoint firstPoint = mPoints.first(); + qDebug() << "First point:"; + QPointF firstPointScreen = mapSettings()->coordinateToScreen( firstPoint ); + qDebug() << "First point screen coordinates:" << firstPointScreen; + QPointF crosshairScreen = mapSettings()->coordinateToScreen( crosshairPoint ); + qDebug() << "Crosshair screen coordinates:" << crosshairScreen; double distanceToFirstPoint = std::hypot( crosshairScreen.x() - firstPointScreen.x(), crosshairScreen.y() - firstPointScreen.y() ); + qDebug() << "Distance to first point:" << distanceToFirstPoint; if ( distanceToFirstPoint <= CLOSE_THRESHOLD ) { + qDebug() << "Distance to first point is within threshold, setting canCloseShape to true"; setCanCloseShape( true ); } else { + qDebug() << "Distance to first point exceeds threshold, setting canCloseShape to false"; setCanCloseShape( false ); } } QgsPoint lastPoint = mPoints.last(); + qDebug() << "Last point:"; QgsDistanceArea mDistanceArea; + qDebug() << "Created QgsDistanceArea object"; + mDistanceArea.setEllipsoid( QStringLiteral( "WGS84" ) ); + qDebug() << "Ellipsoid set to WGS84"; + mDistanceArea.setSourceCrs( mActiveLayer->crs(), QgsCoordinateTransformContext() ); + qDebug() << "Source CRS set with active layer CRS"; + //mDistanceArea.setSourceCrs(mapSettings()->destinationCrs(), QgsCoordinateTransformContext() ); + //qDebug() << "Source CRS set with destination CRS"; double calculatedLength = mDistanceArea.measureLength( mRecordedGeometry ) + mDistanceArea.measureLine( crosshairPoint, lastPoint ); + qDebug() << "Calculated length:" << calculatedLength; setLength( calculatedLength ); + qDebug() << "Length set to calculated value"; } + void MeasurementMapTool::closeShape() { if ( mPoints.count() < 3 ) diff --git a/app/qml/map/MMMeasurementTools.qml b/app/qml/map/MMMeasurementTools.qml index f5a1943c5..736467189 100644 --- a/app/qml/map/MMMeasurementTools.qml +++ b/app/qml/map/MMMeasurementTools.qml @@ -133,7 +133,7 @@ Item { } function onScreenPositionChanged() { - //mapTool.updateDistance( crosshair.recordPoint ); + mapTool.updateDistance( crosshair.recordPoint ); } function closeShape() From 46ba8965342190e476231cede5c5179b421c8140 Mon Sep 17 00:00:00 2001 From: VitorVieiraZ Date: Fri, 30 Aug 2024 16:07:30 -0300 Subject: [PATCH 25/60] code organizing and new custom crosshair for measurement tool, highlighting measurement points --- app/maptools/measurementmaptool.cpp | 207 +++++------ app/maptools/measurementmaptool.h | 39 ++- app/qml/CMakeLists.txt | 1 + app/qml/dialogs/MMFinishMeasurementDialog.qml | 6 +- app/qml/gps/MMMeasureDrawer.qml | 28 +- app/qml/main.qml | 2 +- app/qml/map/MMMapController.qml | 2 +- app/qml/map/MMMeasurementTools.qml | 58 +-- app/qml/map/components/MMMeasureCrosshair.qml | 330 ++++++++++++++++++ 9 files changed, 469 insertions(+), 204 deletions(-) create mode 100644 app/qml/map/components/MMMeasureCrosshair.qml diff --git a/app/maptools/measurementmaptool.cpp b/app/maptools/measurementmaptool.cpp index fbb9fec2a..1c64e63a9 100644 --- a/app/maptools/measurementmaptool.cpp +++ b/app/maptools/measurementmaptool.cpp @@ -10,23 +10,19 @@ #include "measurementmaptool.h" MeasurementMapTool::MeasurementMapTool( QObject *parent ) - : AbstractMapTool{parent} + : AbstractMapTool{ parent } { - qDebug() << "MeasurementMapTool constructor called"; -} -MeasurementMapTool::~MeasurementMapTool() -{ - qDebug() << "MeasurementMapTool destructor called"; } +MeasurementMapTool::~MeasurementMapTool() = default; + void MeasurementMapTool::addPoint( const QgsPoint &point ) { mPoints.push_back( point ); rebuildGeometry(); } - void MeasurementMapTool::removePoint() { if ( !mPoints.isEmpty() ) @@ -40,20 +36,93 @@ void MeasurementMapTool::removePoint() } } +void MeasurementMapTool::updateDistance( const QgsPoint &crosshairPoint ) +{ + if ( mPoints.isEmpty() ) + { + setLength( 0.0 ); + return; + } + + if ( mPoints.count() >= 3 ) + { + QgsPoint firstPoint = mPoints.first(); + QPointF firstPointScreen = mapSettings()->coordinateToScreen( firstPoint ); + QPointF crosshairScreen = mapSettings()->coordinateToScreen( crosshairPoint ); + double distanceToFirstPoint = std::hypot( crosshairScreen.x() - firstPointScreen.x(), crosshairScreen.y() - firstPointScreen.y() ); + + setCanCloseShape( distanceToFirstPoint <= CLOSE_THRESHOLD ); + } + + QgsPoint lastPoint = mPoints.last(); + QgsDistanceArea mDistanceArea; + mDistanceArea.setEllipsoid( QStringLiteral( "WGS84" ) ); + mDistanceArea.setSourceCrs( mActiveLayer->crs(), QgsCoordinateTransformContext() ); + + double calculatedLength = mDistanceArea.measureLength( mRecordedGeometry ) + mDistanceArea.measureLine( crosshairPoint, lastPoint ); + setLength( calculatedLength ); +} + +void MeasurementMapTool::closeShape() +{ + if ( mPoints.count() < 3 ) + return; + + QList pointList; + for ( const QgsPoint &point : mPoints ) + { + pointList.append( QgsPointXY( point.x(), point.y() ) ); + } + + QgsGeometry polygonGeometry = QgsGeometry::fromPolygonXY( QList>() << pointList ); + setRecordedGeometry( polygonGeometry ); + + QgsDistanceArea mDistanceArea; + mDistanceArea.setEllipsoid( QStringLiteral( "WGS84" ) ); + mDistanceArea.setSourceCrs( mActiveLayer->crs(), QgsCoordinateTransformContext() ); + + setArea( mDistanceArea.measureArea( polygonGeometry ) ); + setPerimeter( mDistanceArea.measurePerimeter( polygonGeometry ) ); + setCanCloseShape( false ); + setCloseShapeDone( true ); +} + +void MeasurementMapTool::repeat() +{ + mPoints.clear(); + + setCanCloseShape( false ); + setCloseShapeDone( false ); + + rebuildGeometry(); +} + void MeasurementMapTool::rebuildGeometry() { QgsGeometry geometry; + QgsMultiPoint *existingVertices = new QgsMultiPoint(); + mExistingVertices.set( existingVertices ); + + if ( mPoints.count() > 0 ) { geometry = QgsGeometry::fromPolyline( mPoints ); + + for ( const QgsPoint &point : mPoints ) + { + existingVertices->addGeometry( point.clone() ); + } + setCanUndo( true ); } else + { setCanUndo( false ); + } + emit existingVerticesChanged( mExistingVertices ); setRecordedGeometry( geometry ); - } const QgsGeometry &MeasurementMapTool::recordedGeometry() const @@ -61,6 +130,20 @@ const QgsGeometry &MeasurementMapTool::recordedGeometry() const return mRecordedGeometry; } +QgsGeometry MeasurementMapTool::existingVertices() const +{ + return mExistingVertices; +} + +void MeasurementMapTool::setExistingVertices( const QgsGeometry &vertices ) +{ + if ( mExistingVertices.equals( vertices ) ) + return; + + mExistingVertices = vertices; + emit existingVerticesChanged( mExistingVertices ); +} + double MeasurementMapTool::area() const { return mArea; @@ -85,11 +168,11 @@ void MeasurementMapTool::setCanUndo( bool newCanUndo ) { if ( mCanUndo == newCanUndo ) return; + mCanUndo = newCanUndo; emit canUndoChanged( mCanUndo ); } - bool MeasurementMapTool::canCloseShape() const { return mCanCloseShape; @@ -99,6 +182,7 @@ void MeasurementMapTool::setCanCloseShape( bool newCanCloseShape ) { if ( mCanCloseShape == newCanCloseShape ) return; + mCanCloseShape = newCanCloseShape; emit canCloseShapeChanged( mCanCloseShape ); } @@ -112,6 +196,7 @@ void MeasurementMapTool::setCloseShapeDone( bool newCloseShapeDone ) { if ( mCloseShapeDone == newCloseShapeDone ) return; + mCloseShapeDone = newCloseShapeDone; emit closeShapeDoneChanged( mCloseShapeDone ); } @@ -120,111 +205,11 @@ void MeasurementMapTool::setRecordedGeometry( const QgsGeometry &newRecordedGeom { if ( mRecordedGeometry.equals( newRecordedGeometry ) ) return; + mRecordedGeometry = newRecordedGeometry; emit recordedGeometryChanged( mRecordedGeometry ); } -void MeasurementMapTool::updateDistance( const QgsPoint &crosshairPoint ) -{ - qDebug() << "Entered updateDistance function"; - qDebug() << "Crosshair point:"; - - if ( mPoints.isEmpty() ) - { - qDebug() << "mPoints is empty, setting length to 0.0"; - setLength( 0.0 ); - return; - } - - qDebug() << "Number of points:" << mPoints.count(); - - if ( mPoints.count() >= 3 ) - { - QgsPoint firstPoint = mPoints.first(); - qDebug() << "First point:"; - - QPointF firstPointScreen = mapSettings()->coordinateToScreen( firstPoint ); - qDebug() << "First point screen coordinates:" << firstPointScreen; - - QPointF crosshairScreen = mapSettings()->coordinateToScreen( crosshairPoint ); - qDebug() << "Crosshair screen coordinates:" << crosshairScreen; - - double distanceToFirstPoint = std::hypot( crosshairScreen.x() - firstPointScreen.x(), crosshairScreen.y() - firstPointScreen.y() ); - qDebug() << "Distance to first point:" << distanceToFirstPoint; - - if ( distanceToFirstPoint <= CLOSE_THRESHOLD ) - { - qDebug() << "Distance to first point is within threshold, setting canCloseShape to true"; - setCanCloseShape( true ); - } - else - { - qDebug() << "Distance to first point exceeds threshold, setting canCloseShape to false"; - setCanCloseShape( false ); - } - } - - QgsPoint lastPoint = mPoints.last(); - qDebug() << "Last point:"; - - QgsDistanceArea mDistanceArea; - qDebug() << "Created QgsDistanceArea object"; - - mDistanceArea.setEllipsoid( QStringLiteral( "WGS84" ) ); - qDebug() << "Ellipsoid set to WGS84"; - - mDistanceArea.setSourceCrs( mActiveLayer->crs(), QgsCoordinateTransformContext() ); - qDebug() << "Source CRS set with active layer CRS"; - - //mDistanceArea.setSourceCrs(mapSettings()->destinationCrs(), QgsCoordinateTransformContext() ); - //qDebug() << "Source CRS set with destination CRS"; - - double calculatedLength = mDistanceArea.measureLength( mRecordedGeometry ) + mDistanceArea.measureLine( crosshairPoint, lastPoint ); - qDebug() << "Calculated length:" << calculatedLength; - - setLength( calculatedLength ); - qDebug() << "Length set to calculated value"; -} - - -void MeasurementMapTool::closeShape() -{ - if ( mPoints.count() < 3 ) - return; - - QList pointList; - for ( const QgsPoint &point : mPoints ) - { - pointList.append( QgsPointXY( point.x(), point.y() ) ); - } - - QgsGeometry polygonGeometry = QgsGeometry::fromPolygonXY( QList>() << pointList ); - - setRecordedGeometry( polygonGeometry ); - - QgsDistanceArea mDistanceArea; - mDistanceArea.setEllipsoid( QStringLiteral( "WGS84" ) ); - mDistanceArea.setSourceCrs( mActiveLayer->crs(), QgsCoordinateTransformContext() ); - - double area = mDistanceArea.measureArea( polygonGeometry ); - double perimeter = mDistanceArea.measurePerimeter( polygonGeometry ); - - setArea( area ); - setPerimeter( perimeter ); - setCanCloseShape( false ); - setCloseShapeDone( true ); -} - -void MeasurementMapTool::repeat() -{ - mPoints.clear(); - - setCanCloseShape( false ); - setCloseShapeDone( false ); - - rebuildGeometry(); -} - void MeasurementMapTool::setActiveLayer( QgsVectorLayer *newActiveLayer ) { if ( mActiveLayer == newActiveLayer ) @@ -267,9 +252,7 @@ void MeasurementMapTool::setPerimeter( const double &perimeter ) emit perimeterChanged( perimeter ); } - QgsVectorLayer *MeasurementMapTool::activeLayer() const { return mActiveLayer; } - diff --git a/app/maptools/measurementmaptool.h b/app/maptools/measurementmaptool.h index 1e180c338..775c70b80 100644 --- a/app/maptools/measurementmaptool.h +++ b/app/maptools/measurementmaptool.h @@ -19,6 +19,9 @@ #include #include #include +#include "qgsvertexid.h" +#include "qgsvectorlayer.h" +#include "qgsmultipoint.h" const double CLOSE_THRESHOLD = 5.0; // in pixels @@ -28,6 +31,7 @@ class MeasurementMapTool : public AbstractMapTool Q_PROPERTY( QgsGeometry recordedGeometry READ recordedGeometry WRITE setRecordedGeometry NOTIFY recordedGeometryChanged ) Q_PROPERTY( QgsVectorLayer *activeLayer READ activeLayer WRITE setActiveLayer NOTIFY activeLayerChanged ) + Q_PROPERTY( QgsGeometry existingVertices READ existingVertices WRITE setExistingVertices NOTIFY existingVerticesChanged ) Q_PROPERTY( double length READ length WRITE setLength NOTIFY lengthChanged ) Q_PROPERTY( double perimeter READ perimeter WRITE setPerimeter NOTIFY perimeterChanged ) @@ -43,7 +47,7 @@ class MeasurementMapTool : public AbstractMapTool /** * Adds point to the end of the recorded geometry; updates recordedGeometry afterwards - * Passed point needs to be in active vector layer CRS + * Passed point needs to be in map CRS */ Q_INVOKABLE void addPoint( const QgsPoint &point ); @@ -53,11 +57,19 @@ class MeasurementMapTool : public AbstractMapTool */ Q_INVOKABLE void removePoint(); + /** + * If there are at least 3 points, forms a polygon from recorded points so far. + * Updates recorded geometry and calculates area and perimeter of formed polygon. + */ Q_INVOKABLE void closeShape(); + + /** + * Repeats measurement process. + * Clears all recorded points and rebuilds the geometry. + */ Q_INVOKABLE void repeat(); // Getter and Setters - double length() const; void setLength( const double &length ); @@ -67,12 +79,6 @@ class MeasurementMapTool : public AbstractMapTool double area() const; void setArea( const double &area ); - const QgsGeometry &recordedGeometry() const; - void setRecordedGeometry( const QgsGeometry &newRecordedGeometry ); - - QgsVectorLayer *activeLayer() const; - void setActiveLayer( QgsVectorLayer *newActiveLayer ); - bool canUndo() const; void setCanUndo( bool newCanUndo ); @@ -82,6 +88,15 @@ class MeasurementMapTool : public AbstractMapTool bool closeShapeDone() const; void setCloseShapeDone( bool newCloseShapeDone ); + const QgsGeometry &recordedGeometry() const; + void setRecordedGeometry( const QgsGeometry &newRecordedGeometry ); + + QgsGeometry existingVertices() const; + void setExistingVertices( const QgsGeometry &vertices ); + + QgsVectorLayer *activeLayer() const; + void setActiveLayer( QgsVectorLayer *newActiveLayer ); + signals: void lengthChanged( const double &length ); void perimeterChanged( const double &perimeter ); @@ -89,14 +104,9 @@ class MeasurementMapTool : public AbstractMapTool void canUndoChanged( bool canUndo ); void canCloseShapeChanged( bool canUndo ); void closeShapeDoneChanged( bool canUndo ); - void activeLayerChanged( QgsVectorLayer *activeLayer ); void recordedGeometryChanged( const QgsGeometry &recordedGeometry ); - - void canCloseShape( bool canClose ); - void canUndo( bool canUndo ); - - void shapeAreaAndPerimeter( double area, double perimeter ); + void existingVerticesChanged( const QgsGeometry &vertices ); protected: void rebuildGeometry(); @@ -107,6 +117,7 @@ class MeasurementMapTool : public AbstractMapTool private: QVector mPoints; QgsGeometry mRecordedGeometry; + QgsGeometry mExistingVertices; QgsVectorLayer *mActiveLayer = nullptr; double mLength = 0; double mPerimeter = 0; diff --git a/app/qml/CMakeLists.txt b/app/qml/CMakeLists.txt index b96f616de..c2c8264b8 100644 --- a/app/qml/CMakeLists.txt +++ b/app/qml/CMakeLists.txt @@ -140,6 +140,7 @@ set(MM_QML map/MMMeasurementTools.qml map/components/MMHidingBox.qml map/components/MMCrosshair.qml + map/components/MMMeasureCrosshair.qml map/components/MMMapHidingLabel.qml map/components/MMMapButton.qml map/components/MMMapLabel.qml diff --git a/app/qml/dialogs/MMFinishMeasurementDialog.qml b/app/qml/dialogs/MMFinishMeasurementDialog.qml index 96a68a424..9f5121ea3 100644 --- a/app/qml/dialogs/MMFinishMeasurementDialog.qml +++ b/app/qml/dialogs/MMFinishMeasurementDialog.qml @@ -23,13 +23,9 @@ MMDrawerDialog { secondaryButton.text: qsTr( "No" ) onPrimaryButtonClicked: { - console.log(" Measurement : Finish YES") root.finishMeasurementRequested() close() } - onSecondaryButtonClicked: { - console.log(" Measurement : Finish NO") - close() - } + onSecondaryButtonClicked: close() } diff --git a/app/qml/gps/MMMeasureDrawer.qml b/app/qml/gps/MMMeasureDrawer.qml index 678aeca56..3c0bf205f 100644 --- a/app/qml/gps/MMMeasureDrawer.qml +++ b/app/qml/gps/MMMeasureDrawer.qml @@ -34,16 +34,10 @@ MMDrawer { property string perimeter: __inputUtils.formatDistanceInProjectUnit( mapCanvas.mapToolComponent.mapTool.perimeter, 1 ) property string area: __inputUtils.formatAreaInProjectUnit( mapCanvas.mapToolComponent.mapTool.area, 1 ) - //signal addMeasurePoint() signal measureFinished() signal measureDone() - signal closeShape() - signal undo() - signal repeat() - Component.onCompleted: { - root.open() - } + Component.onCompleted: root.open() modal: false @@ -106,24 +100,4 @@ MMDrawer { } } } - - function endMeasurement() - { - if ( mapCanvas.state !== "measure" ) - return; - - measureFinished() - } - - function restore() - { - root.open() - } - - function repeatMeasure() - { - root.closeShapeDone = false - root.canCloseShape = false - root.repeat() - } } diff --git a/app/qml/main.qml b/app/qml/main.qml index 677acd71e..569c11de2 100644 --- a/app/qml/main.qml +++ b/app/qml/main.qml @@ -468,7 +468,7 @@ ApplicationWindow { mapSettings: map.mapSettings // disable the receivers button when staking out - showReceiversButton: !stakeoutPanelLoader.active || !measurePanelLoader.active + showReceiversButton: !stakeoutPanelLoader.active onManageReceiversClicked: { gpsDataDrawer.close() diff --git a/app/qml/map/MMMapController.qml b/app/qml/map/MMMapController.qml index 8ec9ac712..54d4103e7 100644 --- a/app/qml/map/MMMapController.qml +++ b/app/qml/map/MMMapController.qml @@ -596,7 +596,7 @@ Item { } visible: { - if ( root.mapExtentOffset > 0 && ( root.state !== "stakeout" || root.state !== "measure" ) ) return false + if ( root.mapExtentOffset > 0 && ( root.state !== "stakeout" ) ) return false if ( __positionKit.positionProvider && __positionKit.positionProvider.type() === "external" ) { // for external receivers we want to show gps panel and accuracy button diff --git a/app/qml/map/MMMeasurementTools.qml b/app/qml/map/MMMeasurementTools.qml index 736467189..2000add9f 100644 --- a/app/qml/map/MMMeasurementTools.qml +++ b/app/qml/map/MMMeasurementTools.qml @@ -35,14 +35,6 @@ Item { mapSettings: root.map.mapSettings activeLayer: __activeLayer.vectorLayer - - onCanCloseShape: function( canClose ) { console.log("A") }//measurePanel.canCloseShape = canClose; } - onCanUndo: function( canUndo ) { console.log("A") } //measurePanel.canUndo = canUndo; } - onShapeAreaAndPerimeter: function( area, perimeter ) { - console.log("A") - //measurePanel.area = __inputUtils.formatAreaInProjectUnit( area, 1 ) - //measurePanel.perimeter = __inputUtils.formatDistanceInProjectUnit( perimeter, 1 ) - } } MM.GuidelineController { @@ -82,49 +74,30 @@ Item { geometry: __inputUtils.transformGeometryToMapWithLayer( mapTool.recordedGeometry, __activeLayer.vectorLayer, root.map.mapSettings ) } - // MMMeasureDrawer { - // id: measurePanel + MMHighlight { + id: existingVerticesHighlight + + height: root.map.height + width: root.map.width - // width: window.width - // mapCanvas: root.map + mapSettings: root.map.mapSettings + geometry: __inputUtils.transformGeometryToMapWithLayer( mapTool.existingVertices, __activeLayer.vectorLayer, root.map.mapSettings ) - // //bind length and area to mapTool.length and mapTool.area / iconSource === or closeShape - // onAddMeasurePoint: mapTool.addPoint( crosshair.recordPoint ) - // onMeasureDone: finishMeasurementDialog.open() - // onMeasureFinished: root.finishMeasurement() - // onCloseShape: root.closeShape() - // onRepeat: root.repeatMeasure() - // onUndo: mapTool.removePoint() - // } + markerType: MMHighlight.MarkerTypes.Circle + markerSize: MMHighlight.MarkerSizes.Bigger + } - MMCrosshair { + MMMeasureCrosshair { id: crosshair anchors.fill: parent qgsProject: __activeProject.qgsProject mapSettings: root.map.mapSettings - } - - // MMMapLabel { - // id: mapLabel - - // text: qsTr( "0.0 m" ) - - // //implicitWidth: crosshair.width - // //implicitHeight: crosshair.crosshairForeground.height - 10 - // bgColor: __style.forestColor - // textColor: __style.polarColor - // textBgColorInverted: false - // onClicked: console.log( "MapLabel: ", crosshair.height ) - - // y: crosshair.crosshairForeground.y + crosshair.crosshairForeground.height - // anchors.horizontalCenter: crosshair.crosshairForeground.horizontalCenter - // } + text: __inputUtils.formatDistanceInProjectUnit( mapTool.length ) + canCloseShape: mapTool.canCloseShape - MMFinishMeasurementDialog { - id: finishMeasurementDialog - onFinishMeasurementRequested: root.finishMeasurement() + onCloseShapeClicked: closeShape() } function addPoint() @@ -140,7 +113,6 @@ Item { { guidelineController.allowed = false crosshair.visible = false - //measurePanel.closeShapeDone = true mapTool.closeShape() } @@ -148,8 +120,6 @@ Item { { guidelineController.allowed = true crosshair.visible = true - // measurePanel.closeShapeDone = false - // measurePanel.canCloseShape = false mapTool.repeat() } } diff --git a/app/qml/map/components/MMMeasureCrosshair.qml b/app/qml/map/components/MMMeasureCrosshair.qml new file mode 100644 index 000000000..6ce47dc51 --- /dev/null +++ b/app/qml/map/components/MMMeasureCrosshair.qml @@ -0,0 +1,330 @@ +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +import QtQuick +import Qt5Compat.GraphicalEffects + +import mm 1.0 as MM +import "../../components" + +Item { + id: root + + /*required*/ property var qgsProject + /*required*/ property var mapSettings + property bool shouldUseSnapping: false + + property point center: Qt.point( root.width / 2, root.height / 2 ) + + property var recordPoint: snapUtils.recordPoint + + property point screenPoint: snapUtils.snapped && __activeLayer.vectorLayer ? __inputUtils.transformPointToScreenCoordinates(__activeLayer.vectorLayer.crs, mapSettings, recordPoint) : center + + property real outerSize: 60 * __dp + property real innerDotSize: 10 * __dp + + implicitWidth: row.width + implicitHeight: __style.mapItemHeight + + signal closeShapeClicked + + property bool canCloseShape: false + required property string text + + property real maxWidth: implicitWidth + property url iconSource: "" + property color bgColor: __style.positiveColor + property color textColor: __style.forestColor + property bool textBgColorInverted: false + + MM.SnapUtils { + id: snapUtils + + centerPosition: root.center + mapSettings: root.mapSettings + qgsProject: root.qgsProject + useSnapping: root.shouldUseSnapping + destinationLayer: __activeLayer.vectorLayer + } + + Image { + id: crosshairBackground // white background of the crosshair + + x: root.screenPoint.x - width / 2 + y: root.screenPoint.y - height / 2 + + Behavior on x { + PropertyAnimation { + properties: "x" + duration: 50 + easing.type: Easing.InQuad + } + } + + Behavior on y { + PropertyAnimation { + properties: "y" + duration: 50 + easing.type: Easing.InQuad + } + } + + height: root.outerSize + width: height + + source: __style.crosshairBackgroundImage + sourceSize.width: width + sourceSize.height: height + } + + Image { + id: crosshairForeground // green / purple outer circle of the crosshair + + x: root.screenPoint.x - width / 2 + y: root.screenPoint.y - height / 2 + + Behavior on x { + PropertyAnimation { + properties: "x" + duration: 50 + easing.type: Easing.InQuad + } + } + + Behavior on y { + PropertyAnimation { + properties: "y" + duration: 50 + easing.type: Easing.InQuad + } + } + + height: root.outerSize + width: height + + source: __style.crosshairForegroundImage + sourceSize.width: width + sourceSize.height: height + } + + ColorOverlay { + anchors.fill: crosshairForeground + source: crosshairForeground + color: snapUtils.snapped ? __style.snappingColor : __style.forestColor + } + + Image { + id: crossCenterDot // Center dot - visible when not snapped (green) + + x: root.screenPoint.x - width / 2 + y: root.screenPoint.y - height / 2 + + Behavior on x { + PropertyAnimation { + properties: "x" + duration: 50 + easing.type: Easing.InQuad + } + } + + Behavior on y { + PropertyAnimation { + properties: "y" + duration: 50 + easing.type: Easing.InQuad + } + } + + opacity: snapUtils.snapped ? 0 : 100 + + Behavior on opacity { + PropertyAnimation { + properties: "opacity" + duration: 100 + easing.type: Easing.InQuad + } + } + + height: root.innerDotSize + width: height + sourceSize.width: width + sourceSize.height: height + + source: __style.crosshairCenterImage + } + + Image { + id: crossCenterPlus // Center plus - visible when not snapped (purple) + + x: root.screenPoint.x - width / 2 + y: root.screenPoint.y - height / 2 + + Behavior on x { + PropertyAnimation { + properties: "x" + duration: 50 + easing.type: Easing.InQuad + } + } + + Behavior on y { + PropertyAnimation { + properties: "y" + duration: 50 + easing.type: Easing.InQuad + } + } + + opacity: snapUtils.snapped && ( snapUtils.snapType === MM.SnapUtils.Vertex || snapUtils.snapType === MM.SnapUtils.Other ) ? 100 : 0 + + Behavior on opacity { + PropertyAnimation { + properties: "opacity" + duration: 100 + easing.type: Easing.InQuad + } + } + + rotation: snapUtils.snapType === MM.SnapUtils.Other ? 0 : 45 + + Behavior on rotation { + PropertyAnimation { + properties: "rotation" + duration: 50 + easing.type: Easing.InQuad + } + } + + height: root.innerDotSize * 2 + width: height + sourceSize.width: width + sourceSize.height: height + + // Important: must be same color as __style.snappingColor + source: __style.crosshairPlusImage + } + + Image { + id: crossCenterCircle // Center circle - visible when snapped to segment (purple) + + x: root.screenPoint.x - width / 2 + y: root.screenPoint.y - height / 2 + + Behavior on x { + PropertyAnimation { + properties: "x" + duration: 50 + easing.type: Easing.InQuad + } + } + + Behavior on y { + PropertyAnimation { + properties: "y" + duration: 50 + easing.type: Easing.InQuad + } + } + + opacity: snapUtils.snapped && snapUtils.snapType === MM.SnapUtils.Segment ? 100 : 0 + + Behavior on opacity { + PropertyAnimation { + properties: "opacity" + duration: 100 + easing.type: Easing.InQuad + } + } + + height: root.innerDotSize * 2 + width: height + sourceSize.width: width + sourceSize.height: height + + // Important: must be same color as __style.snappingColor + source: __style.crosshairCircleImage + } + + Rectangle { + width: Math.max( root.outerSize - 10 * __dp , row.width ) + height: root.outerSize * 0.6 + radius: root.height / 2 + color: textBg.color + + layer.enabled: true + layer.effect: MMShadow {} + + anchors.top: crosshairForeground.bottom + anchors.horizontalCenter: crosshairForeground.horizontalCenter + + Row { + id: row + + anchors.centerIn: parent + leftPadding: 8 * __dp + rightPadding: leftPadding + spacing: 4 * __dp + height: parent.height + + MMIcon { + id: icon + anchors.verticalCenter: parent.verticalCenter + source: root.canCloseShape ? __style.closeShapeIcon : "" + size: root.canCloseShape ? __style.icon24 : 0 + } + + Rectangle { + id: textBg + property real spacing: 5 * __dp + anchors.verticalCenter: parent.verticalCenter + color: root.canCloseShape ? __style.grassColor : __style.forestColor + height: text.height + spacing + width: text.width + 3 * spacing + radius: height / 2 + + Text { + id: text + + property real textSurroundingItemsWidth: textBg.spacing + icon.width + row.spacing + 2 * row.leftPadding + + width: ( implicitWidth + textSurroundingItemsWidth ) > root.maxWidth ? root.maxWidth - textSurroundingItemsWidth : implicitWidth + anchors.centerIn: parent + color: root.canCloseShape ? __style.forestColor: __style.polarColor + text: root.canCloseShape ? qsTr( "Close shape" ) : root.text + font: __style.t3 + elide: Text.ElideRight + } + } + } + + MouseArea { + anchors.fill: parent + onClicked: { + if ( root.canCloseShape ) + root.closeShapeClicked() + } + } + } + + Connections { + target: __activeProject + + function onProjectWillBeReloaded() { + snapUtils.clear() + } + + function onProjectReloaded( project ) { + // We need to re-assign qgs project to snaputils, because + // even though we loaded a different project, + // internally we keep the same pointer for QgsProject. + snapUtils.qgsProject = __activeProject.qgsProject + snapUtils.mapSettings = root.mapSettings + } + } +} From cc053f9622a80e6957430f6054ac424f01713be7 Mon Sep 17 00:00:00 2001 From: VitorVieiraZ Date: Wed, 4 Sep 2024 00:55:47 -0300 Subject: [PATCH 26/60] code cleanup plus enhancements --- app/inpututils.cpp | 66 +++++++++++--------------- app/map/inputmapsettings.cpp | 8 +--- app/maptools/measurementmaptool.cpp | 30 +++++++----- app/maptools/measurementmaptool.h | 9 ++-- app/qml/components/MMButton.qml | 12 +++-- app/qml/components/MMDrawerHeader.qml | 2 +- app/qml/gps/MMMeasureDrawer.qml | 6 +++ app/qml/main.qml | 2 +- app/qml/map/MMMapController.qml | 10 +--- app/qml/map/MMMeasurementTools.qml | 10 ++-- app/qml/map/components/MMCrosshair.qml | 3 +- 11 files changed, 71 insertions(+), 87 deletions(-) diff --git a/app/inpututils.cpp b/app/inpututils.cpp index eed98bc2e..f6b24d4dc 100644 --- a/app/inpututils.cpp +++ b/app/inpututils.cpp @@ -839,52 +839,40 @@ QgsPointXY InputUtils::transformPointXY( const QgsCoordinateReferenceSystem &src } QgsPoint InputUtils::transformPoint( const QgsCoordinateReferenceSystem &srcCrs, - const QgsCoordinateReferenceSystem &destCrs, - const QgsCoordinateTransformContext &context, - const QgsPoint &srcPoint ) + const QgsCoordinateReferenceSystem &destCrs, + const QgsCoordinateTransformContext &context, + const QgsPoint &srcPoint ) { + // we do not want to transform empty points, + // QGIS would convert them to a valid (0, 0) points + if ( srcPoint.isEmpty() ) + { + return QgsPoint(); + } - // we do not want to transform empty points, - // QGIS would convert them to a valid (0, 0) points - if ( srcPoint.isEmpty() ) - { - qDebug() << "Source point is empty, returning an empty QgsPoint."; - return QgsPoint(); - } - - try - { - qDebug() << "Creating QgsCoordinateTransform with srcCrs, destCrs, and context."; - QgsCoordinateTransform ct( srcCrs, destCrs, context ); - if ( ct.isValid() ) + try { - qDebug() << "CoordinateTransform is valid."; - if ( !ct.isShortCircuited() ) - { - qDebug() << "Transform is not short-circuited, transforming point."; - const QgsPointXY transformed = ct.transform( srcPoint.x(), srcPoint.y() ); - const QgsPoint pt( transformed.x(), transformed.y(), srcPoint.z(), srcPoint.m() ); - return pt; - } - else - { - qDebug() << "Transform is short-circuited, returning source point."; - return srcPoint; - } + QgsCoordinateTransform ct( srcCrs, destCrs, context ); + if ( ct.isValid() ) + { + if ( !ct.isShortCircuited() ) + { + const QgsPointXY transformed = ct.transform( srcPoint.x(), srcPoint.y() ); + const QgsPoint pt( transformed.x(), transformed.y(), srcPoint.z(), srcPoint.m() ); + return pt; + } + else + { + return srcPoint; + } + } } - else + catch ( QgsCsException &cse ) { - qDebug() << "CoordinateTransform is not valid."; + Q_UNUSED( cse ) } - } - catch ( QgsCsException &cse ) - { - qDebug() << "Caught QgsCsException during transformation:" << cse.what(); - Q_UNUSED( cse ) - } - qDebug() << "Returning an empty QgsPoint due to unsuccessful transformation."; - return QgsPoint(); + return QgsPoint(); } QPointF InputUtils::transformPointToScreenCoordinates( const QgsCoordinateReferenceSystem &srcCrs, InputMapSettings *mapSettings, const QgsPoint &srcPoint ) diff --git a/app/map/inputmapsettings.cpp b/app/map/inputmapsettings.cpp index 0f6654b7f..a529313e3 100644 --- a/app/map/inputmapsettings.cpp +++ b/app/map/inputmapsettings.cpp @@ -136,16 +136,10 @@ QgsRectangle InputMapSettings::visibleExtent() const QPointF InputMapSettings::coordinateToScreen( const QgsPoint &point ) const { QgsPointXY pt( point.x(), point.y() ); - QgsPointXY pp = mMapSettings.mapToPixel().transform( pt ); - pp.setX( pp.x() / devicePixelRatio() ); - pp.setY( pp.y() / devicePixelRatio() ); - - QPointF result = pp.toQPointF(); - - return result; + return pp.toQPointF(); } QgsPoint InputMapSettings::screenToCoordinate( const QPointF &point ) const diff --git a/app/maptools/measurementmaptool.cpp b/app/maptools/measurementmaptool.cpp index 1c64e63a9..d98bd8eef 100644 --- a/app/maptools/measurementmaptool.cpp +++ b/app/maptools/measurementmaptool.cpp @@ -17,9 +17,10 @@ MeasurementMapTool::MeasurementMapTool( QObject *parent ) MeasurementMapTool::~MeasurementMapTool() = default; -void MeasurementMapTool::addPoint( const QgsPoint &point ) +void MeasurementMapTool::addPoint( const QPointF &point ) { - mPoints.push_back( point ); + QgsPoint transformedPoint = mapSettings()->screenToCoordinate( point ); + mPoints.push_back( transformedPoint ); rebuildGeometry(); } @@ -36,7 +37,7 @@ void MeasurementMapTool::removePoint() } } -void MeasurementMapTool::updateDistance( const QgsPoint &crosshairPoint ) +void MeasurementMapTool::updateDistance( const QPointF &crosshairPoint ) { if ( mPoints.isEmpty() ) { @@ -48,18 +49,18 @@ void MeasurementMapTool::updateDistance( const QgsPoint &crosshairPoint ) { QgsPoint firstPoint = mPoints.first(); QPointF firstPointScreen = mapSettings()->coordinateToScreen( firstPoint ); - QPointF crosshairScreen = mapSettings()->coordinateToScreen( crosshairPoint ); - double distanceToFirstPoint = std::hypot( crosshairScreen.x() - firstPointScreen.x(), crosshairScreen.y() - firstPointScreen.y() ); - + double distanceToFirstPoint = std::hypot( crosshairPoint.x() - firstPointScreen.x(), crosshairPoint.y() - firstPointScreen.y() ); setCanCloseShape( distanceToFirstPoint <= CLOSE_THRESHOLD ); } QgsPoint lastPoint = mPoints.last(); + QgsPoint transformedCrosshairPoint = mapSettings()->screenToCoordinate( crosshairPoint ); + QgsDistanceArea mDistanceArea; mDistanceArea.setEllipsoid( QStringLiteral( "WGS84" ) ); - mDistanceArea.setSourceCrs( mActiveLayer->crs(), QgsCoordinateTransformContext() ); + mDistanceArea.setSourceCrs( mapSettings()->destinationCrs(), mapSettings()->transformContext() ); - double calculatedLength = mDistanceArea.measureLength( mRecordedGeometry ) + mDistanceArea.measureLine( crosshairPoint, lastPoint ); + double calculatedLength = mDistanceArea.measureLength( mRecordedGeometry ) + mDistanceArea.measureLine( transformedCrosshairPoint, lastPoint ); setLength( calculatedLength ); } @@ -70,19 +71,22 @@ void MeasurementMapTool::closeShape() QList pointList; for ( const QgsPoint &point : mPoints ) - { pointList.append( QgsPointXY( point.x(), point.y() ) ); - } QgsGeometry polygonGeometry = QgsGeometry::fromPolygonXY( QList>() << pointList ); setRecordedGeometry( polygonGeometry ); QgsDistanceArea mDistanceArea; mDistanceArea.setEllipsoid( QStringLiteral( "WGS84" ) ); - mDistanceArea.setSourceCrs( mActiveLayer->crs(), QgsCoordinateTransformContext() ); + mDistanceArea.setSourceCrs( mapSettings()->destinationCrs(), mapSettings()->transformContext() ); + + double area = mDistanceArea.measureArea( polygonGeometry ); + setArea( area ); + + double perimeter = mDistanceArea.measurePerimeter( polygonGeometry ); + setPerimeter( perimeter ); - setArea( mDistanceArea.measureArea( polygonGeometry ) ); - setPerimeter( mDistanceArea.measurePerimeter( polygonGeometry ) ); + setLength( 0.0 ); setCanCloseShape( false ); setCloseShapeDone( true ); } diff --git a/app/maptools/measurementmaptool.h b/app/maptools/measurementmaptool.h index 775c70b80..23f7e9469 100644 --- a/app/maptools/measurementmaptool.h +++ b/app/maptools/measurementmaptool.h @@ -10,20 +10,17 @@ #ifndef MEASUREMENTMAPTOOL_H #define MEASUREMENTMAPTOOL_H -#include "inputconfig.h" #include "abstractmaptool.h" #include #include "qgsdistancearea.h" #include "qgsgeometry.h" #include "inpututils.h" #include -#include #include -#include "qgsvertexid.h" #include "qgsvectorlayer.h" #include "qgsmultipoint.h" -const double CLOSE_THRESHOLD = 5.0; // in pixels +const double CLOSE_THRESHOLD = 10.0; // in pixels class MeasurementMapTool : public AbstractMapTool { @@ -49,7 +46,7 @@ class MeasurementMapTool : public AbstractMapTool * Adds point to the end of the recorded geometry; updates recordedGeometry afterwards * Passed point needs to be in map CRS */ - Q_INVOKABLE void addPoint( const QgsPoint &point ); + Q_INVOKABLE void addPoint( const QPointF &point ); /** * Removes last point from recorded geometry if there is at least one point @@ -112,7 +109,7 @@ class MeasurementMapTool : public AbstractMapTool void rebuildGeometry(); public slots: - void updateDistance( const QgsPoint &crosshairPoint ); + void updateDistance( const QPointF &crosshairPoint ); private: QVector mPoints; diff --git a/app/qml/components/MMButton.qml b/app/qml/components/MMButton.qml index 631a26b3e..a2f98db87 100644 --- a/app/qml/components/MMButton.qml +++ b/app/qml/components/MMButton.qml @@ -15,8 +15,10 @@ Button { id: root enum Types { Primary, Secondary, Tertiary } + enum Sizes { Small, Regular } property int type: MMButton.Types.Primary + property int size: MMButton.Sizes.Regular property color fontColor: { if ( type === MMButton.Types.Primary ) return __style.forestColor @@ -161,10 +163,10 @@ Button { state: "default" implicitHeight: root.type === MMButton.Types.Tertiary ? buttonContent.height : buttonContent.height + topPadding + bottomPadding - implicitWidth: row.paintedChildrenWidth + 2 * __style.margin20 + implicitWidth: row.paintedChildrenWidth + 2 * ( root.size === MMButton.Sizes.Small ? __style.margin16 : __style.margin20 ) - topPadding: root.type === MMButton.Types.Tertiary ? 0 : 11 * __dp - bottomPadding: root.type === MMButton.Types.Tertiary ? 0 : 11 * __dp + topPadding: ( root.type === MMButton.Types.Tertiary ) ? 0 : 11 * __dp + bottomPadding: ( root.type === MMButton.Types.Tertiary ) ? 0 : 11 * __dp rightPadding: 0 leftPadding: 0 @@ -177,14 +179,14 @@ Button { id: row property real paintedChildrenWidth: buttonIconLeft.paintedWidth + buttonContent.implicitWidth + buttonIconRight.paintedWidth + spacing - property real maxWidth: parent.width - 2 * __style.margin20 + property real maxWidth: parent.width - 2 * ( root.size === MMButton.Sizes.Small ? __style.margin16 : __style.margin20 ) x: ( parent.width - width ) / 2 width: Math.min( paintedChildrenWidth, maxWidth ) height: Math.max( buttonContent.paintedHeight, buttonIconRight.height ) - spacing: buttonIconRight.visible || buttonIconLeft.visible ? __style.spacing12 : 0 + spacing: ( root.size === MMButton.Sizes.Small ) ? 2 : ( buttonIconRight.visible || buttonIconLeft.visible ? __style.spacing12 : 0 ) MMIcon { id: buttonIconLeft diff --git a/app/qml/components/MMDrawerHeader.qml b/app/qml/components/MMDrawerHeader.qml index 2d0042c4c..f4b391a54 100644 --- a/app/qml/components/MMDrawerHeader.qml +++ b/app/qml/components/MMDrawerHeader.qml @@ -46,7 +46,7 @@ Rectangle { text: root.leftButtonText iconSourceLeft: root.leftButtonIcon bgndColor: __style.lightGreenColor - + size: MMButton.Sizes.Small visible: root.leftButtonIcon enabled: root.leftButtonEnabled diff --git a/app/qml/gps/MMMeasureDrawer.qml b/app/qml/gps/MMMeasureDrawer.qml index 3c0bf205f..62111d228 100644 --- a/app/qml/gps/MMMeasureDrawer.qml +++ b/app/qml/gps/MMMeasureDrawer.qml @@ -41,6 +41,8 @@ MMDrawer { modal: false + //not interactive + interactive: false closePolicy: Popup.CloseOnEscape dropShadow: true @@ -53,6 +55,10 @@ MMDrawer { leftButtonEnabled: closeShapeDone || canUndo onLeftButtonClicked: closeShapeDone ? root.mapCanvas.mapToolComponent.repeatMeasure() : root.mapCanvas.mapToolComponent.mapTool.removePoint() + Behavior on implicitHeight { + PropertyAnimation { properties: "implicitHeight"; easing.type: Easing.InOutQuad } + } + drawerHeader.title: qsTr( "Measurement" ) drawerContent: Column { diff --git a/app/qml/main.qml b/app/qml/main.qml index 569c11de2..b5963e6f0 100644 --- a/app/qml/main.qml +++ b/app/qml/main.qml @@ -468,7 +468,7 @@ ApplicationWindow { mapSettings: map.mapSettings // disable the receivers button when staking out - showReceiversButton: !stakeoutPanelLoader.active + showReceiversButton: !stakeoutPanelLoader.active //Here onManageReceiversClicked: { gpsDataDrawer.close() diff --git a/app/qml/map/MMMapController.qml b/app/qml/map/MMMapController.qml index 54d4103e7..eb304242e 100644 --- a/app/qml/map/MMMapController.qml +++ b/app/qml/map/MMMapController.qml @@ -596,7 +596,7 @@ Item { } visible: { - if ( root.mapExtentOffset > 0 && ( root.state !== "stakeout" ) ) return false + if ( root.mapExtentOffset > 0 && (root.state === "stakeout") ) return false if ( __positionKit.positionProvider && __positionKit.positionProvider.type() === "external" ) { // for external receivers we want to show gps panel and accuracy button @@ -913,10 +913,7 @@ Item { mapSettings: mapCanvas.mapSettings positionKit: __positionKit - onScreenPositionChanged: { - //console.log("AA") - root.updatePosition() - } + onScreenPositionChanged: root.updatePosition() } MM.PositionDirection { @@ -1155,9 +1152,6 @@ Item { function measure() { internal.extentBeforeStakeout = mapCanvas.mapSettings.extent state = "measure" - console.log(" MAP TOOL: ", root.mapTool) - root.mapToolComponent = measurementToolsLoader.item - console.log(" MAP TOOL: ", root.mapTool) } function toggleStreaming() { diff --git a/app/qml/map/MMMeasurementTools.qml b/app/qml/map/MMMeasurementTools.qml index 2000add9f..b62cdb908 100644 --- a/app/qml/map/MMMeasurementTools.qml +++ b/app/qml/map/MMMeasurementTools.qml @@ -42,7 +42,7 @@ Item { mapSettings: root.map.mapSettings crosshairPosition: crosshair.screenPoint - realGeometry: __inputUtils.transformGeometryToMapWithLayer( mapTool.recordedGeometry, __activeLayer.vectorLayer, root.map.mapSettings ) + realGeometry: mapTool.recordedGeometry } MMHighlight { @@ -71,7 +71,7 @@ Item { lineWidth: MMHighlight.LineWidths.Narrow mapSettings: root.map.mapSettings - geometry: __inputUtils.transformGeometryToMapWithLayer( mapTool.recordedGeometry, __activeLayer.vectorLayer, root.map.mapSettings ) + geometry: mapTool.recordedGeometry } MMHighlight { @@ -81,7 +81,7 @@ Item { width: root.map.width mapSettings: root.map.mapSettings - geometry: __inputUtils.transformGeometryToMapWithLayer( mapTool.existingVertices, __activeLayer.vectorLayer, root.map.mapSettings ) + geometry: mapTool.existingVertices markerType: MMHighlight.MarkerTypes.Circle markerSize: MMHighlight.MarkerSizes.Bigger @@ -102,11 +102,11 @@ Item { function addPoint() { - mapTool.addPoint( crosshair.recordPoint ) + mapTool.addPoint( crosshair.screenPoint ) } function onScreenPositionChanged() { - mapTool.updateDistance( crosshair.recordPoint ); + mapTool.updateDistance( crosshair.screenPoint ); } function closeShape() diff --git a/app/qml/map/components/MMCrosshair.qml b/app/qml/map/components/MMCrosshair.qml index 326b00868..a9c7ec465 100644 --- a/app/qml/map/components/MMCrosshair.qml +++ b/app/qml/map/components/MMCrosshair.qml @@ -28,8 +28,6 @@ Item { property real outerSize: 60 * __dp property real innerDotSize: 10 * __dp - property alias crosshairForeground: crosshairForeground - MM.SnapUtils { id: snapUtils @@ -38,6 +36,7 @@ Item { qgsProject: root.qgsProject useSnapping: root.shouldUseSnapping destinationLayer: __activeLayer.vectorLayer + } Image { From 977d7bec5bc2ab5437a5fbb50ae9729b3a6e4cce Mon Sep 17 00:00:00 2001 From: VitorVieiraZ Date: Wed, 4 Sep 2024 00:56:52 -0300 Subject: [PATCH 27/60] format cpp code --- app/inpututils.cpp | 58 +++++++++++++++++++++++----------------------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/app/inpututils.cpp b/app/inpututils.cpp index f6b24d4dc..9904308f4 100644 --- a/app/inpututils.cpp +++ b/app/inpututils.cpp @@ -839,40 +839,40 @@ QgsPointXY InputUtils::transformPointXY( const QgsCoordinateReferenceSystem &src } QgsPoint InputUtils::transformPoint( const QgsCoordinateReferenceSystem &srcCrs, - const QgsCoordinateReferenceSystem &destCrs, - const QgsCoordinateTransformContext &context, - const QgsPoint &srcPoint ) + const QgsCoordinateReferenceSystem &destCrs, + const QgsCoordinateTransformContext &context, + const QgsPoint &srcPoint ) { - // we do not want to transform empty points, - // QGIS would convert them to a valid (0, 0) points - if ( srcPoint.isEmpty() ) - { - return QgsPoint(); - } + // we do not want to transform empty points, + // QGIS would convert them to a valid (0, 0) points + if ( srcPoint.isEmpty() ) + { + return QgsPoint(); + } - try - { - QgsCoordinateTransform ct( srcCrs, destCrs, context ); - if ( ct.isValid() ) - { - if ( !ct.isShortCircuited() ) - { - const QgsPointXY transformed = ct.transform( srcPoint.x(), srcPoint.y() ); - const QgsPoint pt( transformed.x(), transformed.y(), srcPoint.z(), srcPoint.m() ); - return pt; - } - else - { - return srcPoint; - } - } - } - catch ( QgsCsException &cse ) + try + { + QgsCoordinateTransform ct( srcCrs, destCrs, context ); + if ( ct.isValid() ) { - Q_UNUSED( cse ) + if ( !ct.isShortCircuited() ) + { + const QgsPointXY transformed = ct.transform( srcPoint.x(), srcPoint.y() ); + const QgsPoint pt( transformed.x(), transformed.y(), srcPoint.z(), srcPoint.m() ); + return pt; + } + else + { + return srcPoint; + } } + } + catch ( QgsCsException &cse ) + { + Q_UNUSED( cse ) + } - return QgsPoint(); + return QgsPoint(); } QPointF InputUtils::transformPointToScreenCoordinates( const QgsCoordinateReferenceSystem &srcCrs, InputMapSettings *mapSettings, const QgsPoint &srcPoint ) From 497ef135af7d59212c0d98e225e3ea943fe20f59 Mon Sep 17 00:00:00 2001 From: VitorVieiraZ Date: Wed, 4 Sep 2024 18:49:30 -0300 Subject: [PATCH 28/60] last adjustments --- app/qml/components/MMDrawer.qml | 12 ----------- app/qml/components/MMDrawerHeader.qml | 29 +++++---------------------- app/qml/gps/MMMeasureDrawer.qml | 27 ++++++++++++++++--------- 3 files changed, 23 insertions(+), 45 deletions(-) diff --git a/app/qml/components/MMDrawer.qml b/app/qml/components/MMDrawer.qml index 3b0b0e762..4badaa59f 100644 --- a/app/qml/components/MMDrawer.qml +++ b/app/qml/components/MMDrawer.qml @@ -28,12 +28,6 @@ Drawer { readonly property real drawerReservedVerticalSpace: topSpacer.height + mmDrawerHeader.height + contentSpacer.height + bottomSpacer.height readonly property real drawerContentAvailableHeight: maxHeight - drawerReservedVerticalSpace // max height for your custom content item - property string leftButtonIcon: "" - property string leftButtonText: "" - property string leftButtonType: MMButton.Types.Primary - property bool leftButtonEnabled: true - signal leftButtonClicked - implicitHeight: contentHeight > maxHeight ? maxHeight : contentHeight implicitWidth: ApplicationWindow.window?.width ?? 0 @@ -80,12 +74,6 @@ Drawer { width: parent.width - leftButtonIcon: root.leftButtonIcon - leftButtonText: root.leftButtonText - leftButtonType: root.leftButtonType - leftButtonEnabled: root.leftButtonEnabled - onLeftButtonClicked: root.leftButtonClicked() - onCloseClicked: { root.close() } diff --git a/app/qml/components/MMDrawerHeader.qml b/app/qml/components/MMDrawerHeader.qml index f4b391a54..e5a821536 100644 --- a/app/qml/components/MMDrawerHeader.qml +++ b/app/qml/components/MMDrawerHeader.qml @@ -23,13 +23,8 @@ Rectangle { property bool hasCloseButton: true - property string leftButtonIcon: "" - property string leftButtonText: "" - property string leftButtonType: MMButton.Types.Primary - property bool leftButtonEnabled: true - property alias closeButton: closeBtn - property alias leftButton: leftBtn + property alias topLeftItemContent: topLeftButtonGroup.children color: __style.transparentColor @@ -39,25 +34,11 @@ Rectangle { implicitHeight: 60 * __dp implicitWidth: ApplicationWindow.window?.width ?? 0 - MMButton { - id: leftBtn - - type: root.leftButtonType - text: root.leftButtonText - iconSourceLeft: root.leftButtonIcon - bgndColor: __style.lightGreenColor - size: MMButton.Sizes.Small - visible: root.leftButtonIcon - - enabled: root.leftButtonEnabled - - anchors { - left: parent.left - leftMargin: __style.pageMargins + __style.safeAreaLeft - verticalCenter: parent.verticalCenter - } + Item { + id: topLeftButtonGroup - onClicked: root.leftButtonClicked() + width: childrenRect.width + height: parent.height } Text { diff --git a/app/qml/gps/MMMeasureDrawer.qml b/app/qml/gps/MMMeasureDrawer.qml index 62111d228..8f9f05052 100644 --- a/app/qml/gps/MMMeasureDrawer.qml +++ b/app/qml/gps/MMMeasureDrawer.qml @@ -40,8 +40,6 @@ MMDrawer { Component.onCompleted: root.open() modal: false - - //not interactive interactive: false closePolicy: Popup.CloseOnEscape @@ -49,23 +47,34 @@ MMDrawer { onClosed: root.measureFinished() - leftButtonText: closeShapeDone ? qsTr( "Repeat" ) : qsTr( "Undo" ) - leftButtonIcon: closeShapeDone ? __style.syncIcon : __style.undoIcon - leftButtonType: MMButton.Types.Primary - leftButtonEnabled: closeShapeDone || canUndo - onLeftButtonClicked: closeShapeDone ? root.mapCanvas.mapToolComponent.repeatMeasure() : root.mapCanvas.mapToolComponent.mapTool.removePoint() - Behavior on implicitHeight { PropertyAnimation { properties: "implicitHeight"; easing.type: Easing.InOutQuad } } drawerHeader.title: qsTr( "Measurement" ) + drawerHeader.topLeftItemContent: MMButton { + type: MMButton.Types.Primary + text: closeShapeDone ? qsTr( "Repeat" ) : qsTr( "Undo" ) + iconSourceLeft: closeShapeDone ? __style.syncIcon : __style.undoIcon + bgndColor: __style.lightGreenColor + size: MMButton.Sizes.Small + enabled: closeShapeDone || canUndo + + anchors { + left: parent.left + leftMargin: __style.pageMargins + __style.safeAreaLeft + verticalCenter: parent.verticalCenter + } + + onClicked: closeShapeDone ? root.mapCanvas.mapToolComponent.repeatMeasure() : root.mapCanvas.mapToolComponent.mapTool.removePoint() + } + drawerContent: Column { id: mainColumn width: parent.width - spacing: __style.margin40 + spacing: __style.margin10 Row { width: parent.width From f844efb78cdc862711230fe6d4fb57f948baf41b Mon Sep 17 00:00:00 2001 From: VitorVieiraZ Date: Wed, 4 Sep 2024 19:04:28 -0300 Subject: [PATCH 29/60] refinements in code --- app/qml/components/MMDrawerHeader.qml | 1 - app/qml/main.qml | 2 +- app/qml/map/components/MMMeasureCrosshair.qml | 6 ------ 3 files changed, 1 insertion(+), 8 deletions(-) diff --git a/app/qml/components/MMDrawerHeader.qml b/app/qml/components/MMDrawerHeader.qml index e5a821536..7750feb8a 100644 --- a/app/qml/components/MMDrawerHeader.qml +++ b/app/qml/components/MMDrawerHeader.qml @@ -29,7 +29,6 @@ Rectangle { color: __style.transparentColor signal closeClicked - signal leftButtonClicked implicitHeight: 60 * __dp implicitWidth: ApplicationWindow.window?.width ?? 0 diff --git a/app/qml/main.qml b/app/qml/main.qml index b5963e6f0..569c11de2 100644 --- a/app/qml/main.qml +++ b/app/qml/main.qml @@ -468,7 +468,7 @@ ApplicationWindow { mapSettings: map.mapSettings // disable the receivers button when staking out - showReceiversButton: !stakeoutPanelLoader.active //Here + showReceiversButton: !stakeoutPanelLoader.active onManageReceiversClicked: { gpsDataDrawer.close() diff --git a/app/qml/map/components/MMMeasureCrosshair.qml b/app/qml/map/components/MMMeasureCrosshair.qml index 6ce47dc51..aa71fd60b 100644 --- a/app/qml/map/components/MMMeasureCrosshair.qml +++ b/app/qml/map/components/MMMeasureCrosshair.qml @@ -37,12 +37,6 @@ Item { property bool canCloseShape: false required property string text - property real maxWidth: implicitWidth - property url iconSource: "" - property color bgColor: __style.positiveColor - property color textColor: __style.forestColor - property bool textBgColorInverted: false - MM.SnapUtils { id: snapUtils From f0820cfd98616f99f55f4d9d593fdcbc86675c48 Mon Sep 17 00:00:00 2001 From: VitorVieiraZ Date: Wed, 4 Sep 2024 22:17:22 -0300 Subject: [PATCH 30/60] fix linux build --- app/maptools/measurementmaptool.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/maptools/measurementmaptool.h b/app/maptools/measurementmaptool.h index 23f7e9469..036edcf86 100644 --- a/app/maptools/measurementmaptool.h +++ b/app/maptools/measurementmaptool.h @@ -15,8 +15,8 @@ #include "qgsdistancearea.h" #include "qgsgeometry.h" #include "inpututils.h" -#include -#include +#include "qgspolygon.h" +#include "qgsgeometry.h" #include "qgsvectorlayer.h" #include "qgsmultipoint.h" From f68ed79adfc4cf3e7cbfbb4042b9184714fa0627 Mon Sep 17 00:00:00 2001 From: VitorVieiraZ Date: Thu, 5 Sep 2024 23:34:19 -0300 Subject: [PATCH 31/60] showInfoTextMessage supports more than 1 line --- app/qml/map/MMMapController.qml | 1 + app/qml/map/components/MMMapHidingLabel.qml | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/app/qml/map/MMMapController.qml b/app/qml/map/MMMapController.qml index eb304242e..11a8d7d62 100644 --- a/app/qml/map/MMMapController.qml +++ b/app/qml/map/MMMapController.qml @@ -153,6 +153,7 @@ Item { } case "measure": { + root.showInfoTextMessage( qsTr( "Add points to measure distance, close the shape to measure area" ) ) root.hideHighlight() root.measureStarted() break diff --git a/app/qml/map/components/MMMapHidingLabel.qml b/app/qml/map/components/MMMapHidingLabel.qml index 7a0ab3720..63941982d 100644 --- a/app/qml/map/components/MMMapHidingLabel.qml +++ b/app/qml/map/components/MMMapHidingLabel.qml @@ -24,12 +24,14 @@ MMHidingBox { root.visible = false } - height: __style.row40 + height: text.lineCount * __style.row40 timerInterval: 10000 fadeOutDuration: 1000 // Text Text { + id: text + height: parent.height width: parent.width - 2 * __style.pageMargins anchors.verticalCenter: parent.verticalCenter @@ -40,6 +42,8 @@ MMHidingBox { font: __style.t3 horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter + maximumLineCount: 3 + wrapMode: Text.WordWrap elide: Text.ElideRight } } From 669e434986bf3a9757a4b411dca38999b94e14ba Mon Sep 17 00:00:00 2001 From: VitorVieiraZ Date: Tue, 10 Sep 2024 20:06:07 -0300 Subject: [PATCH 32/60] fixing qml warnings --- app/qml/gps/MMMeasureDrawer.qml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/app/qml/gps/MMMeasureDrawer.qml b/app/qml/gps/MMMeasureDrawer.qml index 8f9f05052..2b4579649 100644 --- a/app/qml/gps/MMMeasureDrawer.qml +++ b/app/qml/gps/MMMeasureDrawer.qml @@ -26,13 +26,13 @@ MMDrawer { readonly property alias panelHeight: root.height - property bool canCloseShape: mapCanvas.mapToolComponent.mapTool.canCloseShape - property bool closeShapeDone: mapCanvas.mapToolComponent.mapTool.closeShapeDone - property bool canUndo: mapCanvas.mapToolComponent.mapTool.canUndo + property bool canCloseShape: mapCanvas.mapToolComponent?.mapTool?.canCloseShape ?? false + property bool closeShapeDone: mapCanvas.mapToolComponent?.mapTool?.closeShapeDone ?? false + property bool canUndo: mapCanvas.mapToolComponent?.mapTool?.canUndo ?? false - property string length: __inputUtils.formatDistanceInProjectUnit( mapCanvas.mapToolComponent.mapTool.length, 1 ) - property string perimeter: __inputUtils.formatDistanceInProjectUnit( mapCanvas.mapToolComponent.mapTool.perimeter, 1 ) - property string area: __inputUtils.formatAreaInProjectUnit( mapCanvas.mapToolComponent.mapTool.area, 1 ) + property string length: __inputUtils.formatDistanceInProjectUnit( mapCanvas.mapToolComponent?.mapTool?.length ?? 0, 1 ) + property string perimeter: __inputUtils.formatDistanceInProjectUnit( mapCanvas.mapToolComponent?.mapTool?.perimeter ?? 0, 1 ) + property string area: __inputUtils.formatAreaInProjectUnit( mapCanvas.mapToolComponent?.mapTool?.area ?? 0, 1 ) signal measureFinished() signal measureDone() From 82a75c49ccf8cc5dd0a580679ab81a8145ad0557 Mon Sep 17 00:00:00 2001 From: VitorVieiraZ Date: Wed, 11 Sep 2024 19:21:43 -0300 Subject: [PATCH 33/60] post review adjustments --- app/maptools/measurementmaptool.cpp | 79 +++---- app/maptools/measurementmaptool.h | 20 +- app/qml/gps/MMMeasureDrawer.qml | 3 +- app/qml/map/MMMeasurementTools.qml | 5 +- app/qml/map/components/MMCrosshair.qml | 2 + app/qml/map/components/MMMeasureCrosshair.qml | 214 +----------------- 6 files changed, 60 insertions(+), 263 deletions(-) diff --git a/app/maptools/measurementmaptool.cpp b/app/maptools/measurementmaptool.cpp index d98bd8eef..57f22376a 100644 --- a/app/maptools/measurementmaptool.cpp +++ b/app/maptools/measurementmaptool.cpp @@ -12,7 +12,13 @@ MeasurementMapTool::MeasurementMapTool( QObject *parent ) : AbstractMapTool{ parent } { + if ( !mapSettings() ) + { + return; + } + mDistanceArea.setEllipsoid( QStringLiteral( "WGS84" ) ); + mDistanceArea.setSourceCrs( mapSettings()->destinationCrs(), mapSettings()->transformContext() ); } MeasurementMapTool::~MeasurementMapTool() = default; @@ -41,7 +47,24 @@ void MeasurementMapTool::updateDistance( const QPointF &crosshairPoint ) { if ( mPoints.isEmpty() ) { - setLength( 0.0 ); + setLengthWithGuideline( 0.0 ); + return; + } + + checkCanCloseShape( crosshairPoint ) ; + + QgsPoint lastPoint = mPoints.last(); + QgsPoint transformedCrosshairPoint = mapSettings()->screenToCoordinate( crosshairPoint ); + + double calculatedLength = mDistanceArea.measureLength( mRecordedGeometry ) + mDistanceArea.measureLine( transformedCrosshairPoint, lastPoint ); + setLengthWithGuideline( calculatedLength ); +} + +void MeasurementMapTool::checkCanCloseShape( const QPointF &crosshairPoint ) +{ + if ( mRecordedGeometry.isEmpty() || mPoints.count() < 3 ) + { + setCanCloseShape( false ); return; } @@ -52,16 +75,6 @@ void MeasurementMapTool::updateDistance( const QPointF &crosshairPoint ) double distanceToFirstPoint = std::hypot( crosshairPoint.x() - firstPointScreen.x(), crosshairPoint.y() - firstPointScreen.y() ); setCanCloseShape( distanceToFirstPoint <= CLOSE_THRESHOLD ); } - - QgsPoint lastPoint = mPoints.last(); - QgsPoint transformedCrosshairPoint = mapSettings()->screenToCoordinate( crosshairPoint ); - - QgsDistanceArea mDistanceArea; - mDistanceArea.setEllipsoid( QStringLiteral( "WGS84" ) ); - mDistanceArea.setSourceCrs( mapSettings()->destinationCrs(), mapSettings()->transformContext() ); - - double calculatedLength = mDistanceArea.measureLength( mRecordedGeometry ) + mDistanceArea.measureLine( transformedCrosshairPoint, lastPoint ); - setLength( calculatedLength ); } void MeasurementMapTool::closeShape() @@ -76,25 +89,22 @@ void MeasurementMapTool::closeShape() QgsGeometry polygonGeometry = QgsGeometry::fromPolygonXY( QList>() << pointList ); setRecordedGeometry( polygonGeometry ); - QgsDistanceArea mDistanceArea; - mDistanceArea.setEllipsoid( QStringLiteral( "WGS84" ) ); - mDistanceArea.setSourceCrs( mapSettings()->destinationCrs(), mapSettings()->transformContext() ); - double area = mDistanceArea.measureArea( polygonGeometry ); setArea( area ); double perimeter = mDistanceArea.measurePerimeter( polygonGeometry ); setPerimeter( perimeter ); - setLength( 0.0 ); setCanCloseShape( false ); setCloseShapeDone( true ); } -void MeasurementMapTool::repeat() +void MeasurementMapTool::reset() { mPoints.clear(); + setPerimeter( 0.0 ); + setLengthWithGuideline( 0.0 ); setCanCloseShape( false ); setCloseShapeDone( false ); @@ -108,7 +118,6 @@ void MeasurementMapTool::rebuildGeometry() QgsMultiPoint *existingVertices = new QgsMultiPoint(); mExistingVertices.set( existingVertices ); - if ( mPoints.count() > 0 ) { geometry = QgsGeometry::fromPolyline( mPoints ); @@ -118,6 +127,8 @@ void MeasurementMapTool::rebuildGeometry() existingVertices->addGeometry( point.clone() ); } + double perimeter = mDistanceArea.measureLength( geometry ); + setPerimeter( perimeter ); setCanUndo( true ); } else @@ -158,9 +169,9 @@ double MeasurementMapTool::perimeter() const return mPerimeter; } -double MeasurementMapTool::length() const +double MeasurementMapTool::lengthWithGuideline() const { - return mLength; + return mLengthWithGuideline; } bool MeasurementMapTool::canUndo() const @@ -214,28 +225,13 @@ void MeasurementMapTool::setRecordedGeometry( const QgsGeometry &newRecordedGeom emit recordedGeometryChanged( mRecordedGeometry ); } -void MeasurementMapTool::setActiveLayer( QgsVectorLayer *newActiveLayer ) -{ - if ( mActiveLayer == newActiveLayer ) - return; - - if ( mActiveLayer && mActiveLayer->isEditable() ) - { - mActiveLayer->rollBack(); - mActiveLayer->triggerRepaint(); - } - - mActiveLayer = newActiveLayer; - emit activeLayerChanged( mActiveLayer ); -} - -void MeasurementMapTool::setLength( const double &length ) +void MeasurementMapTool::setLengthWithGuideline( const double &lengthWithGuideline ) { - if ( mLength == length ) + if ( mLengthWithGuideline == lengthWithGuideline ) return; - mLength = length; - emit lengthChanged( length ); + mLengthWithGuideline = lengthWithGuideline; + emit lengthWithGuidelineChanged( lengthWithGuideline ); } void MeasurementMapTool::setArea( const double &area ) @@ -255,8 +251,3 @@ void MeasurementMapTool::setPerimeter( const double &perimeter ) mPerimeter = perimeter; emit perimeterChanged( perimeter ); } - -QgsVectorLayer *MeasurementMapTool::activeLayer() const -{ - return mActiveLayer; -} diff --git a/app/maptools/measurementmaptool.h b/app/maptools/measurementmaptool.h index 036edcf86..482b196ec 100644 --- a/app/maptools/measurementmaptool.h +++ b/app/maptools/measurementmaptool.h @@ -27,10 +27,9 @@ class MeasurementMapTool : public AbstractMapTool Q_OBJECT Q_PROPERTY( QgsGeometry recordedGeometry READ recordedGeometry WRITE setRecordedGeometry NOTIFY recordedGeometryChanged ) - Q_PROPERTY( QgsVectorLayer *activeLayer READ activeLayer WRITE setActiveLayer NOTIFY activeLayerChanged ) Q_PROPERTY( QgsGeometry existingVertices READ existingVertices WRITE setExistingVertices NOTIFY existingVerticesChanged ) - Q_PROPERTY( double length READ length WRITE setLength NOTIFY lengthChanged ) + Q_PROPERTY( double lengthWithGuideline READ lengthWithGuideline WRITE setLengthWithGuideline NOTIFY lengthWithGuidelineChanged ) Q_PROPERTY( double perimeter READ perimeter WRITE setPerimeter NOTIFY perimeterChanged ) Q_PROPERTY( double area READ area WRITE setArea NOTIFY areaChanged ) @@ -64,11 +63,11 @@ class MeasurementMapTool : public AbstractMapTool * Repeats measurement process. * Clears all recorded points and rebuilds the geometry. */ - Q_INVOKABLE void repeat(); + Q_INVOKABLE void reset(); // Getter and Setters - double length() const; - void setLength( const double &length ); + double lengthWithGuideline() const; + void setLengthWithGuideline( const double &length ); double perimeter() const; void setPerimeter( const double &perimeter ); @@ -91,22 +90,19 @@ class MeasurementMapTool : public AbstractMapTool QgsGeometry existingVertices() const; void setExistingVertices( const QgsGeometry &vertices ); - QgsVectorLayer *activeLayer() const; - void setActiveLayer( QgsVectorLayer *newActiveLayer ); - signals: - void lengthChanged( const double &length ); + void lengthWithGuidelineChanged( const double &lengthWithGuideline ); void perimeterChanged( const double &perimeter ); void areaChanged( const double &area ); void canUndoChanged( bool canUndo ); void canCloseShapeChanged( bool canUndo ); void closeShapeDoneChanged( bool canUndo ); - void activeLayerChanged( QgsVectorLayer *activeLayer ); void recordedGeometryChanged( const QgsGeometry &recordedGeometry ); void existingVerticesChanged( const QgsGeometry &vertices ); protected: void rebuildGeometry(); + void checkCanCloseShape( const QPointF &crosshairPoint ); public slots: void updateDistance( const QPointF &crosshairPoint ); @@ -115,8 +111,8 @@ class MeasurementMapTool : public AbstractMapTool QVector mPoints; QgsGeometry mRecordedGeometry; QgsGeometry mExistingVertices; - QgsVectorLayer *mActiveLayer = nullptr; - double mLength = 0; + QgsDistanceArea mDistanceArea; + double mLengthWithGuideline = 0; double mPerimeter = 0; double mArea = 0; bool mCanUndo = false; diff --git a/app/qml/gps/MMMeasureDrawer.qml b/app/qml/gps/MMMeasureDrawer.qml index 2b4579649..bcf5032fd 100644 --- a/app/qml/gps/MMMeasureDrawer.qml +++ b/app/qml/gps/MMMeasureDrawer.qml @@ -30,7 +30,6 @@ MMDrawer { property bool closeShapeDone: mapCanvas.mapToolComponent?.mapTool?.closeShapeDone ?? false property bool canUndo: mapCanvas.mapToolComponent?.mapTool?.canUndo ?? false - property string length: __inputUtils.formatDistanceInProjectUnit( mapCanvas.mapToolComponent?.mapTool?.length ?? 0, 1 ) property string perimeter: __inputUtils.formatDistanceInProjectUnit( mapCanvas.mapToolComponent?.mapTool?.perimeter ?? 0, 1 ) property string area: __inputUtils.formatAreaInProjectUnit( mapCanvas.mapToolComponent?.mapTool?.area ?? 0, 1 ) @@ -83,7 +82,7 @@ MMDrawer { width: ( parent.width + parent.spacing ) / 2 title: closeShapeDone ? qsTr( "Perimeter" ) : qsTr( "Length" ) - value: closeShapeDone ? root.perimeter : root.length + value: root.perimeter } MMGpsComponents.MMGpsDataText{ diff --git a/app/qml/map/MMMeasurementTools.qml b/app/qml/map/MMMeasurementTools.qml index b62cdb908..62096b88f 100644 --- a/app/qml/map/MMMeasurementTools.qml +++ b/app/qml/map/MMMeasurementTools.qml @@ -34,7 +34,6 @@ Item { id: mapTool mapSettings: root.map.mapSettings - activeLayer: __activeLayer.vectorLayer } MM.GuidelineController { @@ -94,7 +93,7 @@ Item { qgsProject: __activeProject.qgsProject mapSettings: root.map.mapSettings - text: __inputUtils.formatDistanceInProjectUnit( mapTool.length ) + text: __inputUtils.formatDistanceInProjectUnit( mapTool.lengthWithGuideline ) canCloseShape: mapTool.canCloseShape onCloseShapeClicked: closeShape() @@ -120,6 +119,6 @@ Item { { guidelineController.allowed = true crosshair.visible = true - mapTool.repeat() + mapTool.reset() } } diff --git a/app/qml/map/components/MMCrosshair.qml b/app/qml/map/components/MMCrosshair.qml index a9c7ec465..dd7f7ef86 100644 --- a/app/qml/map/components/MMCrosshair.qml +++ b/app/qml/map/components/MMCrosshair.qml @@ -28,6 +28,8 @@ Item { property real outerSize: 60 * __dp property real innerDotSize: 10 * __dp + property alias crosshairForeground: crosshairForeground + MM.SnapUtils { id: snapUtils diff --git a/app/qml/map/components/MMMeasureCrosshair.qml b/app/qml/map/components/MMMeasureCrosshair.qml index aa71fd60b..b8d76ba3e 100644 --- a/app/qml/map/components/MMMeasureCrosshair.qml +++ b/app/qml/map/components/MMMeasureCrosshair.qml @@ -16,8 +16,11 @@ import "../../components" Item { id: root + required property string text /*required*/ property var qgsProject /*required*/ property var mapSettings + + property bool canCloseShape: false property bool shouldUseSnapping: false property point center: Qt.point( root.width / 2, root.height / 2 ) @@ -34,9 +37,6 @@ Item { signal closeShapeClicked - property bool canCloseShape: false - required property string text - MM.SnapUtils { id: snapUtils @@ -47,205 +47,18 @@ Item { destinationLayer: __activeLayer.vectorLayer } - Image { - id: crosshairBackground // white background of the crosshair - - x: root.screenPoint.x - width / 2 - y: root.screenPoint.y - height / 2 - - Behavior on x { - PropertyAnimation { - properties: "x" - duration: 50 - easing.type: Easing.InQuad - } - } - - Behavior on y { - PropertyAnimation { - properties: "y" - duration: 50 - easing.type: Easing.InQuad - } - } - - height: root.outerSize - width: height - - source: __style.crosshairBackgroundImage - sourceSize.width: width - sourceSize.height: height - } - - Image { - id: crosshairForeground // green / purple outer circle of the crosshair - - x: root.screenPoint.x - width / 2 - y: root.screenPoint.y - height / 2 - - Behavior on x { - PropertyAnimation { - properties: "x" - duration: 50 - easing.type: Easing.InQuad - } - } - - Behavior on y { - PropertyAnimation { - properties: "y" - duration: 50 - easing.type: Easing.InQuad - } - } - - height: root.outerSize - width: height - - source: __style.crosshairForegroundImage - sourceSize.width: width - sourceSize.height: height - } - - ColorOverlay { - anchors.fill: crosshairForeground - source: crosshairForeground - color: snapUtils.snapped ? __style.snappingColor : __style.forestColor - } - - Image { - id: crossCenterDot // Center dot - visible when not snapped (green) + MMCrosshair { + id: crosshair - x: root.screenPoint.x - width / 2 - y: root.screenPoint.y - height / 2 - - Behavior on x { - PropertyAnimation { - properties: "x" - duration: 50 - easing.type: Easing.InQuad - } - } - - Behavior on y { - PropertyAnimation { - properties: "y" - duration: 50 - easing.type: Easing.InQuad - } - } - - opacity: snapUtils.snapped ? 0 : 100 - - Behavior on opacity { - PropertyAnimation { - properties: "opacity" - duration: 100 - easing.type: Easing.InQuad - } - } - - height: root.innerDotSize - width: height - sourceSize.width: width - sourceSize.height: height - - source: __style.crosshairCenterImage - } - - Image { - id: crossCenterPlus // Center plus - visible when not snapped (purple) - - x: root.screenPoint.x - width / 2 - y: root.screenPoint.y - height / 2 - - Behavior on x { - PropertyAnimation { - properties: "x" - duration: 50 - easing.type: Easing.InQuad - } - } - - Behavior on y { - PropertyAnimation { - properties: "y" - duration: 50 - easing.type: Easing.InQuad - } - } - - opacity: snapUtils.snapped && ( snapUtils.snapType === MM.SnapUtils.Vertex || snapUtils.snapType === MM.SnapUtils.Other ) ? 100 : 0 - - Behavior on opacity { - PropertyAnimation { - properties: "opacity" - duration: 100 - easing.type: Easing.InQuad - } - } - - rotation: snapUtils.snapType === MM.SnapUtils.Other ? 0 : 45 - - Behavior on rotation { - PropertyAnimation { - properties: "rotation" - duration: 50 - easing.type: Easing.InQuad - } - } - - height: root.innerDotSize * 2 - width: height - sourceSize.width: width - sourceSize.height: height - - // Important: must be same color as __style.snappingColor - source: __style.crosshairPlusImage - } - - Image { - id: crossCenterCircle // Center circle - visible when snapped to segment (purple) - - x: root.screenPoint.x - width / 2 - y: root.screenPoint.y - height / 2 - - Behavior on x { - PropertyAnimation { - properties: "x" - duration: 50 - easing.type: Easing.InQuad - } - } - - Behavior on y { - PropertyAnimation { - properties: "y" - duration: 50 - easing.type: Easing.InQuad - } - } - - opacity: snapUtils.snapped && snapUtils.snapType === MM.SnapUtils.Segment ? 100 : 0 - - Behavior on opacity { - PropertyAnimation { - properties: "opacity" - duration: 100 - easing.type: Easing.InQuad - } - } - - height: root.innerDotSize * 2 - width: height - sourceSize.width: width - sourceSize.height: height - - // Important: must be same color as __style.snappingColor - source: __style.crosshairCircleImage + anchors.fill: parent + qgsProject: __activeProject.qgsProject + mapSettings: root.mapSettings } Rectangle { + y: crosshair.crosshairForeground.y + crosshair.crosshairForeground.height + x: crosshair.crosshairForeground.x - ( ( width - crosshair.crosshairForeground.width ) / 2 ) + width: Math.max( root.outerSize - 10 * __dp , row.width ) height: root.outerSize * 0.6 radius: root.height / 2 @@ -254,9 +67,6 @@ Item { layer.enabled: true layer.effect: MMShadow {} - anchors.top: crosshairForeground.bottom - anchors.horizontalCenter: crosshairForeground.horizontalCenter - Row { id: row @@ -306,7 +116,7 @@ Item { } } - Connections { + Connections { // future snapping? _(ツ)_/¯ target: __activeProject function onProjectWillBeReloaded() { From 83a3683353e2af5d369bb2436d74d8b809a8a692 Mon Sep 17 00:00:00 2001 From: VitorVieiraZ Date: Mon, 23 Sep 2024 18:54:20 -0300 Subject: [PATCH 34/60] adding small button to gallery and testFormatAreaInProjectUnit --- app/test/testutilsfunctions.cpp | 33 ++++++++++++++ app/test/testutilsfunctions.h | 1 + gallery/qml/pages/ButtonsPage.qml | 76 ++++++++++++++++++++++++++----- 3 files changed, 98 insertions(+), 12 deletions(-) diff --git a/app/test/testutilsfunctions.cpp b/app/test/testutilsfunctions.cpp index 603d8e319..acbc8f83a 100644 --- a/app/test/testutilsfunctions.cpp +++ b/app/test/testutilsfunctions.cpp @@ -888,3 +888,36 @@ void TestUtilsFunctions::testFormatDistanceInDistanceUnit() dist2str = mUtils->formatDistanceInProjectUnit( 7000, 1, Qgis::DistanceUnit::Feet ); QVERIFY( dist2str == "22965.9 ft" ); } + +void TestUtilsFunctions::testFormatAreaInProjectUnit() +{ + QString area2str = mUtils->formatAreaInProjectUnit( 1500.234, 2, Qgis::AreaUnit::SquareMeters ); + QVERIFY( area2str == "1500.23 m²" ); + + area2str = mUtils->formatAreaInProjectUnit( 1500.234, 1, Qgis::AreaUnit::SquareMeters ); + QVERIFY( area2str == "1500.2 m²" ); + + area2str = mUtils->formatAreaInProjectUnit( 1500.234, 0, Qgis::AreaUnit::SquareMeters ); + QVERIFY( area2str == "1500 m²" ); + + area2str = mUtils->formatAreaInProjectUnit( 500.22, 1, Qgis::AreaUnit::SquareMeters ); + QVERIFY( area2str == "500.2 m²" ); + + area2str = mUtils->formatAreaInProjectUnit( 0.22, 0, Qgis::AreaUnit::SquareMeters ); + QVERIFY( area2str == "0 m²" ); + + area2str = mUtils->formatAreaInProjectUnit( -0.22, 0, Qgis::AreaUnit::SquareMeters ); + QVERIFY( area2str == "-0 m²" ); + + area2str = mUtils->formatAreaInProjectUnit( 1.222234, 2, Qgis::AreaUnit::SquareKilometers ); + QVERIFY( area2str == "0.00 km²" ); + + area2str = mUtils->formatAreaInProjectUnit( 6000, 1, Qgis::AreaUnit::Acres ); + QVERIFY( area2str == "1.5 ac" ); + + area2str = mUtils->formatAreaInProjectUnit( 5, 1, Qgis::AreaUnit::Acres ); + QVERIFY( area2str == "0.0 ac" ); + + area2str = mUtils->formatAreaInProjectUnit( 7000, 1, Qgis::AreaUnit::Acres ); + QVERIFY( area2str == "1.7 ac" ); +} diff --git a/app/test/testutilsfunctions.h b/app/test/testutilsfunctions.h index f74cf140f..64259c571 100644 --- a/app/test/testutilsfunctions.h +++ b/app/test/testutilsfunctions.h @@ -49,6 +49,7 @@ class TestUtilsFunctions: public QObject void testAttribution(); void testParsePositionUpdates(); void testFormatDistanceInDistanceUnit(); + void testFormatAreaInProjectUnit(); private: void testFormatDuration( const QDateTime &t0, qint64 diffSecs, const QString &expectedResult ); diff --git a/gallery/qml/pages/ButtonsPage.qml b/gallery/qml/pages/ButtonsPage.qml index 97fabbb3e..4e0bc636e 100644 --- a/gallery/qml/pages/ButtonsPage.qml +++ b/gallery/qml/pages/ButtonsPage.qml @@ -87,8 +87,24 @@ ScrollView { iconSourceLeft: __style.uploadIcon } - MMButton { - text: "Primary flex width (no witdth set)" + Row { + width: parent.width + spacing: 20 + + MMButton { + text: "Primary flex width (no witdth set)" + } + + MMButton { + text: "Small Primary" + size: MMButton.Sizes.Small + } + + MMButton { + text: "Small Primary with Icon" + iconSourceLeft: __style.syncIcon + size: MMButton.Sizes.Small + } } MMListSpacer { height: __style.margin20 } @@ -142,11 +158,29 @@ ScrollView { iconSourceRight: __style.arrowLinkRightIcon } - MMButton { - type: MMButton.Types.Secondary - text: "Secondary flex width (no witdth set)" - iconSourceLeft: __style.uploadIcon - iconSourceRight: __style.uploadIcon + Row { + width: parent.width + spacing: 20 + + MMButton { + type: MMButton.Types.Secondary + text: "Secondary flex width (no witdth set)" + iconSourceLeft: __style.uploadIcon + iconSourceRight: __style.uploadIcon + } + + MMButton { + text: "Small Secondary" + type: MMButton.Types.Secondary + size: MMButton.Sizes.Small + } + + MMButton { + text: "Small Secondary with Icon" + type: MMButton.Types.Secondary + iconSourceLeft: __style.syncIcon + size: MMButton.Sizes.Small + } } MMListSpacer { height: __style.margin20 } @@ -200,11 +234,29 @@ ScrollView { iconSourceRight: __style.arrowLinkRightIcon } - MMButton { - type: MMButton.Types.Tertiary - text: "Tertiary flex width (no witdth set)" - fontColor: __style.nightColor - iconSourceLeft: __style.globeIcon + Row { + width: parent.width + spacing: 20 + + MMButton { + type: MMButton.Types.Tertiary + text: "Tertiary flex width (no witdth set)" + fontColor: __style.nightColor + iconSourceLeft: __style.globeIcon + } + + MMButton { + text: "Small Tertiary" + type: MMButton.Types.Tertiary + size: MMButton.Sizes.Small + } + + MMButton { + text: "Small Tertiary with Icon" + type: MMButton.Types.Tertiary + iconSourceLeft: __style.syncIcon + size: MMButton.Sizes.Small + } } } } From 976464e63314a2089762313e94ce0f80744bfecf Mon Sep 17 00:00:00 2001 From: VitorVieiraZ Date: Tue, 24 Sep 2024 00:25:39 -0300 Subject: [PATCH 35/60] post review measurement tool --- app/maptools/abstractmaptool.h | 3 +- app/maptools/measurementmaptool.cpp | 55 ++++++++++++++++++++--------- app/maptools/measurementmaptool.h | 15 ++++++-- app/qml/gps/MMMeasureDrawer.qml | 2 +- app/qml/map/MMMeasurementTools.qml | 13 +------ app/test/testutilsfunctions.cpp | 40 ++++++++++----------- 6 files changed, 74 insertions(+), 54 deletions(-) diff --git a/app/maptools/abstractmaptool.h b/app/maptools/abstractmaptool.h index ec6a9ca99..11c667170 100644 --- a/app/maptools/abstractmaptool.h +++ b/app/maptools/abstractmaptool.h @@ -33,8 +33,7 @@ class AbstractMapTool : public QObject void mapSettingsChanged( InputMapSettings *mapSettings ); - private: - + protected: InputMapSettings *mMapSettings = nullptr; }; diff --git a/app/maptools/measurementmaptool.cpp b/app/maptools/measurementmaptool.cpp index 57f22376a..beb2fc95a 100644 --- a/app/maptools/measurementmaptool.cpp +++ b/app/maptools/measurementmaptool.cpp @@ -12,20 +12,19 @@ MeasurementMapTool::MeasurementMapTool( QObject *parent ) : AbstractMapTool{ parent } { - if ( !mapSettings() ) + connect( this, &AbstractMapTool::mapSettingsChanged, this, &MeasurementMapTool::onMapSettingsChanged ); + + if ( mapSettings() ) { - return; + onMapSettingsChanged( mapSettings() ); } - - mDistanceArea.setEllipsoid( QStringLiteral( "WGS84" ) ); - mDistanceArea.setSourceCrs( mapSettings()->destinationCrs(), mapSettings()->transformContext() ); } MeasurementMapTool::~MeasurementMapTool() = default; -void MeasurementMapTool::addPoint( const QPointF &point ) +void MeasurementMapTool::addPoint() { - QgsPoint transformedPoint = mapSettings()->screenToCoordinate( point ); + QgsPoint transformedPoint = mapSettings()->screenToCoordinate( mCrosshairPoint ); mPoints.push_back( transformedPoint ); rebuildGeometry(); } @@ -35,15 +34,12 @@ void MeasurementMapTool::removePoint() if ( !mPoints.isEmpty() ) { mPoints.pop_back(); - - if ( mPoints.count() < 3 ) - setCanCloseShape( false ); - + checkCanCloseShape(); rebuildGeometry(); } } -void MeasurementMapTool::updateDistance( const QPointF &crosshairPoint ) +void MeasurementMapTool::updateDistance() { if ( mPoints.isEmpty() ) { @@ -51,16 +47,16 @@ void MeasurementMapTool::updateDistance( const QPointF &crosshairPoint ) return; } - checkCanCloseShape( crosshairPoint ) ; + checkCanCloseShape(); QgsPoint lastPoint = mPoints.last(); - QgsPoint transformedCrosshairPoint = mapSettings()->screenToCoordinate( crosshairPoint ); + QgsPoint transformedCrosshairPoint = mapSettings()->screenToCoordinate( mCrosshairPoint ); double calculatedLength = mDistanceArea.measureLength( mRecordedGeometry ) + mDistanceArea.measureLine( transformedCrosshairPoint, lastPoint ); setLengthWithGuideline( calculatedLength ); } -void MeasurementMapTool::checkCanCloseShape( const QPointF &crosshairPoint ) +void MeasurementMapTool::checkCanCloseShape() { if ( mRecordedGeometry.isEmpty() || mPoints.count() < 3 ) { @@ -72,7 +68,7 @@ void MeasurementMapTool::checkCanCloseShape( const QPointF &crosshairPoint ) { QgsPoint firstPoint = mPoints.first(); QPointF firstPointScreen = mapSettings()->coordinateToScreen( firstPoint ); - double distanceToFirstPoint = std::hypot( crosshairPoint.x() - firstPointScreen.x(), crosshairPoint.y() - firstPointScreen.y() ); + double distanceToFirstPoint = std::hypot( mCrosshairPoint.x() - firstPointScreen.x(), mCrosshairPoint.y() - firstPointScreen.y() ); setCanCloseShape( distanceToFirstPoint <= CLOSE_THRESHOLD ); } } @@ -140,6 +136,19 @@ void MeasurementMapTool::rebuildGeometry() setRecordedGeometry( geometry ); } +void MeasurementMapTool::onMapSettingsChanged( InputMapSettings *newMapSettings ) +{ + if ( newMapSettings ) + { + // Connect to the extentChanged signal of mapSettings + connect( newMapSettings, &InputMapSettings::extentChanged, this, &MeasurementMapTool::updateDistance ); + + // Initialize mDistanceArea with the new map settings + mDistanceArea.setEllipsoid( QStringLiteral( "WGS84" ) ); + mDistanceArea.setSourceCrs( newMapSettings->destinationCrs(), newMapSettings->transformContext() ); + } +} + const QgsGeometry &MeasurementMapTool::recordedGeometry() const { return mRecordedGeometry; @@ -169,6 +178,11 @@ double MeasurementMapTool::perimeter() const return mPerimeter; } +QPointF MeasurementMapTool::crosshairPoint() const +{ + return mCrosshairPoint; +} + double MeasurementMapTool::lengthWithGuideline() const { return mLengthWithGuideline; @@ -251,3 +265,12 @@ void MeasurementMapTool::setPerimeter( const double &perimeter ) mPerimeter = perimeter; emit perimeterChanged( perimeter ); } + +void MeasurementMapTool::setCrosshairPoint( const QPointF &point ) +{ + if ( mCrosshairPoint == point ) + return; + + mCrosshairPoint = point; + emit crosshairPointChanged( mCrosshairPoint ); +} diff --git a/app/maptools/measurementmaptool.h b/app/maptools/measurementmaptool.h index 482b196ec..d96ff70bb 100644 --- a/app/maptools/measurementmaptool.h +++ b/app/maptools/measurementmaptool.h @@ -28,6 +28,7 @@ class MeasurementMapTool : public AbstractMapTool Q_PROPERTY( QgsGeometry recordedGeometry READ recordedGeometry WRITE setRecordedGeometry NOTIFY recordedGeometryChanged ) Q_PROPERTY( QgsGeometry existingVertices READ existingVertices WRITE setExistingVertices NOTIFY existingVerticesChanged ) + Q_PROPERTY( QPointF crosshairPoint READ crosshairPoint WRITE setCrosshairPoint NOTIFY crosshairPointChanged ) Q_PROPERTY( double lengthWithGuideline READ lengthWithGuideline WRITE setLengthWithGuideline NOTIFY lengthWithGuidelineChanged ) Q_PROPERTY( double perimeter READ perimeter WRITE setPerimeter NOTIFY perimeterChanged ) @@ -45,7 +46,7 @@ class MeasurementMapTool : public AbstractMapTool * Adds point to the end of the recorded geometry; updates recordedGeometry afterwards * Passed point needs to be in map CRS */ - Q_INVOKABLE void addPoint( const QPointF &point ); + Q_INVOKABLE void addPoint(); /** * Removes last point from recorded geometry if there is at least one point @@ -75,6 +76,9 @@ class MeasurementMapTool : public AbstractMapTool double area() const; void setArea( const double &area ); + QPointF crosshairPoint() const; + void setCrosshairPoint( const QPointF &point ); + bool canUndo() const; void setCanUndo( bool newCanUndo ); @@ -99,19 +103,24 @@ class MeasurementMapTool : public AbstractMapTool void closeShapeDoneChanged( bool canUndo ); void recordedGeometryChanged( const QgsGeometry &recordedGeometry ); void existingVerticesChanged( const QgsGeometry &vertices ); + void crosshairPointChanged( const QPointF &crosshairPoint ); protected: void rebuildGeometry(); - void checkCanCloseShape( const QPointF &crosshairPoint ); + void checkCanCloseShape(); public slots: - void updateDistance( const QPointF &crosshairPoint ); + void updateDistance(); + + private slots: + void onMapSettingsChanged( InputMapSettings *newMapSettings ); private: QVector mPoints; QgsGeometry mRecordedGeometry; QgsGeometry mExistingVertices; QgsDistanceArea mDistanceArea; + QPointF mCrosshairPoint; double mLengthWithGuideline = 0; double mPerimeter = 0; double mArea = 0; diff --git a/app/qml/gps/MMMeasureDrawer.qml b/app/qml/gps/MMMeasureDrawer.qml index bcf5032fd..80102df85 100644 --- a/app/qml/gps/MMMeasureDrawer.qml +++ b/app/qml/gps/MMMeasureDrawer.qml @@ -103,7 +103,7 @@ MMDrawer { MMButton { text: root.canCloseShape ? qsTr( "Close shape" ) : qsTr( "Add point" ) iconSourceLeft: canCloseShape ? __style.closeShapeIcon : __style.plusIcon - onClicked: canCloseShape ? root.mapCanvas.mapToolComponent.closeShape() : root.mapCanvas.mapToolComponent.addPoint() + onClicked: canCloseShape ? root.mapCanvas.mapToolComponent.closeShape() : root.mapCanvas.mapToolComponent.mapTool.addPoint() } MMButton { diff --git a/app/qml/map/MMMeasurementTools.qml b/app/qml/map/MMMeasurementTools.qml index 62096b88f..14b507fd0 100644 --- a/app/qml/map/MMMeasurementTools.qml +++ b/app/qml/map/MMMeasurementTools.qml @@ -27,13 +27,11 @@ Item { signal finishMeasurement() - Component.onCompleted: map.mapSettings.extentChanged.connect( onScreenPositionChanged ) - Component.onDestruction: map.mapSettings.extentChanged.disconnect( onScreenPositionChanged ) - MM.MeasurementMapTool { id: mapTool mapSettings: root.map.mapSettings + crosshairPoint: crosshair.screenPoint } MM.GuidelineController { @@ -99,15 +97,6 @@ Item { onCloseShapeClicked: closeShape() } - function addPoint() - { - mapTool.addPoint( crosshair.screenPoint ) - } - - function onScreenPositionChanged() { - mapTool.updateDistance( crosshair.screenPoint ); - } - function closeShape() { guidelineController.allowed = false diff --git a/app/test/testutilsfunctions.cpp b/app/test/testutilsfunctions.cpp index acbc8f83a..cb7687844 100644 --- a/app/test/testutilsfunctions.cpp +++ b/app/test/testutilsfunctions.cpp @@ -891,33 +891,33 @@ void TestUtilsFunctions::testFormatDistanceInDistanceUnit() void TestUtilsFunctions::testFormatAreaInProjectUnit() { - QString area2str = mUtils->formatAreaInProjectUnit( 1500.234, 2, Qgis::AreaUnit::SquareMeters ); - QVERIFY( area2str == "1500.23 m²" ); + QString area2str = mUtils->formatAreaInProjectUnit( 1500.234, 2, Qgis::AreaUnit::SquareMeters ); + QVERIFY( area2str == "1500.23 m²" ); - area2str = mUtils->formatAreaInProjectUnit( 1500.234, 1, Qgis::AreaUnit::SquareMeters ); - QVERIFY( area2str == "1500.2 m²" ); + area2str = mUtils->formatAreaInProjectUnit( 1500.234, 1, Qgis::AreaUnit::SquareMeters ); + QVERIFY( area2str == "1500.2 m²" ); - area2str = mUtils->formatAreaInProjectUnit( 1500.234, 0, Qgis::AreaUnit::SquareMeters ); - QVERIFY( area2str == "1500 m²" ); + area2str = mUtils->formatAreaInProjectUnit( 1500.234, 0, Qgis::AreaUnit::SquareMeters ); + QVERIFY( area2str == "1500 m²" ); - area2str = mUtils->formatAreaInProjectUnit( 500.22, 1, Qgis::AreaUnit::SquareMeters ); - QVERIFY( area2str == "500.2 m²" ); + area2str = mUtils->formatAreaInProjectUnit( 500.22, 1, Qgis::AreaUnit::SquareMeters ); + QVERIFY( area2str == "500.2 m²" ); - area2str = mUtils->formatAreaInProjectUnit( 0.22, 0, Qgis::AreaUnit::SquareMeters ); - QVERIFY( area2str == "0 m²" ); + area2str = mUtils->formatAreaInProjectUnit( 0.22, 0, Qgis::AreaUnit::SquareMeters ); + QVERIFY( area2str == "0 m²" ); - area2str = mUtils->formatAreaInProjectUnit( -0.22, 0, Qgis::AreaUnit::SquareMeters ); - QVERIFY( area2str == "-0 m²" ); + area2str = mUtils->formatAreaInProjectUnit( -0.22, 0, Qgis::AreaUnit::SquareMeters ); + QVERIFY( area2str == "-0 m²" ); - area2str = mUtils->formatAreaInProjectUnit( 1.222234, 2, Qgis::AreaUnit::SquareKilometers ); - QVERIFY( area2str == "0.00 km²" ); + area2str = mUtils->formatAreaInProjectUnit( 1.222234, 2, Qgis::AreaUnit::SquareKilometers ); + QVERIFY( area2str == "0.00 km²" ); - area2str = mUtils->formatAreaInProjectUnit( 6000, 1, Qgis::AreaUnit::Acres ); - QVERIFY( area2str == "1.5 ac" ); + area2str = mUtils->formatAreaInProjectUnit( 6000, 1, Qgis::AreaUnit::Acres ); + QVERIFY( area2str == "1.5 ac" ); - area2str = mUtils->formatAreaInProjectUnit( 5, 1, Qgis::AreaUnit::Acres ); - QVERIFY( area2str == "0.0 ac" ); + area2str = mUtils->formatAreaInProjectUnit( 5, 1, Qgis::AreaUnit::Acres ); + QVERIFY( area2str == "0.0 ac" ); - area2str = mUtils->formatAreaInProjectUnit( 7000, 1, Qgis::AreaUnit::Acres ); - QVERIFY( area2str == "1.7 ac" ); + area2str = mUtils->formatAreaInProjectUnit( 7000, 1, Qgis::AreaUnit::Acres ); + QVERIFY( area2str == "1.7 ac" ); } From 3964f647fb3f492d9f4b95ae26c6784e9a0387d7 Mon Sep 17 00:00:00 2001 From: VitorVieiraZ Date: Tue, 24 Sep 2024 00:29:30 -0300 Subject: [PATCH 36/60] last adjustment --- app/maptools/measurementmaptool.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/app/maptools/measurementmaptool.cpp b/app/maptools/measurementmaptool.cpp index beb2fc95a..8f9d9c162 100644 --- a/app/maptools/measurementmaptool.cpp +++ b/app/maptools/measurementmaptool.cpp @@ -140,10 +140,8 @@ void MeasurementMapTool::onMapSettingsChanged( InputMapSettings *newMapSettings { if ( newMapSettings ) { - // Connect to the extentChanged signal of mapSettings connect( newMapSettings, &InputMapSettings::extentChanged, this, &MeasurementMapTool::updateDistance ); - // Initialize mDistanceArea with the new map settings mDistanceArea.setEllipsoid( QStringLiteral( "WGS84" ) ); mDistanceArea.setSourceCrs( newMapSettings->destinationCrs(), newMapSettings->transformContext() ); } From 0183d0bfbd7abfda6a938e0f73e73d718176cadc Mon Sep 17 00:00:00 2001 From: VitorVieiraZ Date: Tue, 24 Sep 2024 08:47:49 -0300 Subject: [PATCH 37/60] small adjustment --- app/maptools/abstractmaptool.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/maptools/abstractmaptool.h b/app/maptools/abstractmaptool.h index 11c667170..5ac544554 100644 --- a/app/maptools/abstractmaptool.h +++ b/app/maptools/abstractmaptool.h @@ -33,7 +33,7 @@ class AbstractMapTool : public QObject void mapSettingsChanged( InputMapSettings *mapSettings ); - protected: + private: InputMapSettings *mMapSettings = nullptr; }; From 2efa1cb3bf353dea4dc6661662cc6e4990847248 Mon Sep 17 00:00:00 2001 From: VitorVieiraZ Date: Fri, 27 Sep 2024 17:17:41 -0300 Subject: [PATCH 38/60] ongoing post review changes --- app/inpututils.cpp | 5 +++++ app/inpututils.h | 5 +++++ app/maptools/abstractmaptool.cpp | 3 +++ app/maptools/measurementmaptool.cpp | 15 +++++---------- app/maptools/measurementmaptool.h | 2 +- app/qml/components/MMButton.qml | 9 ++++++++- app/qml/map/MMMapController.qml | 2 +- app/qml/map/MMMeasurementTools.qml | 2 +- 8 files changed, 29 insertions(+), 14 deletions(-) diff --git a/app/inpututils.cpp b/app/inpututils.cpp index 9904308f4..eabbccffa 100644 --- a/app/inpututils.cpp +++ b/app/inpututils.cpp @@ -2216,3 +2216,8 @@ bool InputUtils::openLink( const QString &homePath, const QString &link ) return true; } + +double InputUtils::pixelDistanceBetween( const QPointF &p1, const QPointF &p2 ) +{ + return std::hypot( p1.x() - p2.x(), p1.y() - p2.y() ); +} diff --git a/app/inpututils.h b/app/inpututils.h index 1fffb70ac..05dc9c100 100644 --- a/app/inpututils.h +++ b/app/inpututils.h @@ -581,6 +581,11 @@ class InputUtils: public QObject */ static QVector qgisProfilerLog(); + /** + * Calculates the Euclidean distance between two pixel points + */ + static double pixelDistanceBetween( const QPointF &p1, const QPointF &p2 ); + public slots: void onQgsLogMessageReceived( const QString &message, const QString &tag, Qgis::MessageLevel level ); diff --git a/app/maptools/abstractmaptool.cpp b/app/maptools/abstractmaptool.cpp index dd8b25636..930496747 100644 --- a/app/maptools/abstractmaptool.cpp +++ b/app/maptools/abstractmaptool.cpp @@ -26,6 +26,9 @@ void AbstractMapTool::setMapSettings( InputMapSettings *newMapSettings ) { if ( mMapSettings == newMapSettings ) return; + else + disconnect( mMapSettings, nullptr, this, nullptr ); + mMapSettings = newMapSettings; emit mapSettingsChanged( mMapSettings ); } diff --git a/app/maptools/measurementmaptool.cpp b/app/maptools/measurementmaptool.cpp index 8f9d9c162..1215a4c8b 100644 --- a/app/maptools/measurementmaptool.cpp +++ b/app/maptools/measurementmaptool.cpp @@ -13,11 +13,6 @@ MeasurementMapTool::MeasurementMapTool( QObject *parent ) : AbstractMapTool{ parent } { connect( this, &AbstractMapTool::mapSettingsChanged, this, &MeasurementMapTool::onMapSettingsChanged ); - - if ( mapSettings() ) - { - onMapSettingsChanged( mapSettings() ); - } } MeasurementMapTool::~MeasurementMapTool() = default; @@ -58,17 +53,17 @@ void MeasurementMapTool::updateDistance() void MeasurementMapTool::checkCanCloseShape() { - if ( mRecordedGeometry.isEmpty() || mPoints.count() < 3 ) + if ( mRecordedGeometry.isEmpty() || mPoints.count() < 3 || !mapSettings() ) { setCanCloseShape( false ); return; } - - if ( mPoints.count() >= 3 ) + else { + QgsPoint firstPoint = mPoints.first(); QPointF firstPointScreen = mapSettings()->coordinateToScreen( firstPoint ); - double distanceToFirstPoint = std::hypot( mCrosshairPoint.x() - firstPointScreen.x(), mCrosshairPoint.y() - firstPointScreen.y() ); + double distanceToFirstPoint = InputUtils::pixelDistanceBetween( mCrosshairPoint, firstPointScreen ); setCanCloseShape( distanceToFirstPoint <= CLOSE_THRESHOLD ); } } @@ -95,7 +90,7 @@ void MeasurementMapTool::closeShape() setCloseShapeDone( true ); } -void MeasurementMapTool::reset() +void MeasurementMapTool::resetMeasurement() { mPoints.clear(); diff --git a/app/maptools/measurementmaptool.h b/app/maptools/measurementmaptool.h index d96ff70bb..d2fd52ff8 100644 --- a/app/maptools/measurementmaptool.h +++ b/app/maptools/measurementmaptool.h @@ -64,7 +64,7 @@ class MeasurementMapTool : public AbstractMapTool * Repeats measurement process. * Clears all recorded points and rebuilds the geometry. */ - Q_INVOKABLE void reset(); + Q_INVOKABLE void resetMeasurement(); // Getter and Setters double lengthWithGuideline() const; diff --git a/app/qml/components/MMButton.qml b/app/qml/components/MMButton.qml index a2f98db87..0791d8144 100644 --- a/app/qml/components/MMButton.qml +++ b/app/qml/components/MMButton.qml @@ -186,7 +186,14 @@ Button { width: Math.min( paintedChildrenWidth, maxWidth ) height: Math.max( buttonContent.paintedHeight, buttonIconRight.height ) - spacing: ( root.size === MMButton.Sizes.Small ) ? 2 : ( buttonIconRight.visible || buttonIconLeft.visible ? __style.spacing12 : 0 ) + spacing: { + if ( ( root.size === MMButton.Sizes.Small ) ) + return 2; + else if ( ( buttonIconRight.visible || buttonIconLeft.visible ) ) + return __style.spacing12; + else + return 0; + } MMIcon { id: buttonIconLeft diff --git a/app/qml/map/MMMapController.qml b/app/qml/map/MMMapController.qml index 11a8d7d62..163f77f76 100644 --- a/app/qml/map/MMMapController.qml +++ b/app/qml/map/MMMapController.qml @@ -597,7 +597,7 @@ Item { } visible: { - if ( root.mapExtentOffset > 0 && (root.state === "stakeout") ) return false + if ( root.mapExtentOffset > 0 && root.state !== "stakeout" ) return false if ( __positionKit.positionProvider && __positionKit.positionProvider.type() === "external" ) { // for external receivers we want to show gps panel and accuracy button diff --git a/app/qml/map/MMMeasurementTools.qml b/app/qml/map/MMMeasurementTools.qml index 14b507fd0..13c5a5dd1 100644 --- a/app/qml/map/MMMeasurementTools.qml +++ b/app/qml/map/MMMeasurementTools.qml @@ -108,6 +108,6 @@ Item { { guidelineController.allowed = true crosshair.visible = true - mapTool.reset() + mapTool.resetMeasurement() } } From 985d7a1b5cc374f3a29f106525f2fb0ba9e7d08d Mon Sep 17 00:00:00 2001 From: VitorVieiraZ Date: Mon, 30 Sep 2024 15:12:58 -0300 Subject: [PATCH 39/60] mapSettings handling, MMDrawerHeader text eliding, activeProject parameter for units formatting --- app/inpututils.cpp | 8 ++++---- app/inpututils.h | 4 ++-- app/maptools/abstractmaptool.cpp | 6 +++++- app/maptools/abstractmaptool.h | 2 +- app/maptools/measurementmaptool.cpp | 21 ++++++++++++++++----- app/maptools/measurementmaptool.h | 5 ++--- app/qml/components/MMDrawerHeader.qml | 13 +++++++++---- app/qml/gps/MMMeasureDrawer.qml | 4 ++-- app/qml/gps/MMStakeoutDrawer.qml | 2 +- app/qml/map/MMMeasurementTools.qml | 2 +- 10 files changed, 43 insertions(+), 24 deletions(-) diff --git a/app/inpututils.cpp b/app/inpututils.cpp index eabbccffa..2bf9ddb0d 100644 --- a/app/inpututils.cpp +++ b/app/inpututils.cpp @@ -168,13 +168,13 @@ QString InputUtils::formatNumber( const double number, int precision ) return QString::number( number, 'f', precision ); } -QString InputUtils::formatDistanceInProjectUnit( const double distanceInMeters, int precision, Qgis::DistanceUnit destUnit ) +QString InputUtils::formatDistanceInProjectUnit( const double distanceInMeters, int precision, Qgis::DistanceUnit destUnit, QgsProject *activeProject ) { Qgis::DistanceUnit distUnit = destUnit; if ( distUnit == Qgis::DistanceUnit::Unknown ) { - distUnit = QgsProject::instance()->distanceUnits(); + distUnit = activeProject->distanceUnits(); } if ( distUnit == Qgis::DistanceUnit::Unknown ) @@ -189,13 +189,13 @@ QString InputUtils::formatDistanceInProjectUnit( const double distanceInMeters, return QString( "%1 %2" ).arg( QString::number( distance, 'f', precision ), abbreviation ); } -QString InputUtils::formatAreaInProjectUnit( const double areaInSquareMeters, int precision, Qgis::AreaUnit destUnit ) +QString InputUtils::formatAreaInProjectUnit( const double areaInSquareMeters, int precision, Qgis::AreaUnit destUnit, QgsProject *activeProject ) { Qgis::AreaUnit areaUnit = destUnit; if ( areaUnit == Qgis::AreaUnit::Unknown ) { - areaUnit = QgsProject::instance()->areaUnits(); + areaUnit = activeProject->areaUnits(); } if ( areaUnit == Qgis::AreaUnit::Unknown ) diff --git a/app/inpututils.h b/app/inpututils.h index 05dc9c100..b59956061 100644 --- a/app/inpututils.h +++ b/app/inpututils.h @@ -75,8 +75,8 @@ class InputUtils: public QObject Q_INVOKABLE QString getFileName( const QString &filePath ); Q_INVOKABLE QString formatProjectName( const QString &fullProjectName ); Q_INVOKABLE QString formatNumber( const double number, int precision = 1 ); - Q_INVOKABLE QString formatDistanceInProjectUnit( const double distanceInMeters, int precision = 1, Qgis::DistanceUnit destUnit = Qgis::DistanceUnit::Unknown ); - Q_INVOKABLE QString formatAreaInProjectUnit( const double areaInSquareMeters, int precision = 1, Qgis::AreaUnit destUnit = Qgis::AreaUnit::Unknown ); + Q_INVOKABLE QString formatDistanceInProjectUnit( const double distanceInMeters, int precision = 1, Qgis::DistanceUnit destUnit = Qgis::DistanceUnit::Unknown, QgsProject *activeProject = QgsProject::instance() ); + Q_INVOKABLE QString formatAreaInProjectUnit( const double areaInSquareMeters, int precision = 1, Qgis::AreaUnit destUnit = Qgis::AreaUnit::Unknown, QgsProject *activeProject = QgsProject::instance() ); Q_INVOKABLE void setExtentToFeature( const FeatureLayerPair &pair, InputMapSettings *mapSettings ); diff --git a/app/maptools/abstractmaptool.cpp b/app/maptools/abstractmaptool.cpp index 930496747..19d5fb129 100644 --- a/app/maptools/abstractmaptool.cpp +++ b/app/maptools/abstractmaptool.cpp @@ -25,9 +25,13 @@ InputMapSettings *AbstractMapTool::mapSettings() const void AbstractMapTool::setMapSettings( InputMapSettings *newMapSettings ) { if ( mMapSettings == newMapSettings ) + { return; + } else - disconnect( mMapSettings, nullptr, this, nullptr ); + { + disconnect( mMapSettings ); + } mMapSettings = newMapSettings; emit mapSettingsChanged( mMapSettings ); diff --git a/app/maptools/abstractmaptool.h b/app/maptools/abstractmaptool.h index 5ac544554..4ed41fccd 100644 --- a/app/maptools/abstractmaptool.h +++ b/app/maptools/abstractmaptool.h @@ -27,7 +27,7 @@ class AbstractMapTool : public QObject virtual ~AbstractMapTool(); InputMapSettings *mapSettings() const; - void setMapSettings( InputMapSettings *newMapSettings ); + virtual void setMapSettings( InputMapSettings *newMapSettings ); signals: diff --git a/app/maptools/measurementmaptool.cpp b/app/maptools/measurementmaptool.cpp index 1215a4c8b..89c9b1fba 100644 --- a/app/maptools/measurementmaptool.cpp +++ b/app/maptools/measurementmaptool.cpp @@ -12,7 +12,7 @@ MeasurementMapTool::MeasurementMapTool( QObject *parent ) : AbstractMapTool{ parent } { - connect( this, &AbstractMapTool::mapSettingsChanged, this, &MeasurementMapTool::onMapSettingsChanged ); + connect( this, &AbstractMapTool::mapSettingsChanged, this, &MeasurementMapTool::setMapSettings ); } MeasurementMapTool::~MeasurementMapTool() = default; @@ -131,14 +131,25 @@ void MeasurementMapTool::rebuildGeometry() setRecordedGeometry( geometry ); } -void MeasurementMapTool::onMapSettingsChanged( InputMapSettings *newMapSettings ) +void MeasurementMapTool::setMapSettings( InputMapSettings *newMapSettings ) { - if ( newMapSettings ) + InputMapSettings *currentMapSettings = mapSettings(); + + if ( currentMapSettings ) + { + disconnect( currentMapSettings ); + } + + AbstractMapTool::setMapSettings( newMapSettings ); + + InputMapSettings *updatedMapSettings = mapSettings(); + + if ( updatedMapSettings ) { - connect( newMapSettings, &InputMapSettings::extentChanged, this, &MeasurementMapTool::updateDistance ); + connect( updatedMapSettings, &InputMapSettings::extentChanged, this, &MeasurementMapTool::updateDistance ); mDistanceArea.setEllipsoid( QStringLiteral( "WGS84" ) ); - mDistanceArea.setSourceCrs( newMapSettings->destinationCrs(), newMapSettings->transformContext() ); + mDistanceArea.setSourceCrs( updatedMapSettings->destinationCrs(), updatedMapSettings->transformContext() ); } } diff --git a/app/maptools/measurementmaptool.h b/app/maptools/measurementmaptool.h index d2fd52ff8..3f87a0b67 100644 --- a/app/maptools/measurementmaptool.h +++ b/app/maptools/measurementmaptool.h @@ -94,6 +94,8 @@ class MeasurementMapTool : public AbstractMapTool QgsGeometry existingVertices() const; void setExistingVertices( const QgsGeometry &vertices ); + void setMapSettings( InputMapSettings *newMapSettings ) override; + signals: void lengthWithGuidelineChanged( const double &lengthWithGuideline ); void perimeterChanged( const double &perimeter ); @@ -112,9 +114,6 @@ class MeasurementMapTool : public AbstractMapTool public slots: void updateDistance(); - private slots: - void onMapSettingsChanged( InputMapSettings *newMapSettings ); - private: QVector mPoints; QgsGeometry mRecordedGeometry; diff --git a/app/qml/components/MMDrawerHeader.qml b/app/qml/components/MMDrawerHeader.qml index 7750feb8a..b40c2ce1e 100644 --- a/app/qml/components/MMDrawerHeader.qml +++ b/app/qml/components/MMDrawerHeader.qml @@ -41,13 +41,18 @@ Rectangle { } Text { - // If the close button is visible, we need to properly center the text - property real margin: internal.closeBtnRealWidth + internal.headerSpacing + __style.pageMargins + property real leftMarginShift: { + return Math.max( internal.closeBtnRealWidth, topLeftButtonGroup.width ) + internal.headerSpacing + __style.pageMargins + } + + property real rightMarginShift: { + return Math.max( internal.closeBtnRealWidth, topLeftButtonGroup.width ) + internal.headerSpacing + __style.pageMargins + } anchors { fill: parent - leftMargin: margin - rightMargin: margin + leftMargin: leftMarginShift + rightMargin: rightMarginShift } text: root.title diff --git a/app/qml/gps/MMMeasureDrawer.qml b/app/qml/gps/MMMeasureDrawer.qml index 80102df85..014a4b999 100644 --- a/app/qml/gps/MMMeasureDrawer.qml +++ b/app/qml/gps/MMMeasureDrawer.qml @@ -30,8 +30,8 @@ MMDrawer { property bool closeShapeDone: mapCanvas.mapToolComponent?.mapTool?.closeShapeDone ?? false property bool canUndo: mapCanvas.mapToolComponent?.mapTool?.canUndo ?? false - property string perimeter: __inputUtils.formatDistanceInProjectUnit( mapCanvas.mapToolComponent?.mapTool?.perimeter ?? 0, 1 ) - property string area: __inputUtils.formatAreaInProjectUnit( mapCanvas.mapToolComponent?.mapTool?.area ?? 0, 1 ) + property string perimeter: __inputUtils.formatDistanceInProjectUnit( mapCanvas.mapToolComponent?.mapTool?.perimeter ?? 0, 1, __activeProject.qgsProject ) + property string area: __inputUtils.formatAreaInProjectUnit( mapCanvas.mapToolComponent?.mapTool?.area ?? 0, 1, __activeProject.qgsProject ) signal measureFinished() signal measureDone() diff --git a/app/qml/gps/MMStakeoutDrawer.qml b/app/qml/gps/MMStakeoutDrawer.qml index b1f6fd657..61f6ca354 100644 --- a/app/qml/gps/MMStakeoutDrawer.qml +++ b/app/qml/gps/MMStakeoutDrawer.qml @@ -109,7 +109,7 @@ MMDrawer { width: ( parent.width + parent.spacing ) / 2 title: qsTr( "Distance" ) - value: remainingDistance >= 0 ?__inputUtils.formatDistanceInProjectUnit( remainingDistance, 2 ) : qsTr( "N/A" ) + value: remainingDistance >= 0 ?__inputUtils.formatDistanceInProjectUnit( remainingDistance, 2, __activeProject.qgsProject ) : qsTr( "N/A" ) alignmentRight: true } } diff --git a/app/qml/map/MMMeasurementTools.qml b/app/qml/map/MMMeasurementTools.qml index 13c5a5dd1..e3591d487 100644 --- a/app/qml/map/MMMeasurementTools.qml +++ b/app/qml/map/MMMeasurementTools.qml @@ -91,7 +91,7 @@ Item { qgsProject: __activeProject.qgsProject mapSettings: root.map.mapSettings - text: __inputUtils.formatDistanceInProjectUnit( mapTool.lengthWithGuideline ) + text: __inputUtils.formatDistanceInProjectUnit( mapTool.lengthWithGuideline, __activeProject.qgsProject ) canCloseShape: mapTool.canCloseShape onCloseShapeClicked: closeShape() From 9c5856fabc96a1d7006536466b6ac2a1e8a56a97 Mon Sep 17 00:00:00 2001 From: VitorVieiraZ Date: Tue, 1 Oct 2024 12:01:41 -0300 Subject: [PATCH 40/60] fixing tests --- app/test/testutilsfunctions.cpp | 40 ++++++++++++++++----------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/app/test/testutilsfunctions.cpp b/app/test/testutilsfunctions.cpp index cb7687844..1fcbc8d95 100644 --- a/app/test/testutilsfunctions.cpp +++ b/app/test/testutilsfunctions.cpp @@ -858,66 +858,66 @@ void TestUtilsFunctions::testParsePositionUpdates() void TestUtilsFunctions::testFormatDistanceInDistanceUnit() { - QString dist2str = mUtils->formatDistanceInProjectUnit( 1222.234, 2, Qgis::DistanceUnit::Meters ); + QString dist2str = mUtils->formatDistanceInProjectUnit( 1222.234, 2, Qgis::DistanceUnit::Meters, QgsProject::instance() ); QVERIFY( dist2str == "1222.23 m" ); - dist2str = mUtils->formatDistanceInProjectUnit( 1222.234, 1, Qgis::DistanceUnit::Meters ); + dist2str = mUtils->formatDistanceInProjectUnit( 1222.234, 1, Qgis::DistanceUnit::Meters, QgsProject::instance() ); QVERIFY( dist2str == "1222.2 m" ); - dist2str = mUtils->formatDistanceInProjectUnit( 1222.234, 0, Qgis::DistanceUnit::Meters ); + dist2str = mUtils->formatDistanceInProjectUnit( 1222.234, 0, Qgis::DistanceUnit::Meters, QgsProject::instance() ); QVERIFY( dist2str == "1222 m" ); - dist2str = mUtils->formatDistanceInProjectUnit( 700.22, 1, Qgis::DistanceUnit::Meters ); + dist2str = mUtils->formatDistanceInProjectUnit( 700.22, 1, Qgis::DistanceUnit::Meters, QgsProject::instance() ); QVERIFY( dist2str == "700.2 m" ); - dist2str = mUtils->formatDistanceInProjectUnit( 0.22, 0, Qgis::DistanceUnit::Meters ); + dist2str = mUtils->formatDistanceInProjectUnit( 0.22, 0, Qgis::DistanceUnit::Meters, QgsProject::instance() ); QVERIFY( dist2str == "0 m" ); - dist2str = mUtils->formatDistanceInProjectUnit( -0.22, 0, Qgis::DistanceUnit::Meters ); + dist2str = mUtils->formatDistanceInProjectUnit( -0.22, 0, Qgis::DistanceUnit::Meters, QgsProject::instance() ); QVERIFY( dist2str == "-0 m" ); - dist2str = mUtils->formatDistanceInProjectUnit( 1.222234, 2, Qgis::DistanceUnit::Kilometers ); + dist2str = mUtils->formatDistanceInProjectUnit( 1.222234, 2, Qgis::DistanceUnit::Kilometers, QgsProject::instance() ); QVERIFY( dist2str == "0.00 km" ); - dist2str = mUtils->formatDistanceInProjectUnit( 6000, 1, Qgis::DistanceUnit::Feet ); + dist2str = mUtils->formatDistanceInProjectUnit( 6000, 1, Qgis::DistanceUnit::Feet, QgsProject::instance() ); QVERIFY( dist2str == "19685.0 ft" ); - dist2str = mUtils->formatDistanceInProjectUnit( 5, 1, Qgis::DistanceUnit::Feet ); + dist2str = mUtils->formatDistanceInProjectUnit( 5, 1, Qgis::DistanceUnit::Feet, QgsProject::instance() ); QVERIFY( dist2str == "16.4 ft" ); - dist2str = mUtils->formatDistanceInProjectUnit( 7000, 1, Qgis::DistanceUnit::Feet ); + dist2str = mUtils->formatDistanceInProjectUnit( 7000, 1, Qgis::DistanceUnit::Feet, QgsProject::instance() ); QVERIFY( dist2str == "22965.9 ft" ); } void TestUtilsFunctions::testFormatAreaInProjectUnit() { - QString area2str = mUtils->formatAreaInProjectUnit( 1500.234, 2, Qgis::AreaUnit::SquareMeters ); + QString area2str = mUtils->formatAreaInProjectUnit( 1500.234, 2, Qgis::AreaUnit::SquareMeters, QgsProject::instance() ); QVERIFY( area2str == "1500.23 m²" ); - area2str = mUtils->formatAreaInProjectUnit( 1500.234, 1, Qgis::AreaUnit::SquareMeters ); + area2str = mUtils->formatAreaInProjectUnit( 1500.234, 1, Qgis::AreaUnit::SquareMeters, QgsProject::instance() ); QVERIFY( area2str == "1500.2 m²" ); - area2str = mUtils->formatAreaInProjectUnit( 1500.234, 0, Qgis::AreaUnit::SquareMeters ); + area2str = mUtils->formatAreaInProjectUnit( 1500.234, 0, Qgis::AreaUnit::SquareMeters, QgsProject::instance() ); QVERIFY( area2str == "1500 m²" ); - area2str = mUtils->formatAreaInProjectUnit( 500.22, 1, Qgis::AreaUnit::SquareMeters ); + area2str = mUtils->formatAreaInProjectUnit( 500.22, 1, Qgis::AreaUnit::SquareMeters, QgsProject::instance() ); QVERIFY( area2str == "500.2 m²" ); - area2str = mUtils->formatAreaInProjectUnit( 0.22, 0, Qgis::AreaUnit::SquareMeters ); + area2str = mUtils->formatAreaInProjectUnit( 0.22, 0, Qgis::AreaUnit::SquareMeters, QgsProject::instance() ); QVERIFY( area2str == "0 m²" ); - area2str = mUtils->formatAreaInProjectUnit( -0.22, 0, Qgis::AreaUnit::SquareMeters ); + area2str = mUtils->formatAreaInProjectUnit( -0.22, 0, Qgis::AreaUnit::SquareMeters, QgsProject::instance() ); QVERIFY( area2str == "-0 m²" ); - area2str = mUtils->formatAreaInProjectUnit( 1.222234, 2, Qgis::AreaUnit::SquareKilometers ); + area2str = mUtils->formatAreaInProjectUnit( 1.222234, 2, Qgis::AreaUnit::SquareKilometers, QgsProject::instance() ); QVERIFY( area2str == "0.00 km²" ); - area2str = mUtils->formatAreaInProjectUnit( 6000, 1, Qgis::AreaUnit::Acres ); + area2str = mUtils->formatAreaInProjectUnit( 6000, 1, Qgis::AreaUnit::Acres, QgsProject::instance() ); QVERIFY( area2str == "1.5 ac" ); - area2str = mUtils->formatAreaInProjectUnit( 5, 1, Qgis::AreaUnit::Acres ); + area2str = mUtils->formatAreaInProjectUnit( 5, 1, Qgis::AreaUnit::Acres, QgsProject::instance() ); QVERIFY( area2str == "0.0 ac" ); - area2str = mUtils->formatAreaInProjectUnit( 7000, 1, Qgis::AreaUnit::Acres ); + area2str = mUtils->formatAreaInProjectUnit( 7000, 1, Qgis::AreaUnit::Acres, QgsProject::instance() ); QVERIFY( area2str == "1.7 ac" ); } From 0ca29c74d6d5b00b7184aa4be5c6afaf11d32b6a Mon Sep 17 00:00:00 2001 From: VitorVieiraZ Date: Tue, 1 Oct 2024 14:32:40 -0300 Subject: [PATCH 41/60] handling done button functionality --- app/maptools/measurementmaptool.cpp | 73 +++++++++++++++++++---------- app/maptools/measurementmaptool.h | 18 ++++--- app/qml/gps/MMMeasureDrawer.qml | 28 ++++++----- app/qml/main.qml | 3 +- app/qml/map/MMMeasurementTools.qml | 6 +-- 5 files changed, 79 insertions(+), 49 deletions(-) diff --git a/app/maptools/measurementmaptool.cpp b/app/maptools/measurementmaptool.cpp index 89c9b1fba..56eea147a 100644 --- a/app/maptools/measurementmaptool.cpp +++ b/app/maptools/measurementmaptool.cpp @@ -53,41 +53,49 @@ void MeasurementMapTool::updateDistance() void MeasurementMapTool::checkCanCloseShape() { - if ( mRecordedGeometry.isEmpty() || mPoints.count() < 3 || !mapSettings() ) + bool canFinalize = !mRecordedGeometry.isEmpty() && mapSettings() && mPoints.count() >= 2; + setCanFinalizeMeasurement( canFinalize ); + + if ( !canFinalize || mPoints.count() < 3 ) { setCanCloseShape( false ); return; } - else - { - QgsPoint firstPoint = mPoints.first(); - QPointF firstPointScreen = mapSettings()->coordinateToScreen( firstPoint ); - double distanceToFirstPoint = InputUtils::pixelDistanceBetween( mCrosshairPoint, firstPointScreen ); - setCanCloseShape( distanceToFirstPoint <= CLOSE_THRESHOLD ); - } + QgsPoint firstPoint = mPoints.first(); + QPointF firstPointScreen = mapSettings()->coordinateToScreen( firstPoint ); + double distanceToFirstPoint = InputUtils::pixelDistanceBetween( mCrosshairPoint, firstPointScreen ); + setCanCloseShape( distanceToFirstPoint <= CLOSE_THRESHOLD ); } -void MeasurementMapTool::closeShape() +void MeasurementMapTool::finalizeMeasurement( bool closeShapeClicked ) { - if ( mPoints.count() < 3 ) + if ( mPoints.count() < 2 ) return; QList pointList; for ( const QgsPoint &point : mPoints ) pointList.append( QgsPointXY( point.x(), point.y() ) ); - QgsGeometry polygonGeometry = QgsGeometry::fromPolygonXY( QList>() << pointList ); - setRecordedGeometry( polygonGeometry ); + QgsGeometry geometry; + double perimeter = 0.0; - double area = mDistanceArea.measureArea( polygonGeometry ); - setArea( area ); + if ( closeShapeClicked && mCanCloseShape && mPoints.count() >= 3 ) + { + geometry = QgsGeometry::fromPolygonXY( QList>() << pointList ); + perimeter = mDistanceArea.measurePerimeter( geometry ); + setArea( mDistanceArea.measureArea( geometry ) ); + setCanCloseShape( false ); + } + else + { + geometry = QgsGeometry::fromPolylineXY( pointList ); + perimeter = mDistanceArea.measureLength( geometry ); + } - double perimeter = mDistanceArea.measurePerimeter( polygonGeometry ); + setRecordedGeometry( geometry ); setPerimeter( perimeter ); - - setCanCloseShape( false ); - setCloseShapeDone( true ); + setMeasurementFinalized( true ); } void MeasurementMapTool::resetMeasurement() @@ -95,9 +103,10 @@ void MeasurementMapTool::resetMeasurement() mPoints.clear(); setPerimeter( 0.0 ); + setArea( 0.0 ); setLengthWithGuideline( 0.0 ); setCanCloseShape( false ); - setCloseShapeDone( false ); + setMeasurementFinalized( false ); rebuildGeometry(); } @@ -220,18 +229,32 @@ void MeasurementMapTool::setCanCloseShape( bool newCanCloseShape ) emit canCloseShapeChanged( mCanCloseShape ); } -bool MeasurementMapTool::closeShapeDone() const +bool MeasurementMapTool::canFinalizeMeasurement() const +{ + return mCanFinalizeMeasurement; +} + +void MeasurementMapTool::setCanFinalizeMeasurement( bool canFinalize ) +{ + if ( mCanFinalizeMeasurement != canFinalize ) + { + mCanFinalizeMeasurement = canFinalize; + emit canFinalizeMeasurementChanged( canFinalize ); + } +} + +bool MeasurementMapTool::measurementFinalized() const { - return mCloseShapeDone; + return mMeasurementFinalized; } -void MeasurementMapTool::setCloseShapeDone( bool newCloseShapeDone ) +void MeasurementMapTool::setMeasurementFinalized( bool newMeasurementFinalized ) { - if ( mCloseShapeDone == newCloseShapeDone ) + if ( mMeasurementFinalized == newMeasurementFinalized ) return; - mCloseShapeDone = newCloseShapeDone; - emit closeShapeDoneChanged( mCloseShapeDone ); + mMeasurementFinalized = newMeasurementFinalized; + emit measurementFinalizedChanged( mMeasurementFinalized ); } void MeasurementMapTool::setRecordedGeometry( const QgsGeometry &newRecordedGeometry ) diff --git a/app/maptools/measurementmaptool.h b/app/maptools/measurementmaptool.h index 3f87a0b67..0e07949af 100644 --- a/app/maptools/measurementmaptool.h +++ b/app/maptools/measurementmaptool.h @@ -36,7 +36,8 @@ class MeasurementMapTool : public AbstractMapTool Q_PROPERTY( bool canUndo READ canUndo WRITE setCanUndo NOTIFY canUndoChanged ) Q_PROPERTY( bool canCloseShape READ canCloseShape WRITE setCanCloseShape NOTIFY canCloseShapeChanged ) - Q_PROPERTY( bool closeShapeDone READ closeShapeDone WRITE setCloseShapeDone NOTIFY closeShapeDoneChanged ) + Q_PROPERTY( bool canFinalizeMeasurement READ canFinalizeMeasurement WRITE setCanFinalizeMeasurement NOTIFY canFinalizeMeasurementChanged ) + Q_PROPERTY( bool measurementFinalized READ measurementFinalized WRITE setMeasurementFinalized NOTIFY measurementFinalizedChanged ) public: explicit MeasurementMapTool( QObject *parent = nullptr ); @@ -58,7 +59,7 @@ class MeasurementMapTool : public AbstractMapTool * If there are at least 3 points, forms a polygon from recorded points so far. * Updates recorded geometry and calculates area and perimeter of formed polygon. */ - Q_INVOKABLE void closeShape(); + Q_INVOKABLE void finalizeMeasurement( bool closeShapeClicked ); /** * Repeats measurement process. @@ -85,8 +86,11 @@ class MeasurementMapTool : public AbstractMapTool bool canCloseShape() const; void setCanCloseShape( bool newCanCloseShape ); - bool closeShapeDone() const; - void setCloseShapeDone( bool newCloseShapeDone ); + bool canFinalizeMeasurement() const; + void setCanFinalizeMeasurement( bool canFinalize ); + + bool measurementFinalized() const; + void setMeasurementFinalized( bool newMeasurementFinalized ); const QgsGeometry &recordedGeometry() const; void setRecordedGeometry( const QgsGeometry &newRecordedGeometry ); @@ -102,10 +106,11 @@ class MeasurementMapTool : public AbstractMapTool void areaChanged( const double &area ); void canUndoChanged( bool canUndo ); void canCloseShapeChanged( bool canUndo ); - void closeShapeDoneChanged( bool canUndo ); + void measurementFinalizedChanged( bool measurementFinalized ); void recordedGeometryChanged( const QgsGeometry &recordedGeometry ); void existingVerticesChanged( const QgsGeometry &vertices ); void crosshairPointChanged( const QPointF &crosshairPoint ); + void canFinalizeMeasurementChanged( bool canFinalize ); protected: void rebuildGeometry(); @@ -125,7 +130,8 @@ class MeasurementMapTool : public AbstractMapTool double mArea = 0; bool mCanUndo = false; bool mCanCloseShape = false; - bool mCloseShapeDone = false; + bool mCanFinalizeMeasurement = false; + bool mMeasurementFinalized = false; }; #endif // MEASUREMENTMAPTOOL_H diff --git a/app/qml/gps/MMMeasureDrawer.qml b/app/qml/gps/MMMeasureDrawer.qml index 014a4b999..a655b7d79 100644 --- a/app/qml/gps/MMMeasureDrawer.qml +++ b/app/qml/gps/MMMeasureDrawer.qml @@ -27,11 +27,12 @@ MMDrawer { readonly property alias panelHeight: root.height property bool canCloseShape: mapCanvas.mapToolComponent?.mapTool?.canCloseShape ?? false - property bool closeShapeDone: mapCanvas.mapToolComponent?.mapTool?.closeShapeDone ?? false property bool canUndo: mapCanvas.mapToolComponent?.mapTool?.canUndo ?? false + property bool canFinalizeMeasurement: mapCanvas.mapToolComponent?.mapTool?.canFinalizeMeasurement ?? false + property bool measurementFinalized: mapCanvas.mapToolComponent?.mapTool?.measurementFinalized ?? false - property string perimeter: __inputUtils.formatDistanceInProjectUnit( mapCanvas.mapToolComponent?.mapTool?.perimeter ?? 0, 1, __activeProject.qgsProject ) - property string area: __inputUtils.formatAreaInProjectUnit( mapCanvas.mapToolComponent?.mapTool?.area ?? 0, 1, __activeProject.qgsProject ) + property string perimeter: mapCanvas.mapToolComponent?.mapTool?.perimeter ?? 0 + property string area: mapCanvas.mapToolComponent?.mapTool?.area ?? 0 signal measureFinished() signal measureDone() @@ -54,11 +55,11 @@ MMDrawer { drawerHeader.topLeftItemContent: MMButton { type: MMButton.Types.Primary - text: closeShapeDone ? qsTr( "Repeat" ) : qsTr( "Undo" ) - iconSourceLeft: closeShapeDone ? __style.syncIcon : __style.undoIcon + text: measurementFinalized ? qsTr( "Repeat" ) : qsTr( "Undo" ) + iconSourceLeft: measurementFinalized ? __style.syncIcon : __style.undoIcon bgndColor: __style.lightGreenColor size: MMButton.Sizes.Small - enabled: closeShapeDone || canUndo + enabled: measurementFinalized || canUndo anchors { left: parent.left @@ -66,7 +67,7 @@ MMDrawer { verticalCenter: parent.verticalCenter } - onClicked: closeShapeDone ? root.mapCanvas.mapToolComponent.repeatMeasure() : root.mapCanvas.mapToolComponent.mapTool.removePoint() + onClicked: measurementFinalized ? root.mapCanvas.mapToolComponent.repeatMeasure() : root.mapCanvas.mapToolComponent.mapTool.removePoint() } drawerContent: Column { @@ -81,35 +82,36 @@ MMDrawer { MMGpsComponents.MMGpsDataText{ width: ( parent.width + parent.spacing ) / 2 - title: closeShapeDone ? qsTr( "Perimeter" ) : qsTr( "Length" ) - value: root.perimeter + title: measurementFinalized ? qsTr( "Perimeter" ) : qsTr( "Length" ) + value: __inputUtils.formatDistanceInProjectUnit( root.perimeter, 1, __activeProject.qgsProject ) } MMGpsComponents.MMGpsDataText{ width: ( parent.width + parent.spacing ) / 2 title: qsTr( "Area" ) - value: root.area + value: __inputUtils.formatAreaInProjectUnit( root.area, 1, __activeProject.qgsProject ) alignmentRight: true - visible: closeShapeDone + visible: measurementFinalized && root.area > 0 } } Row { width: parent.width spacing: __style.margin12 - visible: !root.closeShapeDone + visible: !root.measurementFinalized MMButton { text: root.canCloseShape ? qsTr( "Close shape" ) : qsTr( "Add point" ) iconSourceLeft: canCloseShape ? __style.closeShapeIcon : __style.plusIcon - onClicked: canCloseShape ? root.mapCanvas.mapToolComponent.closeShape() : root.mapCanvas.mapToolComponent.mapTool.addPoint() + onClicked: canCloseShape ? root.mapCanvas.mapToolComponent.finalizeMeasurement( true ) : root.mapCanvas.mapToolComponent.mapTool.addPoint() } MMButton { type: MMButton.Types.Secondary text: qsTr( "Done" ) iconSourceLeft: __style.doneCircleIcon + enabled: root.canFinalizeMeasurement onClicked: root.measureDone() } } diff --git a/app/qml/main.qml b/app/qml/main.qml index 569c11de2..40ed9d314 100644 --- a/app/qml/main.qml +++ b/app/qml/main.qml @@ -777,8 +777,7 @@ ApplicationWindow { id: finishMeasurementDialog onFinishMeasurementRequested: { - measurePanelLoader.active = false - map.finishMeasure() + map.mapToolComponent.finalizeMeasurement( false ) } } diff --git a/app/qml/map/MMMeasurementTools.qml b/app/qml/map/MMMeasurementTools.qml index e3591d487..2ec5dd274 100644 --- a/app/qml/map/MMMeasurementTools.qml +++ b/app/qml/map/MMMeasurementTools.qml @@ -94,14 +94,14 @@ Item { text: __inputUtils.formatDistanceInProjectUnit( mapTool.lengthWithGuideline, __activeProject.qgsProject ) canCloseShape: mapTool.canCloseShape - onCloseShapeClicked: closeShape() + onCloseShapeClicked: finalizeMeasurement( true ) } - function closeShape() + function finalizeMeasurement( closeShapeClicked ) { guidelineController.allowed = false crosshair.visible = false - mapTool.closeShape() + mapTool.finalizeMeasurement( closeShapeClicked ) } function repeatMeasure() From 32aeb20524e0bb78f002fde4b8c6f002cafd4105 Mon Sep 17 00:00:00 2001 From: VitorVieiraZ Date: Wed, 2 Oct 2024 10:13:09 -0300 Subject: [PATCH 42/60] fixing ci --- app/maptools/abstractmaptool.cpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/app/maptools/abstractmaptool.cpp b/app/maptools/abstractmaptool.cpp index 19d5fb129..899e781d9 100644 --- a/app/maptools/abstractmaptool.cpp +++ b/app/maptools/abstractmaptool.cpp @@ -25,13 +25,7 @@ InputMapSettings *AbstractMapTool::mapSettings() const void AbstractMapTool::setMapSettings( InputMapSettings *newMapSettings ) { if ( mMapSettings == newMapSettings ) - { return; - } - else - { - disconnect( mMapSettings ); - } mMapSettings = newMapSettings; emit mapSettingsChanged( mMapSettings ); From 15c4bb40ef8cdedc7b1c3c8932cfb809893366dd Mon Sep 17 00:00:00 2001 From: VitorVieiraZ Date: Wed, 2 Oct 2024 11:03:32 -0300 Subject: [PATCH 43/60] updating finalizeMeasurement header description --- app/maptools/measurementmaptool.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/app/maptools/measurementmaptool.h b/app/maptools/measurementmaptool.h index 0e07949af..b0cff4bd5 100644 --- a/app/maptools/measurementmaptool.h +++ b/app/maptools/measurementmaptool.h @@ -59,6 +59,12 @@ class MeasurementMapTool : public AbstractMapTool * If there are at least 3 points, forms a polygon from recorded points so far. * Updates recorded geometry and calculates area and perimeter of formed polygon. */ + + /** + * Finalizes measurement by forming a polygon if "Close shape" button was clicked + * and there are at least 3 points; otherwise, if "Done" button was clicked, forms a polyline. + * Updates recorded geometry, calculates perimeter, and calculates the area if it's a polygon. + */ Q_INVOKABLE void finalizeMeasurement( bool closeShapeClicked ); /** From 9e196f7cb2a2704d59836ea1015203828019e93f Mon Sep 17 00:00:00 2001 From: VitorVieiraZ Date: Thu, 3 Oct 2024 09:02:32 -0300 Subject: [PATCH 44/60] adding measurement tool tests --- app/test/testmaptools.cpp | 82 +++++++++++++++++++++++++++++++++++++++ app/test/testmaptools.h | 1 + 2 files changed, 83 insertions(+) diff --git a/app/test/testmaptools.cpp b/app/test/testmaptools.cpp index 3b359a399..75c868d7d 100644 --- a/app/test/testmaptools.cpp +++ b/app/test/testmaptools.cpp @@ -29,6 +29,7 @@ #include "snaputils.h" #include "maptools/splittingmaptool.h" #include "maptools/recordingmaptool.h" +#include "maptools/measurementmaptool.h" #include "featurelayerpair.h" #include "streamingintervaltype.h" @@ -276,6 +277,87 @@ void TestMapTools::testRecording() delete recordTool; } +void TestMapTools::testMeasuring() +{ + MeasurementMapTool *measurementTool = new MeasurementMapTool(); + + InputMapCanvasMap canvas; + InputMapSettings *ms = canvas.mapSettings(); + + QgsProject *project = TestUtils::loadPlanesTestProject(); + QVERIFY( project && !project->homePath().isEmpty() ); + + setupMapSettings( ms, project, QgsRectangle( -10, -10, 10, 10 ), QSize( 600, 600 ) ); + + measurementTool->setMapSettings( ms ); + + QgsDistanceArea distanceArea; + distanceArea.setEllipsoid( QStringLiteral( "WGS84" ) ); + distanceArea.setSourceCrs( ms->destinationCrs(), ms->transformContext() ); + + QPointF crosshairPoint1 = ms->coordinateToScreen( QgsPoint( 0, 0 ) ); + measurementTool->setCrosshairPoint( crosshairPoint1 ); + measurementTool->addPoint(); + + measurementTool->updateDistance(); + QCOMPARE( measurementTool->lengthWithGuideline(), 0.0 ); + + QPointF crosshairPoint2 = ms->coordinateToScreen( QgsPoint( 0, 1 ) ); + measurementTool->setCrosshairPoint( crosshairPoint2 ); + measurementTool->addPoint(); + + measurementTool->updateDistance(); + + QList points; + points.append( QgsPointXY( 0, 0 ) ); + points.append( QgsPointXY( 0, 1 ) ); + + QgsGeometry lineGeometry = QgsGeometry::fromPolylineXY( points ); + double expectedPerimeter = distanceArea.measureLength( lineGeometry ); + QCOMPARE( measurementTool->perimeter(), expectedPerimeter ); + + QPointF crosshairPoint3 = ms->coordinateToScreen( QgsPoint( 1, 1 ) ); + measurementTool->setCrosshairPoint( crosshairPoint3 ); + measurementTool->addPoint(); + + measurementTool->updateDistance(); + points.append( QgsPointXY( 1, 1 ) ); + lineGeometry = QgsGeometry::fromPolylineXY( points ); + expectedPerimeter = distanceArea.measureLength( lineGeometry ); + QCOMPARE( measurementTool->perimeter(), expectedPerimeter ); + + measurementTool->finalizeMeasurement( false ); + + QVERIFY( measurementTool->recordedGeometry().wkbType() == Qgis::WkbType::LineString ); + + measurementTool->resetMeasurement(); + + measurementTool->setCrosshairPoint( crosshairPoint1 ); + measurementTool->addPoint(); + + measurementTool->setCrosshairPoint( crosshairPoint2 ); + measurementTool->addPoint(); + + measurementTool->setCrosshairPoint( crosshairPoint3 ); + measurementTool->addPoint(); + + measurementTool->setCrosshairPoint( crosshairPoint1 ); + measurementTool->updateDistance(); + + QVERIFY( measurementTool->canCloseShape() ); + + measurementTool->finalizeMeasurement( true ); + + QVERIFY( measurementTool->recordedGeometry().wkbType() == Qgis::WkbType::Polygon ); + + QgsGeometry polygonGeometry = QgsGeometry::fromPolygonXY( QList>() << points ); + double expectedArea = distanceArea.measureArea( polygonGeometry ); + QCOMPARE( measurementTool->area(), expectedArea ); + + delete project; + delete measurementTool; +} + void TestMapTools::testExistingVertices() { RecordingMapTool mapTool; diff --git a/app/test/testmaptools.h b/app/test/testmaptools.h index deb24e0c4..e06c748aa 100644 --- a/app/test/testmaptools.h +++ b/app/test/testmaptools.h @@ -29,6 +29,7 @@ class TestMapTools : public QObject void testSnapping(); void testSplitting(); void testRecording(); + void testMeasuring(); void testExistingVertices(); void testMidSegmentVertices(); From ff5c5c72b81096ee37cbb6ef90dcc26a28b9d4f1 Mon Sep 17 00:00:00 2001 From: VitorVieiraZ Date: Fri, 4 Oct 2024 11:57:02 -0300 Subject: [PATCH 45/60] adjust ci to produce aab --- .github/workflows/android.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/android.yml b/.github/workflows/android.yml index 2f29ad786..47b162cb6 100644 --- a/.github/workflows/android.yml +++ b/.github/workflows/android.yml @@ -272,7 +272,7 @@ jobs: name: Mergin Maps ${{ env.INPUT_VERSION_CODE }} APK [v7 + v8a] - name: build AAB - if: ${{ github.ref_name == 'master' || github.ref_type == 'tag' }} + if: ${{ github.ref_name == 'master' || github.ref_name == 'enhancement/measurementTool' || github.ref_type == 'tag' }} env: ANDROID_NDK_ROOT: ${{ steps.setup-ndk.outputs.ndk-path }} ANDROID_NDK_HOST: darwin-x86_64 From 00db84ed46f72484f52a5bf54036fb79f6dc9c50 Mon Sep 17 00:00:00 2001 From: VitorVieiraZ Date: Fri, 4 Oct 2024 13:13:18 -0300 Subject: [PATCH 46/60] fixing aab producing ci --- .github/workflows/android.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.github/workflows/android.yml b/.github/workflows/android.yml index 47b162cb6..69e172ede 100644 --- a/.github/workflows/android.yml +++ b/.github/workflows/android.yml @@ -272,7 +272,6 @@ jobs: name: Mergin Maps ${{ env.INPUT_VERSION_CODE }} APK [v7 + v8a] - name: build AAB - if: ${{ github.ref_name == 'master' || github.ref_name == 'enhancement/measurementTool' || github.ref_type == 'tag' }} env: ANDROID_NDK_ROOT: ${{ steps.setup-ndk.outputs.ndk-path }} ANDROID_NDK_HOST: darwin-x86_64 @@ -286,14 +285,12 @@ jobs: find . | grep .aab - name: Rename AAB artefacts - if: ${{ github.ref_name == 'master' || github.ref_type == 'tag' }} run: | mv \ ${{ github.workspace }}/build-Input/app/android-build/build/outputs/bundle/release/android-build-release.aab \ ${{ github.workspace }}/merginmaps-${{ env.INPUT_VERSION_CODE }}.aab - name: Upload AAB to Artifacts - if: ${{ github.ref_name == 'master' || github.ref_type == 'tag' }} uses: actions/upload-artifact@v3 with: path: ${{ github.workspace }}/merginmaps-${{ env.INPUT_VERSION_CODE }}.aab From 146e13fb571f9baa43fd0d76c5f35f357480e9cc Mon Sep 17 00:00:00 2001 From: VitorVieiraZ Date: Fri, 4 Oct 2024 19:21:39 -0300 Subject: [PATCH 47/60] smaller version of drawer title --- app/qml/gps/MMMeasureDrawer.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/qml/gps/MMMeasureDrawer.qml b/app/qml/gps/MMMeasureDrawer.qml index a655b7d79..91a966ae9 100644 --- a/app/qml/gps/MMMeasureDrawer.qml +++ b/app/qml/gps/MMMeasureDrawer.qml @@ -51,7 +51,7 @@ MMDrawer { PropertyAnimation { properties: "implicitHeight"; easing.type: Easing.InOutQuad } } - drawerHeader.title: qsTr( "Measurement" ) + drawerHeader.title: qsTr( "Measure" ) drawerHeader.topLeftItemContent: MMButton { type: MMButton.Types.Primary From 6f14f69cb0fcc930096b76e6474e91844bf1b049 Mon Sep 17 00:00:00 2001 From: VitorVieiraZ Date: Mon, 7 Oct 2024 15:34:19 -0300 Subject: [PATCH 48/60] post review changes --- app/maptools/abstractmaptool.cpp | 3 ++ app/maptools/abstractmaptool.h | 4 +- app/maptools/measurementmaptool.cpp | 52 ++++++++++++------- app/maptools/measurementmaptool.h | 18 +++---- app/qml/gps/MMMeasureDrawer.qml | 3 +- app/qml/main.qml | 10 ---- app/qml/map/MMMapController.qml | 2 - app/qml/map/components/MMMeasureCrosshair.qml | 2 +- 8 files changed, 46 insertions(+), 48 deletions(-) diff --git a/app/maptools/abstractmaptool.cpp b/app/maptools/abstractmaptool.cpp index 899e781d9..ee81f1dc0 100644 --- a/app/maptools/abstractmaptool.cpp +++ b/app/maptools/abstractmaptool.cpp @@ -27,6 +27,9 @@ void AbstractMapTool::setMapSettings( InputMapSettings *newMapSettings ) if ( mMapSettings == newMapSettings ) return; + emit onAboutToChangeMapSettings(); + mMapSettings = newMapSettings; + emit mapSettingsChanged( mMapSettings ); } diff --git a/app/maptools/abstractmaptool.h b/app/maptools/abstractmaptool.h index 4ed41fccd..e6eba3532 100644 --- a/app/maptools/abstractmaptool.h +++ b/app/maptools/abstractmaptool.h @@ -27,10 +27,10 @@ class AbstractMapTool : public QObject virtual ~AbstractMapTool(); InputMapSettings *mapSettings() const; - virtual void setMapSettings( InputMapSettings *newMapSettings ); + void setMapSettings( InputMapSettings *newMapSettings ); signals: - + void onAboutToChangeMapSettings(); void mapSettingsChanged( InputMapSettings *mapSettings ); private: diff --git a/app/maptools/measurementmaptool.cpp b/app/maptools/measurementmaptool.cpp index 56eea147a..0b66baae8 100644 --- a/app/maptools/measurementmaptool.cpp +++ b/app/maptools/measurementmaptool.cpp @@ -12,31 +12,36 @@ MeasurementMapTool::MeasurementMapTool( QObject *parent ) : AbstractMapTool{ parent } { - connect( this, &AbstractMapTool::mapSettingsChanged, this, &MeasurementMapTool::setMapSettings ); + connect( this, &AbstractMapTool::onAboutToChangeMapSettings, this, &MeasurementMapTool::resetMapSettings ); + connect( this, &AbstractMapTool::mapSettingsChanged, this, &MeasurementMapTool::updateMapSettings ); } MeasurementMapTool::~MeasurementMapTool() = default; void MeasurementMapTool::addPoint() { - QgsPoint transformedPoint = mapSettings()->screenToCoordinate( mCrosshairPoint ); - mPoints.push_back( transformedPoint ); - rebuildGeometry(); + if ( mapSettings() ) + { + QgsPoint transformedPoint = mapSettings()->screenToCoordinate( mCrosshairPoint ); + mPoints.push_back( transformedPoint ); + rebuildGeometry(); + } } void MeasurementMapTool::removePoint() { - if ( !mPoints.isEmpty() ) + if ( !mPoints.isEmpty() && mapSettings() ) { mPoints.pop_back(); checkCanCloseShape(); rebuildGeometry(); + updateDistance(); } } void MeasurementMapTool::updateDistance() { - if ( mPoints.isEmpty() ) + if ( mPoints.isEmpty() || !mapSettings() ) { setLengthWithGuideline( 0.0 ); return; @@ -47,16 +52,13 @@ void MeasurementMapTool::updateDistance() QgsPoint lastPoint = mPoints.last(); QgsPoint transformedCrosshairPoint = mapSettings()->screenToCoordinate( mCrosshairPoint ); - double calculatedLength = mDistanceArea.measureLength( mRecordedGeometry ) + mDistanceArea.measureLine( transformedCrosshairPoint, lastPoint ); + double calculatedLength = mPerimeter + mDistanceArea.measureLine( transformedCrosshairPoint, lastPoint ); setLengthWithGuideline( calculatedLength ); } void MeasurementMapTool::checkCanCloseShape() { - bool canFinalize = !mRecordedGeometry.isEmpty() && mapSettings() && mPoints.count() >= 2; - setCanFinalizeMeasurement( canFinalize ); - - if ( !canFinalize || mPoints.count() < 3 ) + if ( !mRecordedGeometry.isEmpty() && mapSettings() && mPoints.count() < 3 ) { setCanCloseShape( false ); return; @@ -70,7 +72,7 @@ void MeasurementMapTool::checkCanCloseShape() void MeasurementMapTool::finalizeMeasurement( bool closeShapeClicked ) { - if ( mPoints.count() < 2 ) + if ( mPoints.count() < 2 || !mapSettings() ) return; QList pointList; @@ -80,7 +82,7 @@ void MeasurementMapTool::finalizeMeasurement( bool closeShapeClicked ) QgsGeometry geometry; double perimeter = 0.0; - if ( closeShapeClicked && mCanCloseShape && mPoints.count() >= 3 ) + if ( closeShapeClicked && mCanCloseShape ) { geometry = QgsGeometry::fromPolygonXY( QList>() << pointList ); perimeter = mDistanceArea.measurePerimeter( geometry ); @@ -113,6 +115,9 @@ void MeasurementMapTool::resetMeasurement() void MeasurementMapTool::rebuildGeometry() { + if ( !mapSettings() ) + return; + QgsGeometry geometry; QgsMultiPoint *existingVertices = new QgsMultiPoint(); @@ -136,11 +141,15 @@ void MeasurementMapTool::rebuildGeometry() setCanUndo( false ); } + // If we have more two or more points, "Done" button will be enabled + bool hasValidGeometry = !mRecordedGeometry.isEmpty() && mPoints.count() >= 2; + setIsValidGeometry( hasValidGeometry ); + emit existingVerticesChanged( mExistingVertices ); setRecordedGeometry( geometry ); } -void MeasurementMapTool::setMapSettings( InputMapSettings *newMapSettings ) +void MeasurementMapTool::resetMapSettings() { InputMapSettings *currentMapSettings = mapSettings(); @@ -148,7 +157,10 @@ void MeasurementMapTool::setMapSettings( InputMapSettings *newMapSettings ) { disconnect( currentMapSettings ); } +} +void MeasurementMapTool::updateMapSettings( InputMapSettings *newMapSettings ) +{ AbstractMapTool::setMapSettings( newMapSettings ); InputMapSettings *updatedMapSettings = mapSettings(); @@ -229,17 +241,17 @@ void MeasurementMapTool::setCanCloseShape( bool newCanCloseShape ) emit canCloseShapeChanged( mCanCloseShape ); } -bool MeasurementMapTool::canFinalizeMeasurement() const +bool MeasurementMapTool::isValidGeometry() const { - return mCanFinalizeMeasurement; + return mIsValidGeometry; } -void MeasurementMapTool::setCanFinalizeMeasurement( bool canFinalize ) +void MeasurementMapTool::setIsValidGeometry( bool hasValidGeometry ) { - if ( mCanFinalizeMeasurement != canFinalize ) + if ( mIsValidGeometry != hasValidGeometry ) { - mCanFinalizeMeasurement = canFinalize; - emit canFinalizeMeasurementChanged( canFinalize ); + mIsValidGeometry = hasValidGeometry; + emit isValidGeometryChanged( hasValidGeometry ); } } diff --git a/app/maptools/measurementmaptool.h b/app/maptools/measurementmaptool.h index b0cff4bd5..0393fd029 100644 --- a/app/maptools/measurementmaptool.h +++ b/app/maptools/measurementmaptool.h @@ -36,7 +36,7 @@ class MeasurementMapTool : public AbstractMapTool Q_PROPERTY( bool canUndo READ canUndo WRITE setCanUndo NOTIFY canUndoChanged ) Q_PROPERTY( bool canCloseShape READ canCloseShape WRITE setCanCloseShape NOTIFY canCloseShapeChanged ) - Q_PROPERTY( bool canFinalizeMeasurement READ canFinalizeMeasurement WRITE setCanFinalizeMeasurement NOTIFY canFinalizeMeasurementChanged ) + Q_PROPERTY( bool isValidGeometry READ isValidGeometry WRITE setIsValidGeometry NOTIFY isValidGeometryChanged ) Q_PROPERTY( bool measurementFinalized READ measurementFinalized WRITE setMeasurementFinalized NOTIFY measurementFinalizedChanged ) public: @@ -55,11 +55,6 @@ class MeasurementMapTool : public AbstractMapTool */ Q_INVOKABLE void removePoint(); - /** - * If there are at least 3 points, forms a polygon from recorded points so far. - * Updates recorded geometry and calculates area and perimeter of formed polygon. - */ - /** * Finalizes measurement by forming a polygon if "Close shape" button was clicked * and there are at least 3 points; otherwise, if "Done" button was clicked, forms a polyline. @@ -92,8 +87,8 @@ class MeasurementMapTool : public AbstractMapTool bool canCloseShape() const; void setCanCloseShape( bool newCanCloseShape ); - bool canFinalizeMeasurement() const; - void setCanFinalizeMeasurement( bool canFinalize ); + bool isValidGeometry() const; + void setIsValidGeometry( bool canFinalize ); bool measurementFinalized() const; void setMeasurementFinalized( bool newMeasurementFinalized ); @@ -104,7 +99,8 @@ class MeasurementMapTool : public AbstractMapTool QgsGeometry existingVertices() const; void setExistingVertices( const QgsGeometry &vertices ); - void setMapSettings( InputMapSettings *newMapSettings ) override; + void resetMapSettings(); + void updateMapSettings( InputMapSettings *newMapSettings ); signals: void lengthWithGuidelineChanged( const double &lengthWithGuideline ); @@ -116,7 +112,7 @@ class MeasurementMapTool : public AbstractMapTool void recordedGeometryChanged( const QgsGeometry &recordedGeometry ); void existingVerticesChanged( const QgsGeometry &vertices ); void crosshairPointChanged( const QPointF &crosshairPoint ); - void canFinalizeMeasurementChanged( bool canFinalize ); + void isValidGeometryChanged( bool canFinalize ); protected: void rebuildGeometry(); @@ -136,7 +132,7 @@ class MeasurementMapTool : public AbstractMapTool double mArea = 0; bool mCanUndo = false; bool mCanCloseShape = false; - bool mCanFinalizeMeasurement = false; + bool mIsValidGeometry = false; bool mMeasurementFinalized = false; }; diff --git a/app/qml/gps/MMMeasureDrawer.qml b/app/qml/gps/MMMeasureDrawer.qml index 91a966ae9..6df3696de 100644 --- a/app/qml/gps/MMMeasureDrawer.qml +++ b/app/qml/gps/MMMeasureDrawer.qml @@ -35,7 +35,6 @@ MMDrawer { property string area: mapCanvas.mapToolComponent?.mapTool?.area ?? 0 signal measureFinished() - signal measureDone() Component.onCompleted: root.open() @@ -112,7 +111,7 @@ MMDrawer { text: qsTr( "Done" ) iconSourceLeft: __style.doneCircleIcon enabled: root.canFinalizeMeasurement - onClicked: root.measureDone() + onClicked: root.mapCanvas.mapToolComponent.finalizeMeasurement( false ) } } } diff --git a/app/qml/main.qml b/app/qml/main.qml index 40ed9d314..b4449a922 100644 --- a/app/qml/main.qml +++ b/app/qml/main.qml @@ -633,8 +633,6 @@ ApplicationWindow { width: window.width mapCanvas: map - onMeasureDone: finishMeasurementDialog.open() - onMeasureFinished: { measurePanelLoader.active = false map.finishMeasure() @@ -773,14 +771,6 @@ ApplicationWindow { } } - MMFinishMeasurementDialog { - id: finishMeasurementDialog - - onFinishMeasurementRequested: { - map.mapToolComponent.finalizeMeasurement( false ) - } - } - MMNotificationView {} MMListDrawer { diff --git a/app/qml/map/MMMapController.qml b/app/qml/map/MMMapController.qml index 163f77f76..22ad5cf6e 100644 --- a/app/qml/map/MMMapController.qml +++ b/app/qml/map/MMMapController.qml @@ -1151,7 +1151,6 @@ Item { } function measure() { - internal.extentBeforeStakeout = mapCanvas.mapSettings.extent state = "measure" } @@ -1173,7 +1172,6 @@ Item { function finishMeasure() { state = "view" - mapCanvas.mapSettings.extent = internal.extentBeforeStakeout } function centerToPair( pair ) { diff --git a/app/qml/map/components/MMMeasureCrosshair.qml b/app/qml/map/components/MMMeasureCrosshair.qml index b8d76ba3e..4e177466d 100644 --- a/app/qml/map/components/MMMeasureCrosshair.qml +++ b/app/qml/map/components/MMMeasureCrosshair.qml @@ -56,7 +56,7 @@ Item { } Rectangle { - y: crosshair.crosshairForeground.y + crosshair.crosshairForeground.height + y: crosshair.crosshairForeground.y + crosshair.crosshairForeground.height + 2 * __dp x: crosshair.crosshairForeground.x - ( ( width - crosshair.crosshairForeground.width ) / 2 ) width: Math.max( root.outerSize - 10 * __dp , row.width ) From 3428de27dcb07cabc27a3d3c506f5f3bd9ab4ebd Mon Sep 17 00:00:00 2001 From: VitorVieiraZ Date: Mon, 7 Oct 2024 15:36:37 -0300 Subject: [PATCH 49/60] small renaming --- app/maptools/measurementmaptool.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/maptools/measurementmaptool.h b/app/maptools/measurementmaptool.h index 0393fd029..1d041b203 100644 --- a/app/maptools/measurementmaptool.h +++ b/app/maptools/measurementmaptool.h @@ -88,7 +88,7 @@ class MeasurementMapTool : public AbstractMapTool void setCanCloseShape( bool newCanCloseShape ); bool isValidGeometry() const; - void setIsValidGeometry( bool canFinalize ); + void setIsValidGeometry( bool hasValidGeometry ); bool measurementFinalized() const; void setMeasurementFinalized( bool newMeasurementFinalized ); From 16ba5578e9fea8e4eb4bd38d59ca69b01a4dc4a0 Mon Sep 17 00:00:00 2001 From: VitorVieiraZ Date: Mon, 7 Oct 2024 16:03:37 -0300 Subject: [PATCH 50/60] binding done button to isValidGeometry property --- app/qml/gps/MMMeasureDrawer.qml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/qml/gps/MMMeasureDrawer.qml b/app/qml/gps/MMMeasureDrawer.qml index 6df3696de..82f3bf6d2 100644 --- a/app/qml/gps/MMMeasureDrawer.qml +++ b/app/qml/gps/MMMeasureDrawer.qml @@ -28,7 +28,7 @@ MMDrawer { property bool canCloseShape: mapCanvas.mapToolComponent?.mapTool?.canCloseShape ?? false property bool canUndo: mapCanvas.mapToolComponent?.mapTool?.canUndo ?? false - property bool canFinalizeMeasurement: mapCanvas.mapToolComponent?.mapTool?.canFinalizeMeasurement ?? false + property bool isValidGeometry: mapCanvas.mapToolComponent?.mapTool?.isValidGeometry ?? false property bool measurementFinalized: mapCanvas.mapToolComponent?.mapTool?.measurementFinalized ?? false property string perimeter: mapCanvas.mapToolComponent?.mapTool?.perimeter ?? 0 @@ -110,7 +110,7 @@ MMDrawer { type: MMButton.Types.Secondary text: qsTr( "Done" ) iconSourceLeft: __style.doneCircleIcon - enabled: root.canFinalizeMeasurement + enabled: root.isValidGeometry onClicked: root.mapCanvas.mapToolComponent.finalizeMeasurement( false ) } } From 951a63f3393b928033b19d0340c4cada34dd3563 Mon Sep 17 00:00:00 2001 From: VitorVieiraZ Date: Fri, 11 Oct 2024 10:28:13 -0300 Subject: [PATCH 51/60] in progress - final review changes --- app/mmstyle.h | 2 + app/qml/CMakeLists.txt | 1 - app/qml/components/MMButton.qml | 2 +- app/qml/dialogs/MMFinishMeasurementDialog.qml | 31 ---- app/qml/gps/MMMeasureDrawer.qml | 20 +-- app/qml/main.qml | 7 +- app/qml/map/MMMapController.qml | 2 +- app/qml/map/MMMeasurementTools.qml | 18 +- app/qml/map/components/MMCrosshair.qml | 1 + app/qml/map/components/MMMeasureCrosshair.qml | 160 ++++++++---------- gallery/qml/pages/DrawerPage.qml | 12 -- 11 files changed, 87 insertions(+), 169 deletions(-) delete mode 100644 app/qml/dialogs/MMFinishMeasurementDialog.qml diff --git a/app/mmstyle.h b/app/mmstyle.h index 7529e9670..16587bb81 100644 --- a/app/mmstyle.h +++ b/app/mmstyle.h @@ -279,7 +279,9 @@ class MMStyle: public QObject // Page Q_PROPERTY( double pageMargins READ number20 CONSTANT ) // distance between screen edge and components + Q_PROPERTY( double spacing2 READ number2 CONSTANT ) Q_PROPERTY( double spacing5 READ number5 CONSTANT ) + Q_PROPERTY( double spacing10 READ number10 CONSTANT ) Q_PROPERTY( double spacing12 READ number12 CONSTANT ) // distance between page header, page content and page footer Q_PROPERTY( double spacing20 READ number20 CONSTANT ) Q_PROPERTY( double spacing30 READ number30 CONSTANT ) diff --git a/app/qml/CMakeLists.txt b/app/qml/CMakeLists.txt index c2c8264b8..ccf99a8d5 100644 --- a/app/qml/CMakeLists.txt +++ b/app/qml/CMakeLists.txt @@ -77,7 +77,6 @@ set(MM_QML dialogs/MMDiscardGeometryChangesDialog.qml dialogs/MMProjectLoadErrorDialog.qml dialogs/MMProviderRemoveReceiverDialog.qml - dialogs/MMFinishMeasurementDialog.qml dialogs/components/MMDialogAdditionalText.qml form/MMFormPage.qml form/MMFormStackController.qml diff --git a/app/qml/components/MMButton.qml b/app/qml/components/MMButton.qml index 0791d8144..3cce97fc9 100644 --- a/app/qml/components/MMButton.qml +++ b/app/qml/components/MMButton.qml @@ -188,7 +188,7 @@ Button { spacing: { if ( ( root.size === MMButton.Sizes.Small ) ) - return 2; + return __style.spacing2; else if ( ( buttonIconRight.visible || buttonIconLeft.visible ) ) return __style.spacing12; else diff --git a/app/qml/dialogs/MMFinishMeasurementDialog.qml b/app/qml/dialogs/MMFinishMeasurementDialog.qml deleted file mode 100644 index 9f5121ea3..000000000 --- a/app/qml/dialogs/MMFinishMeasurementDialog.qml +++ /dev/null @@ -1,31 +0,0 @@ -/*************************************************************************** - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - ***************************************************************************/ - -import QtQuick - -import "../components" - -MMDrawerDialog { - id: root - - signal finishMeasurementRequested() - - imageSource: __style.neutralMMSymbolImage - title: qsTr( "Do you wish to finish the measurement?" ) - description: qsTr( "Your measured segment will be lost." ) - primaryButton.text: qsTr( "Yes" ) - secondaryButton.text: qsTr( "No" ) - - onPrimaryButtonClicked: { - root.finishMeasurementRequested() - close() - } - - onSecondaryButtonClicked: close() -} diff --git a/app/qml/gps/MMMeasureDrawer.qml b/app/qml/gps/MMMeasureDrawer.qml index 82f3bf6d2..2ac33df65 100644 --- a/app/qml/gps/MMMeasureDrawer.qml +++ b/app/qml/gps/MMMeasureDrawer.qml @@ -22,17 +22,17 @@ import "./components" as MMGpsComponents MMDrawer { id: root - property var mapCanvas + property var mapTool readonly property alias panelHeight: root.height - property bool canCloseShape: mapCanvas.mapToolComponent?.mapTool?.canCloseShape ?? false - property bool canUndo: mapCanvas.mapToolComponent?.mapTool?.canUndo ?? false - property bool isValidGeometry: mapCanvas.mapToolComponent?.mapTool?.isValidGeometry ?? false - property bool measurementFinalized: mapCanvas.mapToolComponent?.mapTool?.measurementFinalized ?? false + property bool canCloseShape: mapTool?.canCloseShape ?? false + property bool canUndo: mapTool?.canUndo ?? false + property bool isValidGeometry: mapTool?.isValidGeometry ?? false + property bool measurementFinalized: mapTool?.measurementFinalized ?? false - property string perimeter: mapCanvas.mapToolComponent?.mapTool?.perimeter ?? 0 - property string area: mapCanvas.mapToolComponent?.mapTool?.area ?? 0 + property string perimeter: mapTool?.perimeter ?? 0 + property string area: mapTool?.area ?? 0 signal measureFinished() @@ -66,7 +66,7 @@ MMDrawer { verticalCenter: parent.verticalCenter } - onClicked: measurementFinalized ? root.mapCanvas.mapToolComponent.repeatMeasure() : root.mapCanvas.mapToolComponent.mapTool.removePoint() + onClicked: measurementFinalized ? root.mapTool.resetMeasurement() : root.mapTool.removePoint() } drawerContent: Column { @@ -103,7 +103,7 @@ MMDrawer { MMButton { text: root.canCloseShape ? qsTr( "Close shape" ) : qsTr( "Add point" ) iconSourceLeft: canCloseShape ? __style.closeShapeIcon : __style.plusIcon - onClicked: canCloseShape ? root.mapCanvas.mapToolComponent.finalizeMeasurement( true ) : root.mapCanvas.mapToolComponent.mapTool.addPoint() + onClicked: canCloseShape ? root.mapTool.finalizeMeasurement( true ) : root.mapTool.addPoint() } MMButton { @@ -111,7 +111,7 @@ MMDrawer { text: qsTr( "Done" ) iconSourceLeft: __style.doneCircleIcon enabled: root.isValidGeometry - onClicked: root.mapCanvas.mapToolComponent.finalizeMeasurement( false ) + onClicked: root.mapTool.finalizeMeasurement( false ) } } } diff --git a/app/qml/main.qml b/app/qml/main.qml index b4449a922..d6b7ea116 100644 --- a/app/qml/main.qml +++ b/app/qml/main.qml @@ -338,10 +338,7 @@ ApplicationWindow { MMToolbarButton { text: qsTr("Measure") iconSource: __style.measurementToolIcon - onClicked: { - stateManager.state = "map" - map.measure() - } + onClicked: map.measure() } MMToolbarButton { @@ -631,7 +628,7 @@ ApplicationWindow { id: measurePanel width: window.width - mapCanvas: map + mapTool: map.mapToolComponent onMeasureFinished: { measurePanelLoader.active = false diff --git a/app/qml/map/MMMapController.qml b/app/qml/map/MMMapController.qml index 22ad5cf6e..43f76d8af 100644 --- a/app/qml/map/MMMapController.qml +++ b/app/qml/map/MMMapController.qml @@ -36,7 +36,7 @@ Item { property bool centeredToGPS: false property var mapToolComponent: { - state === "measure" ? measurementToolsLoader.item : null + measurementToolsLoader.active ? measurementToolsLoader.item.mapTool : null } property MM.PositionTrackingManager trackingManager: tracking.item?.manager ?? null diff --git a/app/qml/map/MMMeasurementTools.qml b/app/qml/map/MMMeasurementTools.qml index 2ec5dd274..da9be9b88 100644 --- a/app/qml/map/MMMeasurementTools.qml +++ b/app/qml/map/MMMeasurementTools.qml @@ -37,6 +37,7 @@ Item { MM.GuidelineController { id: guidelineController + allowed: !mapTool.measurementFinalized mapSettings: root.map.mapSettings crosshairPosition: crosshair.screenPoint realGeometry: mapTool.recordedGeometry @@ -90,24 +91,11 @@ Item { anchors.fill: parent qgsProject: __activeProject.qgsProject mapSettings: root.map.mapSettings + visible: !mapTool.measurementFinalized text: __inputUtils.formatDistanceInProjectUnit( mapTool.lengthWithGuideline, __activeProject.qgsProject ) canCloseShape: mapTool.canCloseShape - onCloseShapeClicked: finalizeMeasurement( true ) - } - - function finalizeMeasurement( closeShapeClicked ) - { - guidelineController.allowed = false - crosshair.visible = false - mapTool.finalizeMeasurement( closeShapeClicked ) - } - - function repeatMeasure() - { - guidelineController.allowed = true - crosshair.visible = true - mapTool.resetMeasurement() + onCloseShapeClicked: root.mapTool.finalizeMeasurement( true ) } } diff --git a/app/qml/map/components/MMCrosshair.qml b/app/qml/map/components/MMCrosshair.qml index dd7f7ef86..82892ff25 100644 --- a/app/qml/map/components/MMCrosshair.qml +++ b/app/qml/map/components/MMCrosshair.qml @@ -29,6 +29,7 @@ Item { property real innerDotSize: 10 * __dp property alias crosshairForeground: crosshairForeground + property alias snapUtils: snapUtils MM.SnapUtils { id: snapUtils diff --git a/app/qml/map/components/MMMeasureCrosshair.qml b/app/qml/map/components/MMMeasureCrosshair.qml index 4e177466d..366c8ea2b 100644 --- a/app/qml/map/components/MMMeasureCrosshair.qml +++ b/app/qml/map/components/MMMeasureCrosshair.qml @@ -14,121 +14,95 @@ import mm 1.0 as MM import "../../components" Item { - id: root + id: root - required property string text - /*required*/ property var qgsProject - /*required*/ property var mapSettings + required property string text + /*required*/ property var qgsProject + /*required*/ property var mapSettings - property bool canCloseShape: false - property bool shouldUseSnapping: false + property bool canCloseShape: false + property bool shouldUseSnapping: false - property point center: Qt.point( root.width / 2, root.height / 2 ) + property point center: Qt.point( root.width / 2, root.height / 2 ) - property var recordPoint: snapUtils.recordPoint + property var recordPoint: crosshair.recordPoint - property point screenPoint: snapUtils.snapped && __activeLayer.vectorLayer ? __inputUtils.transformPointToScreenCoordinates(__activeLayer.vectorLayer.crs, mapSettings, recordPoint) : center + property point screenPoint: crosshair.snapUtils.snapped && __activeLayer.vectorLayer ? __inputUtils.transformPointToScreenCoordinates(__activeLayer.vectorLayer.crs, mapSettings, recordPoint) : center - property real outerSize: 60 * __dp - property real innerDotSize: 10 * __dp + property real outerSize: 60 * __dp + property real innerDotSize: 10 * __dp - implicitWidth: row.width - implicitHeight: __style.mapItemHeight + implicitWidth: row.width + implicitHeight: __style.mapItemHeight - signal closeShapeClicked + signal closeShapeClicked - MM.SnapUtils { - id: snapUtils + MMCrosshair { + id: crosshair - centerPosition: root.center - mapSettings: root.mapSettings - qgsProject: root.qgsProject - useSnapping: root.shouldUseSnapping - destinationLayer: __activeLayer.vectorLayer - } - - MMCrosshair { - id: crosshair - - anchors.fill: parent - qgsProject: __activeProject.qgsProject - mapSettings: root.mapSettings - } - - Rectangle { - y: crosshair.crosshairForeground.y + crosshair.crosshairForeground.height + 2 * __dp - x: crosshair.crosshairForeground.x - ( ( width - crosshair.crosshairForeground.width ) / 2 ) + anchors.fill: parent + qgsProject: __activeProject.qgsProject + mapSettings: root.mapSettings + } - width: Math.max( root.outerSize - 10 * __dp , row.width ) - height: root.outerSize * 0.6 - radius: root.height / 2 - color: textBg.color + Rectangle { + y: crosshair.crosshairForeground.y + crosshair.crosshairForeground.height + __style.spacing2 + x: crosshair.crosshairForeground.x - ( ( width - crosshair.crosshairForeground.width ) / 2 ) - layer.enabled: true - layer.effect: MMShadow {} + width: Math.max( root.outerSize - __style.spacing10 , row.width ) + height: root.outerSize * 0.6 + radius: root.height / 2 + color: textBg.color - Row { - id: row + layer.enabled: true + layer.effect: MMShadow {} - anchors.centerIn: parent - leftPadding: 8 * __dp - rightPadding: leftPadding - spacing: 4 * __dp - height: parent.height + Row { + id: row - MMIcon { - id: icon - anchors.verticalCenter: parent.verticalCenter - source: root.canCloseShape ? __style.closeShapeIcon : "" - size: root.canCloseShape ? __style.icon24 : 0 - } + anchors.centerIn: parent + leftPadding: 8 * __dp + rightPadding: leftPadding + spacing: 4 * __dp + height: parent.height - Rectangle { - id: textBg - property real spacing: 5 * __dp - anchors.verticalCenter: parent.verticalCenter - color: root.canCloseShape ? __style.grassColor : __style.forestColor - height: text.height + spacing - width: text.width + 3 * spacing - radius: height / 2 - - Text { - id: text - - property real textSurroundingItemsWidth: textBg.spacing + icon.width + row.spacing + 2 * row.leftPadding - - width: ( implicitWidth + textSurroundingItemsWidth ) > root.maxWidth ? root.maxWidth - textSurroundingItemsWidth : implicitWidth - anchors.centerIn: parent - color: root.canCloseShape ? __style.forestColor: __style.polarColor - text: root.canCloseShape ? qsTr( "Close shape" ) : root.text - font: __style.t3 - elide: Text.ElideRight - } - } + MMIcon { + id: icon + anchors.verticalCenter: parent.verticalCenter + source: root.canCloseShape ? __style.closeShapeIcon : "" + size: root.canCloseShape ? __style.icon24 : 0 } - MouseArea { - anchors.fill: parent - onClicked: { - if ( root.canCloseShape ) - root.closeShapeClicked() + Rectangle { + id: textBg + property real spacing: __style.spacing5 + anchors.verticalCenter: parent.verticalCenter + color: root.canCloseShape ? __style.grassColor : __style.forestColor + height: text.height + spacing + width: text.width + 3 * spacing + radius: height / 2 + + MMText { + id: text + + property real textSurroundingItemsWidth: textBg.spacing + icon.width + row.spacing + 2 * row.leftPadding + + width: ( implicitWidth + textSurroundingItemsWidth ) > root.maxWidth ? root.maxWidth - textSurroundingItemsWidth : implicitWidth + anchors.centerIn: parent + color: root.canCloseShape ? __style.forestColor: __style.polarColor + text: root.canCloseShape ? qsTr( "Close shape" ) : root.text + font: __style.t3 + elide: Text.ElideRight } } } - Connections { // future snapping? _(ツ)_/¯ - target: __activeProject - - function onProjectWillBeReloaded() { - snapUtils.clear() - } - - function onProjectReloaded( project ) { - // We need to re-assign qgs project to snaputils, because - // even though we loaded a different project, - // internally we keep the same pointer for QgsProject. - snapUtils.qgsProject = __activeProject.qgsProject - snapUtils.mapSettings = root.mapSettings + MouseArea { + anchors.fill: parent + onClicked: { + if ( root.canCloseShape ) + root.closeShapeClicked() } } + } } diff --git a/gallery/qml/pages/DrawerPage.qml b/gallery/qml/pages/DrawerPage.qml index be7cf90e3..e3400a423 100644 --- a/gallery/qml/pages/DrawerPage.qml +++ b/gallery/qml/pages/DrawerPage.qml @@ -194,14 +194,6 @@ Page { welcomeToNewDesignDialog.open() } } - - Button { - text: "finishMeasurementDialog" - - onClicked: { - finishMeasurementDialog.open() - } - } } } @@ -375,8 +367,4 @@ Page { MMWelcomeToNewDesignDialog { id: welcomeToNewDesignDialog } - - MMFinishMeasurementDialog { - id: finishMeasurementDialog - } } From 8a6e67bd3c89ed17e08aba527b54eaa23b2f92bb Mon Sep 17 00:00:00 2001 From: VitorVieiraZ Date: Fri, 11 Oct 2024 13:24:05 -0300 Subject: [PATCH 52/60] final adjustments for review --- app/inpututils.cpp | 43 +++++++++---------- app/inpututils.h | 7 +++- app/qml/map/MMMeasurementTools.qml | 2 +- app/test/testutilsfunctions.cpp | 67 ++++++++++++++++++++---------- app/test/testutilsfunctions.h | 2 +- gallery/qml.qrc | 1 - 6 files changed, 75 insertions(+), 47 deletions(-) diff --git a/app/inpututils.cpp b/app/inpututils.cpp index 2bf9ddb0d..cfad0359f 100644 --- a/app/inpututils.cpp +++ b/app/inpututils.cpp @@ -168,45 +168,46 @@ QString InputUtils::formatNumber( const double number, int precision ) return QString::number( number, 'f', precision ); } -QString InputUtils::formatDistanceInProjectUnit( const double distanceInMeters, int precision, Qgis::DistanceUnit destUnit, QgsProject *activeProject ) +QString InputUtils::formatDistanceInProjectUnit( const double distanceInMeters, int precision, QgsProject *activeProject ) { - Qgis::DistanceUnit distUnit = destUnit; + if ( !activeProject ) + return QString(); - if ( distUnit == Qgis::DistanceUnit::Unknown ) - { - distUnit = activeProject->distanceUnits(); - } + return InputUtils::formatDistanceHelper( distanceInMeters, precision, activeProject->distanceUnits() ); +} - if ( distUnit == Qgis::DistanceUnit::Unknown ) +QString InputUtils::formatDistanceHelper( const double distanceInMeters, int precision, Qgis::DistanceUnit destUnit ) +{ + if ( destUnit == Qgis::DistanceUnit::Unknown ) { - return QString::number( distanceInMeters, 'f', precision ); + destUnit = Qgis::DistanceUnit::Meters; } - double factor = QgsUnitTypes::fromUnitToUnitFactor( Qgis::DistanceUnit::Meters, distUnit ); + double factor = QgsUnitTypes::fromUnitToUnitFactor( Qgis::DistanceUnit::Meters, destUnit ); double distance = distanceInMeters * factor; - QString abbreviation = QgsUnitTypes::toAbbreviatedString( distUnit ); + QString abbreviation = QgsUnitTypes::toAbbreviatedString( destUnit ); return QString( "%1 %2" ).arg( QString::number( distance, 'f', precision ), abbreviation ); } -QString InputUtils::formatAreaInProjectUnit( const double areaInSquareMeters, int precision, Qgis::AreaUnit destUnit, QgsProject *activeProject ) +QString InputUtils::formatAreaInProjectUnit( const double areaInSquareMeters, int precision, QgsProject *activeProject ) { - Qgis::AreaUnit areaUnit = destUnit; + if ( !activeProject ) + return QString(); - if ( areaUnit == Qgis::AreaUnit::Unknown ) - { - areaUnit = activeProject->areaUnits(); - } + return InputUtils::formatAreaHelper( areaInSquareMeters, precision, activeProject->areaUnits() ); +} - if ( areaUnit == Qgis::AreaUnit::Unknown ) +QString InputUtils::formatAreaHelper( const double areaInSquareMeters, int precision, Qgis::AreaUnit destUnit ) +{ + if ( destUnit == Qgis::AreaUnit::Unknown ) { - return QString::number( areaInSquareMeters, 'f', precision ); + destUnit = Qgis::AreaUnit::SquareMeters; } - double factor = QgsUnitTypes::fromUnitToUnitFactor( Qgis::AreaUnit::SquareMeters, areaUnit ); + double factor = QgsUnitTypes::fromUnitToUnitFactor( Qgis::AreaUnit::SquareMeters, destUnit ); double area = areaInSquareMeters * factor; - - QString abbreviation = QgsUnitTypes::toAbbreviatedString( areaUnit ); + QString abbreviation = QgsUnitTypes::toAbbreviatedString( destUnit ); return QString( "%1 %2" ).arg( QString::number( area, 'f', precision ), abbreviation ); } diff --git a/app/inpututils.h b/app/inpututils.h index b59956061..b3a5ce32b 100644 --- a/app/inpututils.h +++ b/app/inpututils.h @@ -75,8 +75,11 @@ class InputUtils: public QObject Q_INVOKABLE QString getFileName( const QString &filePath ); Q_INVOKABLE QString formatProjectName( const QString &fullProjectName ); Q_INVOKABLE QString formatNumber( const double number, int precision = 1 ); - Q_INVOKABLE QString formatDistanceInProjectUnit( const double distanceInMeters, int precision = 1, Qgis::DistanceUnit destUnit = Qgis::DistanceUnit::Unknown, QgsProject *activeProject = QgsProject::instance() ); - Q_INVOKABLE QString formatAreaInProjectUnit( const double areaInSquareMeters, int precision = 1, Qgis::AreaUnit destUnit = Qgis::AreaUnit::Unknown, QgsProject *activeProject = QgsProject::instance() ); + Q_INVOKABLE QString formatDistanceInProjectUnit( const double distanceInMeters, int precision, QgsProject *activeProject ); + Q_INVOKABLE QString formatAreaInProjectUnit( const double areaInSquareMeters, int precision, QgsProject *activeProject ); + + static QString formatDistanceHelper( const double distanceInMeters, int precision, Qgis::DistanceUnit destUnit ); + static QString formatAreaHelper( const double areaInSquareMeters, int precision, Qgis::AreaUnit destUnit ); Q_INVOKABLE void setExtentToFeature( const FeatureLayerPair &pair, InputMapSettings *mapSettings ); diff --git a/app/qml/map/MMMeasurementTools.qml b/app/qml/map/MMMeasurementTools.qml index da9be9b88..e4a785961 100644 --- a/app/qml/map/MMMeasurementTools.qml +++ b/app/qml/map/MMMeasurementTools.qml @@ -93,7 +93,7 @@ Item { mapSettings: root.map.mapSettings visible: !mapTool.measurementFinalized - text: __inputUtils.formatDistanceInProjectUnit( mapTool.lengthWithGuideline, __activeProject.qgsProject ) + text: __inputUtils.formatDistanceInProjectUnit( mapTool.lengthWithGuideline, 1, __activeProject.qgsProject ) canCloseShape: mapTool.canCloseShape onCloseShapeClicked: root.mapTool.finalizeMeasurement( true ) diff --git a/app/test/testutilsfunctions.cpp b/app/test/testutilsfunctions.cpp index 1fcbc8d95..564b8458b 100644 --- a/app/test/testutilsfunctions.cpp +++ b/app/test/testutilsfunctions.cpp @@ -856,68 +856,93 @@ void TestUtilsFunctions::testParsePositionUpdates() } } -void TestUtilsFunctions::testFormatDistanceInDistanceUnit() +void TestUtilsFunctions::testFormatDistanceInProjectUnit() { - QString dist2str = mUtils->formatDistanceInProjectUnit( 1222.234, 2, Qgis::DistanceUnit::Meters, QgsProject::instance() ); + QgsProject *project = QgsProject::instance(); + QVERIFY( project != nullptr ); + + // Set the project distance units to meters + project->setDistanceUnits( Qgis::DistanceUnit::Meters ); + + QString dist2str = mUtils->formatDistanceInProjectUnit( 1222.234, 2, project ); QVERIFY( dist2str == "1222.23 m" ); - dist2str = mUtils->formatDistanceInProjectUnit( 1222.234, 1, Qgis::DistanceUnit::Meters, QgsProject::instance() ); + dist2str = mUtils->formatDistanceInProjectUnit( 1222.234, 1, project ); QVERIFY( dist2str == "1222.2 m" ); - dist2str = mUtils->formatDistanceInProjectUnit( 1222.234, 0, Qgis::DistanceUnit::Meters, QgsProject::instance() ); + dist2str = mUtils->formatDistanceInProjectUnit( 1222.234, 0, project ); QVERIFY( dist2str == "1222 m" ); - dist2str = mUtils->formatDistanceInProjectUnit( 700.22, 1, Qgis::DistanceUnit::Meters, QgsProject::instance() ); + dist2str = mUtils->formatDistanceInProjectUnit( 700.22, 1, project ); QVERIFY( dist2str == "700.2 m" ); - dist2str = mUtils->formatDistanceInProjectUnit( 0.22, 0, Qgis::DistanceUnit::Meters, QgsProject::instance() ); + dist2str = mUtils->formatDistanceInProjectUnit( 0.22, 0, project ); QVERIFY( dist2str == "0 m" ); - dist2str = mUtils->formatDistanceInProjectUnit( -0.22, 0, Qgis::DistanceUnit::Meters, QgsProject::instance() ); + dist2str = mUtils->formatDistanceInProjectUnit( -0.22, 0, project ); QVERIFY( dist2str == "-0 m" ); - dist2str = mUtils->formatDistanceInProjectUnit( 1.222234, 2, Qgis::DistanceUnit::Kilometers, QgsProject::instance() ); + // Change project distance units to kilometers + project->setDistanceUnits( Qgis::DistanceUnit::Kilometers ); + + dist2str = mUtils->formatDistanceInProjectUnit( 1.222234, 2, project ); QVERIFY( dist2str == "0.00 km" ); - dist2str = mUtils->formatDistanceInProjectUnit( 6000, 1, Qgis::DistanceUnit::Feet, QgsProject::instance() ); + // Change project distance units to feet + project->setDistanceUnits( Qgis::DistanceUnit::Feet ); + + dist2str = mUtils->formatDistanceInProjectUnit( 6000, 1, project ); QVERIFY( dist2str == "19685.0 ft" ); - dist2str = mUtils->formatDistanceInProjectUnit( 5, 1, Qgis::DistanceUnit::Feet, QgsProject::instance() ); + dist2str = mUtils->formatDistanceInProjectUnit( 5, 1, project ); QVERIFY( dist2str == "16.4 ft" ); - dist2str = mUtils->formatDistanceInProjectUnit( 7000, 1, Qgis::DistanceUnit::Feet, QgsProject::instance() ); + dist2str = mUtils->formatDistanceInProjectUnit( 7000, 1, project ); QVERIFY( dist2str == "22965.9 ft" ); } + void TestUtilsFunctions::testFormatAreaInProjectUnit() { - QString area2str = mUtils->formatAreaInProjectUnit( 1500.234, 2, Qgis::AreaUnit::SquareMeters, QgsProject::instance() ); + QgsProject *project = QgsProject::instance(); + QVERIFY( project != nullptr ); + + // Set project area units to square meters + project->setAreaUnits( Qgis::AreaUnit::SquareMeters ); + + QString area2str = mUtils->formatAreaInProjectUnit( 1500.234, 2, project ); QVERIFY( area2str == "1500.23 m²" ); - area2str = mUtils->formatAreaInProjectUnit( 1500.234, 1, Qgis::AreaUnit::SquareMeters, QgsProject::instance() ); + area2str = mUtils->formatAreaInProjectUnit( 1500.234, 1, project ); QVERIFY( area2str == "1500.2 m²" ); - area2str = mUtils->formatAreaInProjectUnit( 1500.234, 0, Qgis::AreaUnit::SquareMeters, QgsProject::instance() ); + area2str = mUtils->formatAreaInProjectUnit( 1500.234, 0, project ); QVERIFY( area2str == "1500 m²" ); - area2str = mUtils->formatAreaInProjectUnit( 500.22, 1, Qgis::AreaUnit::SquareMeters, QgsProject::instance() ); + area2str = mUtils->formatAreaInProjectUnit( 500.22, 1, project ); QVERIFY( area2str == "500.2 m²" ); - area2str = mUtils->formatAreaInProjectUnit( 0.22, 0, Qgis::AreaUnit::SquareMeters, QgsProject::instance() ); + area2str = mUtils->formatAreaInProjectUnit( 0.22, 0, project ); QVERIFY( area2str == "0 m²" ); - area2str = mUtils->formatAreaInProjectUnit( -0.22, 0, Qgis::AreaUnit::SquareMeters, QgsProject::instance() ); + area2str = mUtils->formatAreaInProjectUnit( -0.22, 0, project ); QVERIFY( area2str == "-0 m²" ); - area2str = mUtils->formatAreaInProjectUnit( 1.222234, 2, Qgis::AreaUnit::SquareKilometers, QgsProject::instance() ); + // Change project area units to square kilometers + project->setAreaUnits( Qgis::AreaUnit::SquareKilometers ); + + area2str = mUtils->formatAreaInProjectUnit( 1.222234, 2, project ); QVERIFY( area2str == "0.00 km²" ); - area2str = mUtils->formatAreaInProjectUnit( 6000, 1, Qgis::AreaUnit::Acres, QgsProject::instance() ); + // Change project area units to acres + project->setAreaUnits( Qgis::AreaUnit::Acres ); + + area2str = mUtils->formatAreaInProjectUnit( 6000, 1, project ); QVERIFY( area2str == "1.5 ac" ); - area2str = mUtils->formatAreaInProjectUnit( 5, 1, Qgis::AreaUnit::Acres, QgsProject::instance() ); + area2str = mUtils->formatAreaInProjectUnit( 5, 1, project ); QVERIFY( area2str == "0.0 ac" ); - area2str = mUtils->formatAreaInProjectUnit( 7000, 1, Qgis::AreaUnit::Acres, QgsProject::instance() ); + area2str = mUtils->formatAreaInProjectUnit( 7000, 1, project ); QVERIFY( area2str == "1.7 ac" ); } diff --git a/app/test/testutilsfunctions.h b/app/test/testutilsfunctions.h index 64259c571..75b497c78 100644 --- a/app/test/testutilsfunctions.h +++ b/app/test/testutilsfunctions.h @@ -48,7 +48,7 @@ class TestUtilsFunctions: public QObject void testInvalidGeometryWarning(); void testAttribution(); void testParsePositionUpdates(); - void testFormatDistanceInDistanceUnit(); + void testFormatDistanceInProjectUnit(); void testFormatAreaInProjectUnit(); private: diff --git a/gallery/qml.qrc b/gallery/qml.qrc index b66430682..b54c2ff92 100644 --- a/gallery/qml.qrc +++ b/gallery/qml.qrc @@ -155,6 +155,5 @@ ../app/qml/dialogs/MMDiscardGeometryChangesDialog.qml ../app/qml/dialogs/MMProviderRemoveReceiverDialog.qml ../app/qml/dialogs/components/MMDialogAdditionalText.qml - ../app/qml/dialogs/MMFinishMeasurementDialog.qml From b86b10bf3cb07e32ddcce96c4ad0f3490bb62d62 Mon Sep 17 00:00:00 2001 From: VitorVieiraZ Date: Thu, 17 Oct 2024 20:28:04 -0300 Subject: [PATCH 53/60] length if done button was clicked, perimeter if close shape was clicked --- app/qml/gps/MMMeasureDrawer.qml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/app/qml/gps/MMMeasureDrawer.qml b/app/qml/gps/MMMeasureDrawer.qml index 2ac33df65..6e10a39fb 100644 --- a/app/qml/gps/MMMeasureDrawer.qml +++ b/app/qml/gps/MMMeasureDrawer.qml @@ -33,6 +33,7 @@ MMDrawer { property string perimeter: mapTool?.perimeter ?? 0 property string area: mapTool?.area ?? 0 + property bool isPolygon: root.area > 0 signal measureFinished() @@ -81,7 +82,7 @@ MMDrawer { MMGpsComponents.MMGpsDataText{ width: ( parent.width + parent.spacing ) / 2 - title: measurementFinalized ? qsTr( "Perimeter" ) : qsTr( "Length" ) + title: measurementFinalized && root.isPolygon ? qsTr( "Perimeter" ) : qsTr( "Length" ) //Perimeter only if its a polygon value: __inputUtils.formatDistanceInProjectUnit( root.perimeter, 1, __activeProject.qgsProject ) } @@ -91,7 +92,7 @@ MMDrawer { title: qsTr( "Area" ) value: __inputUtils.formatAreaInProjectUnit( root.area, 1, __activeProject.qgsProject ) alignmentRight: true - visible: measurementFinalized && root.area > 0 + visible: measurementFinalized && root.isPolygon } } From dd3c896bf1d10b04887d8f8f5c50771806310915 Mon Sep 17 00:00:00 2001 From: VitorVieiraZ Date: Thu, 17 Oct 2024 20:31:13 -0300 Subject: [PATCH 54/60] small fix --- app/qml/gps/MMMeasureDrawer.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/qml/gps/MMMeasureDrawer.qml b/app/qml/gps/MMMeasureDrawer.qml index 6e10a39fb..75910e175 100644 --- a/app/qml/gps/MMMeasureDrawer.qml +++ b/app/qml/gps/MMMeasureDrawer.qml @@ -33,7 +33,7 @@ MMDrawer { property string perimeter: mapTool?.perimeter ?? 0 property string area: mapTool?.area ?? 0 - property bool isPolygon: root.area > 0 + property bool isPolygon: area > 0 signal measureFinished() From 4f1e62dca866c877248b980717f619738a08acc5 Mon Sep 17 00:00:00 2001 From: VitorVieiraZ Date: Fri, 18 Oct 2024 11:33:38 -0300 Subject: [PATCH 55/60] technical changes application --- app/inpututils.cpp | 24 ++++++++++++------------ app/inpututils.h | 4 ++-- app/maptools/measurementmaptool.cpp | 2 +- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/app/inpututils.cpp b/app/inpututils.cpp index cfad0359f..b10983a92 100644 --- a/app/inpututils.cpp +++ b/app/inpututils.cpp @@ -168,12 +168,12 @@ QString InputUtils::formatNumber( const double number, int precision ) return QString::number( number, 'f', precision ); } -QString InputUtils::formatDistanceInProjectUnit( const double distanceInMeters, int precision, QgsProject *activeProject ) +QString InputUtils::formatDistanceInProjectUnit( const double distanceInMeters, int precision, QgsProject *project ) { - if ( !activeProject ) + if ( !project ) return QString(); - return InputUtils::formatDistanceHelper( distanceInMeters, precision, activeProject->distanceUnits() ); + return InputUtils::formatDistanceHelper( distanceInMeters, precision, project->distanceUnits() ); } QString InputUtils::formatDistanceHelper( const double distanceInMeters, int precision, Qgis::DistanceUnit destUnit ) @@ -183,19 +183,19 @@ QString InputUtils::formatDistanceHelper( const double distanceInMeters, int pre destUnit = Qgis::DistanceUnit::Meters; } - double factor = QgsUnitTypes::fromUnitToUnitFactor( Qgis::DistanceUnit::Meters, destUnit ); - double distance = distanceInMeters * factor; - QString abbreviation = QgsUnitTypes::toAbbreviatedString( destUnit ); + const double factor = QgsUnitTypes::fromUnitToUnitFactor( Qgis::DistanceUnit::Meters, destUnit ); + const double distance = distanceInMeters * factor; + const QString abbreviation = QgsUnitTypes::toAbbreviatedString( destUnit ); return QString( "%1 %2" ).arg( QString::number( distance, 'f', precision ), abbreviation ); } -QString InputUtils::formatAreaInProjectUnit( const double areaInSquareMeters, int precision, QgsProject *activeProject ) +QString InputUtils::formatAreaInProjectUnit( const double areaInSquareMeters, int precision, QgsProject *project ) { - if ( !activeProject ) + if ( !project ) return QString(); - return InputUtils::formatAreaHelper( areaInSquareMeters, precision, activeProject->areaUnits() ); + return InputUtils::formatAreaHelper( areaInSquareMeters, precision, project->areaUnits() ); } QString InputUtils::formatAreaHelper( const double areaInSquareMeters, int precision, Qgis::AreaUnit destUnit ) @@ -205,9 +205,9 @@ QString InputUtils::formatAreaHelper( const double areaInSquareMeters, int preci destUnit = Qgis::AreaUnit::SquareMeters; } - double factor = QgsUnitTypes::fromUnitToUnitFactor( Qgis::AreaUnit::SquareMeters, destUnit ); - double area = areaInSquareMeters * factor; - QString abbreviation = QgsUnitTypes::toAbbreviatedString( destUnit ); + const double factor = QgsUnitTypes::fromUnitToUnitFactor( Qgis::AreaUnit::SquareMeters, destUnit ); + const double area = areaInSquareMeters * factor; + const QString abbreviation = QgsUnitTypes::toAbbreviatedString( destUnit ); return QString( "%1 %2" ).arg( QString::number( area, 'f', precision ), abbreviation ); } diff --git a/app/inpututils.h b/app/inpututils.h index b3a5ce32b..83be81f39 100644 --- a/app/inpututils.h +++ b/app/inpututils.h @@ -75,8 +75,8 @@ class InputUtils: public QObject Q_INVOKABLE QString getFileName( const QString &filePath ); Q_INVOKABLE QString formatProjectName( const QString &fullProjectName ); Q_INVOKABLE QString formatNumber( const double number, int precision = 1 ); - Q_INVOKABLE QString formatDistanceInProjectUnit( const double distanceInMeters, int precision, QgsProject *activeProject ); - Q_INVOKABLE QString formatAreaInProjectUnit( const double areaInSquareMeters, int precision, QgsProject *activeProject ); + Q_INVOKABLE QString formatDistanceInProjectUnit( const double distanceInMeters, int precision, QgsProject *project ); + Q_INVOKABLE QString formatAreaInProjectUnit( const double areaInSquareMeters, int precision, QgsProject *project ); static QString formatDistanceHelper( const double distanceInMeters, int precision, Qgis::DistanceUnit destUnit ); static QString formatAreaHelper( const double areaInSquareMeters, int precision, Qgis::AreaUnit destUnit ); diff --git a/app/maptools/measurementmaptool.cpp b/app/maptools/measurementmaptool.cpp index 0b66baae8..3aad186bf 100644 --- a/app/maptools/measurementmaptool.cpp +++ b/app/maptools/measurementmaptool.cpp @@ -169,7 +169,7 @@ void MeasurementMapTool::updateMapSettings( InputMapSettings *newMapSettings ) { connect( updatedMapSettings, &InputMapSettings::extentChanged, this, &MeasurementMapTool::updateDistance ); - mDistanceArea.setEllipsoid( QStringLiteral( "WGS84" ) ); + mDistanceArea.setEllipsoid( updatedMapSettings->project()->ellipsoid() ); mDistanceArea.setSourceCrs( updatedMapSettings->destinationCrs(), updatedMapSettings->transformContext() ); } } From 7a7deb41bb1c1a486b1cd3e15176423b55eb6aa9 Mon Sep 17 00:00:00 2001 From: VitorVieiraZ Date: Fri, 18 Oct 2024 12:00:27 -0300 Subject: [PATCH 56/60] using locale to return units --- app/inpututils.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/inpututils.cpp b/app/inpututils.cpp index b10983a92..4a283a745 100644 --- a/app/inpututils.cpp +++ b/app/inpututils.cpp @@ -187,7 +187,7 @@ QString InputUtils::formatDistanceHelper( const double distanceInMeters, int pre const double distance = distanceInMeters * factor; const QString abbreviation = QgsUnitTypes::toAbbreviatedString( destUnit ); - return QString( "%1 %2" ).arg( QString::number( distance, 'f', precision ), abbreviation ); + return QString( "%L1 %2" ).arg( distance, 0, 'f', precision ).arg( abbreviation ); } QString InputUtils::formatAreaInProjectUnit( const double areaInSquareMeters, int precision, QgsProject *project ) @@ -209,7 +209,7 @@ QString InputUtils::formatAreaHelper( const double areaInSquareMeters, int preci const double area = areaInSquareMeters * factor; const QString abbreviation = QgsUnitTypes::toAbbreviatedString( destUnit ); - return QString( "%1 %2" ).arg( QString::number( area, 'f', precision ), abbreviation ); + return QString( "%L1 %2" ).arg( area, 0, 'f', precision ).arg( abbreviation ); } QString InputUtils::formatDateTimeDiff( const QDateTime &tMin, const QDateTime &tMax ) From 7afd49f61c27b8a14f658f5f9de9c2128e979706 Mon Sep 17 00:00:00 2001 From: VitorVieiraZ Date: Fri, 18 Oct 2024 12:10:02 -0300 Subject: [PATCH 57/60] small fix in formatUnits --- app/inpututils.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/inpututils.cpp b/app/inpututils.cpp index 4a283a745..218c024e1 100644 --- a/app/inpututils.cpp +++ b/app/inpututils.cpp @@ -187,7 +187,7 @@ QString InputUtils::formatDistanceHelper( const double distanceInMeters, int pre const double distance = distanceInMeters * factor; const QString abbreviation = QgsUnitTypes::toAbbreviatedString( destUnit ); - return QString( "%L1 %2" ).arg( distance, 0, 'f', precision ).arg( abbreviation ); + return QString( "%L1 %2" ).arg( QString::number( distance, 'f', precision ), abbreviation ); } QString InputUtils::formatAreaInProjectUnit( const double areaInSquareMeters, int precision, QgsProject *project ) @@ -209,7 +209,7 @@ QString InputUtils::formatAreaHelper( const double areaInSquareMeters, int preci const double area = areaInSquareMeters * factor; const QString abbreviation = QgsUnitTypes::toAbbreviatedString( destUnit ); - return QString( "%L1 %2" ).arg( area, 0, 'f', precision ).arg( abbreviation ); + return QString( "%L1 %2" ).arg( QString::number( area, 'f', precision ), abbreviation ); } QString InputUtils::formatDateTimeDiff( const QDateTime &tMin, const QDateTime &tMax ) From 1f39fc67784097d45250770ef1059299cff0bcc7 Mon Sep 17 00:00:00 2001 From: VitorVieiraZ Date: Mon, 21 Oct 2024 08:42:58 -0300 Subject: [PATCH 58/60] fixing tests --- app/test/testmaptools.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/test/testmaptools.cpp b/app/test/testmaptools.cpp index 75c868d7d..c90fb4de2 100644 --- a/app/test/testmaptools.cpp +++ b/app/test/testmaptools.cpp @@ -292,7 +292,7 @@ void TestMapTools::testMeasuring() measurementTool->setMapSettings( ms ); QgsDistanceArea distanceArea; - distanceArea.setEllipsoid( QStringLiteral( "WGS84" ) ); + distanceArea.setEllipsoid( ms->project()->ellipsoid() ); distanceArea.setSourceCrs( ms->destinationCrs(), ms->transformContext() ); QPointF crosshairPoint1 = ms->coordinateToScreen( QgsPoint( 0, 0 ) ); From 8e9a40e24660e006364afe139e7d50dd5894c34e Mon Sep 17 00:00:00 2001 From: VitorVieiraZ Date: Mon, 21 Oct 2024 10:26:45 -0300 Subject: [PATCH 59/60] checking if points are equal before adding and enabling map label mouse area only if canCloseShape --- app/maptools/measurementmaptool.cpp | 4 ++++ app/qml/map/components/MMMeasureCrosshair.qml | 6 ++---- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/app/maptools/measurementmaptool.cpp b/app/maptools/measurementmaptool.cpp index 3aad186bf..dcaad908b 100644 --- a/app/maptools/measurementmaptool.cpp +++ b/app/maptools/measurementmaptool.cpp @@ -23,6 +23,10 @@ void MeasurementMapTool::addPoint() if ( mapSettings() ) { QgsPoint transformedPoint = mapSettings()->screenToCoordinate( mCrosshairPoint ); + + if ( !mPoints.empty() && transformedPoint == mPoints.back() ) + return; + mPoints.push_back( transformedPoint ); rebuildGeometry(); } diff --git a/app/qml/map/components/MMMeasureCrosshair.qml b/app/qml/map/components/MMMeasureCrosshair.qml index 366c8ea2b..3102def00 100644 --- a/app/qml/map/components/MMMeasureCrosshair.qml +++ b/app/qml/map/components/MMMeasureCrosshair.qml @@ -99,10 +99,8 @@ Item { MouseArea { anchors.fill: parent - onClicked: { - if ( root.canCloseShape ) - root.closeShapeClicked() - } + enabled: root.canCloseShape + onClicked: root.closeShapeClicked() } } } From d14f7f4b514afac952a45ea6cba6a4e48f9913fa Mon Sep 17 00:00:00 2001 From: Tomas Mizera Date: Tue, 22 Oct 2024 16:10:35 +0200 Subject: [PATCH 60/60] revert android CI debug changes --- .github/workflows/android.yml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/.github/workflows/android.yml b/.github/workflows/android.yml index 69e172ede..09f9e4099 100644 --- a/.github/workflows/android.yml +++ b/.github/workflows/android.yml @@ -246,7 +246,7 @@ jobs: -S ../ \ -B ./ - - name: build APK + - name: Build APK env: ANDROID_NDK_ROOT: ${{ steps.setup-ndk.outputs.ndk-path }} ANDROID_NDK_HOST: darwin-x86_64 @@ -271,7 +271,8 @@ jobs: path: ${{ github.workspace }}/merginmaps-${{ env.INPUT_VERSION_CODE }}.apk name: Mergin Maps ${{ env.INPUT_VERSION_CODE }} APK [v7 + v8a] - - name: build AAB + - name: Build AAB + if: ${{ github.ref_name == 'master' || github.ref_type == 'tag' }} env: ANDROID_NDK_ROOT: ${{ steps.setup-ndk.outputs.ndk-path }} ANDROID_NDK_HOST: darwin-x86_64 @@ -285,14 +286,15 @@ jobs: find . | grep .aab - name: Rename AAB artefacts + if: ${{ github.ref_name == 'master' || github.ref_type == 'tag' }} run: | mv \ ${{ github.workspace }}/build-Input/app/android-build/build/outputs/bundle/release/android-build-release.aab \ ${{ github.workspace }}/merginmaps-${{ env.INPUT_VERSION_CODE }}.aab - name: Upload AAB to Artifacts + if: ${{ github.ref_name == 'master' || github.ref_type == 'tag' }} uses: actions/upload-artifact@v3 with: path: ${{ github.workspace }}/merginmaps-${{ env.INPUT_VERSION_CODE }}.aab name: Mergin Maps ${{ env.INPUT_VERSION_CODE }} AAB -