diff --git a/doc/CMakeLists.txt b/doc/CMakeLists.txt index 5f596547da50..94ebae00c562 100644 --- a/doc/CMakeLists.txt +++ b/doc/CMakeLists.txt @@ -109,6 +109,7 @@ if(WITH_APIDOC) ${CMAKE_SOURCE_DIR}/src/gui/layertree ${CMAKE_SOURCE_DIR}/src/gui/layout ${CMAKE_SOURCE_DIR}/src/gui/locator + ${CMAKE_SOURCE_DIR}/src/gui/maptools ${CMAKE_SOURCE_DIR}/src/gui/mesh ${CMAKE_SOURCE_DIR}/src/gui/numericformats ${CMAKE_SOURCE_DIR}/src/gui/ogr diff --git a/images/images.qrc b/images/images.qrc index 8e6616378ace..d082e9637396 100644 --- a/images/images.qrc +++ b/images/images.qrc @@ -290,7 +290,9 @@ themes/default/mActionDeleteTable.svg themes/default/mActionDeselectAll.svg themes/default/mActionDeselectActiveLayer.svg + themes/default/mActionDigitizeShape.svg themes/default/mActionDigitizeWithCurve.svg + themes/default/mActionDigitizeWithSegment.svg themes/default/mActionDuplicateLayer.svg themes/default/mActionDuplicateComposer.svg themes/default/mActionEditCopy.svg diff --git a/images/themes/default/mActionDigitizeShape.svg b/images/themes/default/mActionDigitizeShape.svg new file mode 100644 index 000000000000..9cc3f7f66936 --- /dev/null +++ b/images/themes/default/mActionDigitizeShape.svg @@ -0,0 +1,52 @@ + + + + + + + + + + diff --git a/images/themes/default/mActionDigitizeWithSegment.svg b/images/themes/default/mActionDigitizeWithSegment.svg new file mode 100644 index 000000000000..2268e62971ad --- /dev/null +++ b/images/themes/default/mActionDigitizeWithSegment.svg @@ -0,0 +1,67 @@ + + + + + + image/svg+xml + + + + + + + + + + diff --git a/python/gui/auto_additions/qgsmaptoolcapture.py b/python/gui/auto_additions/qgsmaptoolcapture.py new file mode 100644 index 000000000000..9b3591992f32 --- /dev/null +++ b/python/gui/auto_additions/qgsmaptoolcapture.py @@ -0,0 +1,2 @@ +# The following has been generated automatically from src/gui/qgsmaptoolcapture.h +QgsMapToolCapture.CaptureTechnique.baseClass = QgsMapToolCapture diff --git a/python/gui/auto_generated/maptools/qgsmaptoolcapturelayergeometry.sip.in b/python/gui/auto_generated/maptools/qgsmaptoolcapturelayergeometry.sip.in new file mode 100644 index 000000000000..6906409c8201 --- /dev/null +++ b/python/gui/auto_generated/maptools/qgsmaptoolcapturelayergeometry.sip.in @@ -0,0 +1,59 @@ +/************************************************************************ + * This file has been generated automatically from * + * * + * src/gui/maptools/qgsmaptoolcapturelayergeometry.h * + * * + * Do not edit manually ! Edit header and run scripts/sipify.pl again * + ************************************************************************/ + + + + +class QgsMapToolCaptureLayerGeometry : QgsMapToolCapture +{ +%Docstring(signature="appended") +:py:class:`QgsMapToolCaptureLayerGeometry` is a base class for map tools digitizing layer geometries +This map tool subclass automatically handles intersection avoidance with other layers in the active project whenever a geometry is digitized by the user. + +.. versionadded:: 3.26 +%End + +%TypeHeaderCode +#include "qgsmaptoolcapturelayergeometry.h" +%End + public: + QgsMapToolCaptureLayerGeometry( QgsMapCanvas *canvas, QgsAdvancedDigitizingDockWidget *cadDockWidget, CaptureMode mode ); +%Docstring +Constructor +%End + + private: + virtual void layerGeometryCaptured( const QgsGeometry &geometry ); +%Docstring +Called when the geometry is captured +A more specific handler is also called afterwards (layerPointCaptured, layerLineCaptured or layerPolygonCaptured) +%End + virtual void layerPointCaptured( const QgsPoint &point ); +%Docstring +Called when a point is captured +The generic :py:func:`~QgsMapToolCaptureLayerGeometry.geometryCaptured` signal will be emitted immediately before this point-specific signal. +%End + virtual void layerLineCaptured( const QgsCurve *line ); +%Docstring +Called when a line is captured +The generic :py:func:`~QgsMapToolCaptureLayerGeometry.geometryCaptured` signal will be emitted immediately before this line-specific signal. +%End + virtual void layerPolygonCaptured( const QgsCurvePolygon *polygon ); +%Docstring +Called when a polygon is captured +The generic :py:func:`~QgsMapToolCaptureLayerGeometry.geometryCaptured` signal will be emitted immediately before this polygon-specific signal. +%End +}; + +/************************************************************************ + * This file has been generated automatically from * + * * + * src/gui/maptools/qgsmaptoolcapturelayergeometry.h * + * * + * Do not edit manually ! Edit header and run scripts/sipify.pl again * + ************************************************************************/ diff --git a/python/gui/auto_generated/qgisinterface.sip.in b/python/gui/auto_generated/qgisinterface.sip.in index 4b2862810ee6..49c686a4ac47 100644 --- a/python/gui/auto_generated/qgisinterface.sip.in +++ b/python/gui/auto_generated/qgisinterface.sip.in @@ -672,69 +672,133 @@ Returns the Hide Deselected Layers action. virtual QAction *actionCheckQgisVersion() = 0; virtual QAction *actionAbout() = 0; - virtual QAction *actionCircle2Points() = 0; + + virtual QAction *actionCircle2Points() /Deprecated/; %Docstring Returns the native add circle from 2 points action. Call :py:func:`~QgisInterface.trigger` on it to set the map tool. + +.. deprecated:: QGIS 3.26 + shape digitizing is now part of the add feature tool. To enable the shape tool, use :py:func:`QgsMapToolCapture.setCurrentCaptureTechnique()` and then :py:func:`QgsMapToolCapture.setCurrentShapeMapTool()`. %End - virtual QAction *actionCircle3Points() = 0; + + virtual QAction *actionCircle3Points() /Deprecated/; %Docstring Returns the native add circle from 3 points action. Call :py:func:`~QgisInterface.trigger` on it to set the map tool. + +.. deprecated:: QGIS 3.26 + shape digitizing is now part of the add feature tool. To enable the shape tool, use :py:func:`QgsMapToolCapture.setCurrentCaptureTechnique()` and then :py:func:`QgsMapToolCapture.setCurrentShapeMapTool()`. %End - virtual QAction *actionCircle3Tangents() = 0; + + virtual QAction *actionCircle3Tangents() /Deprecated/; %Docstring Returns the native add circle from 3 tangents action. Call :py:func:`~QgisInterface.trigger` on it to set the map tool. + +.. deprecated:: QGIS 3.26 + shape digitizing is now part of the add feature tool. To enable the shape tool, use :py:func:`QgsMapToolCapture.setCurrentCaptureTechnique()` and then :py:func:`QgsMapToolCapture.setCurrentShapeMapTool()`. %End - virtual QAction *actionCircle2TangentsPoint() = 0; + + virtual QAction *actionCircle2TangentsPoint() /Deprecated/; %Docstring Returns the native add circle from 2 tangents and a point action. Call :py:func:`~QgisInterface.trigger` on it to set the map tool. + +.. deprecated:: QGIS 3.26 + shape digitizing is now part of the add feature tool. To enable the shape tool, use :py:func:`QgsMapToolCapture.setCurrentCaptureTechnique()` and then :py:func:`QgsMapToolCapture.setCurrentShapeMapTool()`. %End - virtual QAction *actionCircleCenterPoint() = 0; + + virtual QAction *actionCircleCenterPoint() /Deprecated/; %Docstring Returns the native add circle from center action. Call :py:func:`~QgisInterface.trigger` on it to set the map tool. + +.. deprecated:: QGIS 3.26 + shape digitizing is now part of the add feature tool. To enable the shape tool, use :py:func:`QgsMapToolCapture.setCurrentCaptureTechnique()` and then :py:func:`QgsMapToolCapture.setCurrentShapeMapTool()`. %End - virtual QAction *actionEllipseCenter2Points() = 0; + + virtual QAction *actionEllipseCenter2Points() /Deprecated/; %Docstring Returns the native add ellipse from center and 2 points action. Call :py:func:`~QgisInterface.trigger` on it to set the map tool. + +.. deprecated:: QGIS 3.26 + shape digitizing is now part of the add feature tool. To enable the shape tool, use :py:func:`QgsMapToolCapture.setCurrentCaptureTechnique()` and then :py:func:`QgsMapToolCapture.setCurrentShapeMapTool()`. %End - virtual QAction *actionEllipseCenterPoint() = 0; + + virtual QAction *actionEllipseCenterPoint() /Deprecated/; %Docstring Returns the native add ellipse from center and a point action. Call :py:func:`~QgisInterface.trigger` on it to set the map tool. + +.. deprecated:: QGIS 3.26 + shape digitizing is now part of the add feature tool. To enable the shape tool, use :py:func:`QgsMapToolCapture.setCurrentCaptureTechnique()` and then :py:func:`QgsMapToolCapture.setCurrentShapeMapTool()`. %End - virtual QAction *actionEllipseExtent() = 0; + + virtual QAction *actionEllipseExtent() /Deprecated/; %Docstring Returns the native add ellipse from an extent action. Call :py:func:`~QgisInterface.trigger` on it to set the map tool. + +.. deprecated:: QGIS 3.26 + shape digitizing is now part of the add feature tool. To enable the shape tool, use :py:func:`QgsMapToolCapture.setCurrentCaptureTechnique()` and then :py:func:`QgsMapToolCapture.setCurrentShapeMapTool()`. %End - virtual QAction *actionEllipseFoci() = 0; + + virtual QAction *actionEllipseFoci() /Deprecated/; %Docstring Returns the native add ellipse from foci action. Call :py:func:`~QgisInterface.trigger` on it to set the map tool. + +.. deprecated:: QGIS 3.26 + shape digitizing is now part of the add feature tool. To enable the shape tool, use :py:func:`QgsMapToolCapture.setCurrentCaptureTechnique()` and then :py:func:`QgsMapToolCapture.setCurrentShapeMapTool()`. %End - virtual QAction *actionRectangleCenterPoint() = 0; + + virtual QAction *actionRectangleCenterPoint() /Deprecated/; %Docstring Returns the native add rectangle from center and a point action. Call :py:func:`~QgisInterface.trigger` on it to set the map tool. + +.. deprecated:: QGIS 3.26 + shape digitizing is now part of the add feature tool. To enable the shape tool, use :py:func:`QgsMapToolCapture.setCurrentCaptureTechnique()` and then :py:func:`QgsMapToolCapture.setCurrentShapeMapTool()`. %End - virtual QAction *actionRectangleExtent() = 0; + + virtual QAction *actionRectangleExtent() /Deprecated/; %Docstring Returns the native add rectangle from extent action. Call :py:func:`~QgisInterface.trigger` on it to set the map tool. + +.. deprecated:: QGIS 3.26 + shape digitizing is now part of the add feature tool. To enable the shape tool, use :py:func:`QgsMapToolCapture.setCurrentCaptureTechnique()` and then :py:func:`QgsMapToolCapture.setCurrentShapeMapTool()`. %End - virtual QAction *actionRectangle3PointsDistance() = 0; + + virtual QAction *actionRectangle3PointsDistance() /Deprecated/; %Docstring Returns the native add rectangle from 3 points (distance from 2nd and 3rd points) action. Call :py:func:`~QgisInterface.trigger` on it to set the map tool. + +.. deprecated:: QGIS 3.26 + shape digitizing is now part of the add feature tool. To enable the shape tool, use :py:func:`QgsMapToolCapture.setCurrentCaptureTechnique()` and then :py:func:`QgsMapToolCapture.setCurrentShapeMapTool()`. %End - virtual QAction *actionRectangle3PointsProjected() = 0; + + virtual QAction *actionRectangle3PointsProjected() /Deprecated/; %Docstring Returns the native add rectangle from 3 points (distance from projected 3rd point on segment p1 and p2) action. Call :py:func:`~QgisInterface.trigger` on it to set the map tool. + +.. deprecated:: QGIS 3.26 + shape digitizing is now part of the add feature tool. To enable the shape tool, use :py:func:`QgsMapToolCapture.setCurrentCaptureTechnique()` and then :py:func:`QgsMapToolCapture.setCurrentShapeMapTool()`. %End - virtual QAction *actionRegularPolygon2Points() = 0; + + virtual QAction *actionRegularPolygon2Points() /Deprecated/; %Docstring Returns the native add regular polygon from 2 points action. Call :py:func:`~QgisInterface.trigger` on it to set the map tool. + +.. deprecated:: QGIS 3.26 + shape digitizing is now part of the add feature tool. To enable the shape tool, use :py:func:`QgsMapToolCapture.setCurrentCaptureTechnique()` and then :py:func:`QgsMapToolCapture.setCurrentShapeMapTool()`. %End - virtual QAction *actionRegularPolygonCenterPoint() = 0; + + virtual QAction *actionRegularPolygonCenterPoint() /Deprecated/; %Docstring Returns the native add regular polygon from center and a point action. Call :py:func:`~QgisInterface.trigger` on it to set the map tool. + +.. deprecated:: QGIS 3.26 + shape digitizing is now part of the add feature tool. To enable the shape tool, use :py:func:`QgsMapToolCapture.setCurrentCaptureTechnique()` and then :py:func:`QgsMapToolCapture.setCurrentShapeMapTool()`. %End - virtual QAction *actionRegularPolygonCenterCorner() = 0; + + virtual QAction *actionRegularPolygonCenterCorner() /Deprecated/; %Docstring Returns the native add regular polygon from center and a corner action. Call :py:func:`~QgisInterface.trigger` on it to set the map tool. + +.. deprecated:: QGIS 3.26 + shape digitizing is now part of the add feature tool. To enable the shape tool, use :py:func:`QgsMapToolCapture.setCurrentCaptureTechnique()` and then :py:func:`QgsMapToolCapture.setCurrentShapeMapTool()`. %End virtual QgsVectorLayerTools *vectorLayerTools() = 0; diff --git a/python/gui/auto_generated/qgsmaptool.sip.in b/python/gui/auto_generated/qgsmaptool.sip.in index 1fb5a68c4f7c..734c23406d91 100644 --- a/python/gui/auto_generated/qgsmaptool.sip.in +++ b/python/gui/auto_generated/qgsmaptool.sip.in @@ -261,6 +261,11 @@ The default implementation does nothing and returns false. is present in :py:func:`~QgsMapTool.flags`. .. versionadded:: 3.18 +%End + + QgsPointXY toMapCoordinates( QPoint point ); +%Docstring +Transforms a ``point`` from screen coordinates to map coordinates. %End signals: @@ -289,11 +294,6 @@ signal emitted once the map tool is deactivated QgsMapTool( QgsMapCanvas *canvas /TransferThis/ ); %Docstring Constructor takes a map canvas as a parameter. -%End - - QgsPointXY toMapCoordinates( QPoint point ); -%Docstring -Transforms a ``point`` from screen coordinates to map coordinates. %End QgsPoint toLayerCoordinates( const QgsMapLayer *layer, const QgsPoint &point ) /PyName=toLayerCoordinatesV2/; diff --git a/python/gui/auto_generated/qgsmaptoolcapture.sip.in b/python/gui/auto_generated/qgsmaptoolcapture.sip.in index 7ed60961f449..daef29408040 100644 --- a/python/gui/auto_generated/qgsmaptoolcapture.sip.in +++ b/python/gui/auto_generated/qgsmaptoolcapture.sip.in @@ -14,6 +14,12 @@ class QgsMapToolCapture : QgsMapToolAdvancedDigitizing { +%Docstring(signature="appended") +:py:class:`QgsMapToolCapture` is a base class capable of capturing point, lines and polygons. +The tool supports different techniques: straight segments, curves, streaming and shapes +Once the the geometry is captured the virtual private handler geometryCaptured is called +as well as a more specific handler (pointCaptured, lineCaptured or polygonCaptured) +%End %TypeHeaderCode #include "qgsmaptoolcapture.h" @@ -33,6 +39,7 @@ class QgsMapToolCapture : QgsMapToolAdvancedDigitizing StraightSegments, CircularString, Streaming, + Shape, }; enum Capability @@ -64,6 +71,14 @@ Returns ``True`` if the tool supports the specified capture ``technique``. .. versionadded:: 3.20 %End + void setCurrentCaptureTechnique( CaptureTechnique technique ); +%Docstring +Sets the current capture if it is supported by the map tool + +.. versionadded:: 3.26 +%End + + virtual void activate(); virtual void deactivate(); @@ -104,6 +119,8 @@ Returns a list of matches for each point on the captureCurve. virtual void cadCanvasMoveEvent( QgsMapMouseEvent *e ); + virtual void cadCanvasReleaseEvent( QgsMapMouseEvent *e ); + virtual void keyPressEvent( QKeyEvent *e ); @@ -132,17 +149,52 @@ transfers ownership to the caller. .. versionadded:: 3.8 %End + QgsPoint mapPoint( const QgsMapMouseEvent &e ) const; +%Docstring +Creates a :py:class:`QgsPoint` with ZM support if necessary (according to the +WkbType of the current layer). If the point is snapped, then the Z +value is derived from the snapped point. + +:param e: A mouse event + +:return: a point with ZM support if necessary + + +.. versionadded:: 3.0 +%End + + QgsPoint mapPoint( const QgsPointXY &point ) const; +%Docstring +Creates a :py:class:`QgsPoint` with ZM support if necessary (according to the +WkbType of the current layer). + +:param point: A point in 2D + +:return: a point with ZM support if necessary + + +.. versionadded:: 3.0 +%End + + public slots: - void setCircularDigitizingEnabled( bool enable ); + + void setCircularDigitizingEnabled( bool enable ) /Deprecated/; %Docstring Enable the digitizing with curve + +.. deprecated:: QGIS 3.26 + use :py:func:`~QgsMapToolCapture.setCurrentCaptureTechnique` instead %End - void setStreamDigitizingEnabled( bool enable ); + void setStreamDigitizingEnabled( bool enable ) /Deprecated/; %Docstring Toggles the stream digitizing mode. .. versionadded:: 3.20 + +.. deprecated:: QGIS 3.26 + use :py:func:`~QgsMapToolCapture.setCurrentCaptureTechnique` instead %End protected: @@ -187,34 +239,6 @@ CRS as the current layer. .. versionadded:: 2.14 %End - QgsPoint mapPoint( const QgsMapMouseEvent &e ) const; -%Docstring -Creates a :py:class:`QgsPoint` with ZM support if necessary (according to the -WkbType of the current layer). If the point is snapped, then the Z -value is took from the snapped point. - -:param e: A mouse event - -:return: a point with ZM support if necessary - - -.. versionadded:: 3.0 -%End - - QgsPoint mapPoint( const QgsPointXY &point ) const; -%Docstring -Creates a :py:class:`QgsPoint` with ZM support if necessary (according to the -WkbType of the current layer). - -:param point: A point in 2D - -:return: a point with ZM support if necessary - - -.. versionadded:: 3.0 -%End - - int addVertex( const QgsPointXY &point ); %Docstring Adds a point to the rubber band (in map coordinates) and to the capture list (in layer coordinates) @@ -310,6 +334,35 @@ Close an open polygon Stop capturing %End + private: + virtual void geometryCaptured( const QgsGeometry &geometry ); +%Docstring +Called when the geometry is captured +A more specific handler is also called afterwards (pointCaptured, lineCaptured or polygonCaptured) + +.. versionadded:: 3.26 +%End + virtual void pointCaptured( const QgsPoint &point ); +%Docstring +Called when a point is captured +geometryCaptured is called just before + +.. versionadded:: 3.26 +%End + virtual void lineCaptured( const QgsCurve *line ); +%Docstring +Called when a line is captured +geometryCaptured is called just before + +.. versionadded:: 3.26 +%End + virtual void polygonCaptured( const QgsCurvePolygon *polygon ); +%Docstring +Called when a polygon is captured +geometryCaptured is called just before + +.. versionadded:: 3.26 +%End }; QFlags operator|(QgsMapToolCapture::Capability f1, QFlags f2); diff --git a/python/gui/auto_generated/qgsmaptooldigitizefeature.sip.in b/python/gui/auto_generated/qgsmaptooldigitizefeature.sip.in index 18fc810c3ff2..862ca9489809 100644 --- a/python/gui/auto_generated/qgsmaptooldigitizefeature.sip.in +++ b/python/gui/auto_generated/qgsmaptooldigitizefeature.sip.in @@ -8,7 +8,7 @@ -class QgsMapToolDigitizeFeature : QgsMapToolCapture +class QgsMapToolDigitizeFeature : QgsMapToolCaptureLayerGeometry { %Docstring(signature="appended") This tool digitizes geometry of new point/line/polygon features on already existing vector layers @@ -61,7 +61,7 @@ Emitted whenever the digitizing has been successfully completed :param feature: the new digitized feature %End - void digitizingFinished( ); + void digitizingFinished(); %Docstring Emitted whenever the digitizing has been ended without digitizing any feature @@ -83,6 +83,13 @@ Check if CaptureMode matches layer type. Default is ``True``. .. versionadded:: 3.0 %End + private: + virtual void featureDigitized( const QgsFeature &feature ); +%Docstring +Called when the feature has been digitized + +.. versionadded:: 3.26 +%End }; /************************************************************************ diff --git a/python/gui/auto_generated/qgsmaptooledit.sip.in b/python/gui/auto_generated/qgsmaptooledit.sip.in index 873327e644ce..1f21384413ac 100644 --- a/python/gui/auto_generated/qgsmaptooledit.sip.in +++ b/python/gui/auto_generated/qgsmaptooledit.sip.in @@ -35,6 +35,16 @@ Returns default M value. Used for setting M coordinate to new vertex. .. versionadded:: 3.20 +%End + + QgsGeometryRubberBand *createGeometryRubberBand( QgsWkbTypes::GeometryType geometryType = QgsWkbTypes::LineGeometry, bool alternativeBand = false ) const /Factory/; +%Docstring +Creates a geometry rubber band with the color/line width from +the QGIS settings. The caller takes ownership of the +returned object + +:param geometryType: +:param alternativeBand: if ``True``, rubber band will be set with more transparency and a dash pattern. default is ``False``. %End protected: @@ -62,8 +72,6 @@ returned object :param alternativeBand: if ``True``, rubber band will be set with more transparency and a dash pattern. default is ``False``. %End - QgsGeometryRubberBand *createGeometryRubberBand( QgsWkbTypes::GeometryType geometryType = QgsWkbTypes::LineGeometry, bool alternativeBand = false ) const /Factory/; - QgsVectorLayer *currentVectorLayer(); %Docstring Returns the current vector layer of the map canvas or 0 diff --git a/python/gui/gui_auto.sip b/python/gui/gui_auto.sip index 8bbc90550550..62e6b1e8effa 100644 --- a/python/gui/gui_auto.sip +++ b/python/gui/gui_auto.sip @@ -354,6 +354,7 @@ %Include auto_generated/layout/qgslayoutviewtooltemporarymousepan.sip %Include auto_generated/layout/qgslayoutviewtoolzoom.sip %Include auto_generated/locator/qgslocatorwidget.sip +%Include auto_generated/maptools/qgsmaptoolcapturelayergeometry.sip %Include auto_generated/mesh/qgsmeshlayerproperties.sip %Include auto_generated/numericformats/qgsnumericformatselectorwidget.sip %Include auto_generated/numericformats/qgsnumericformatwidget.sip diff --git a/src/app/CMakeLists.txt b/src/app/CMakeLists.txt index e95f7d67ccb8..7fb3d453c34c 100644 --- a/src/app/CMakeLists.txt +++ b/src/app/CMakeLists.txt @@ -157,29 +157,6 @@ set(QGIS_APP_SRCS qgsundowidget.cpp qgsmapthemes.cpp qgshandlebadlayers.cpp - qgsmaptooladdabstract.cpp - qgsmaptooladdcircularstring.cpp - qgsmaptoolcircularstringcurvepoint.cpp - qgsmaptoolcircularstringradius.cpp - qgsmaptooladdcircle.cpp - qgsmaptoolcircle2points.cpp - qgsmaptoolcircle3points.cpp - qgsmaptoolcircle3tangents.cpp - qgsmaptoolcircle2tangentspoint.cpp - qgsmaptoolcirclecenterpoint.cpp - qgsmaptooladdellipse.cpp - qgsmaptoolellipsefoci.cpp - qgsmaptoolellipseextent.cpp - qgsmaptoolellipsecenterpoint.cpp - qgsmaptoolellipsecenter2points.cpp - qgsmaptooladdrectangle.cpp - qgsmaptooladdregularpolygon.cpp - qgsmaptoolrectanglecenter.cpp - qgsmaptoolrectangleextent.cpp - qgsmaptoolrectangle3points.cpp - qgsmaptoolregularpolygon2points.cpp - qgsmaptoolregularpolygoncenterpoint.cpp - qgsmaptoolregularpolygoncentercorner.cpp browser/qgsinbuiltdataitemproviders.cpp @@ -225,6 +202,30 @@ set(QGIS_APP_SRCS locator/qgslocatoroptionswidget.cpp maptools/qgsappmaptools.cpp + maptools/qgsmaptoolsdigitizingtechniquemanager.cpp + + maptools/qgsmaptoolshapecircleabstract.cpp + maptools/qgsmaptoolshapecircularstringabstract.cpp + maptools/qgsmaptoolshapeellipseabstract.cpp + maptools/qgsmaptoolshaperectangleabstract.cpp + maptools/qgsmaptoolshaperegularpolygonabstract.cpp + + maptools/qgsmaptoolshapecircle2points.cpp + maptools/qgsmaptoolshapecircle2tangentspoint.cpp + maptools/qgsmaptoolshapecircle3points.cpp + maptools/qgsmaptoolshapecircle3tangents.cpp + maptools/qgsmaptoolshapecirclecenterpoint.cpp + maptools/qgsmaptoolshapecircularstringradius.cpp + maptools/qgsmaptoolshapeellipsecenter2points.cpp + maptools/qgsmaptoolshapeellipsecenterpoint.cpp + maptools/qgsmaptoolshapeellipseextent.cpp + maptools/qgsmaptoolshapeellipsefoci.cpp + maptools/qgsmaptoolshaperectangle3points.cpp + maptools/qgsmaptoolshaperectanglecenter.cpp + maptools/qgsmaptoolshaperectangleextent.cpp + maptools/qgsmaptoolshaperegularpolygon2points.cpp + maptools/qgsmaptoolshaperegularpolygoncentercorner.cpp + maptools/qgsmaptoolshaperegularpolygoncenterpoint.cpp options/qgsadvancedoptions.cpp options/qgscodeeditoroptions.cpp @@ -247,6 +248,7 @@ set(QGIS_APP_SRCS pluginmanager/qgspluginitemdelegate.cpp qgssettingstree.cpp + qgssettingsregistryapp.cpp qgsvariantdelegate.cpp qgscrashhandler.cpp diff --git a/src/app/maptools/qgsappmaptools.cpp b/src/app/maptools/qgsappmaptools.cpp index 478dc9c9e741..4e44415e4231 100644 --- a/src/app/maptools/qgsappmaptools.cpp +++ b/src/app/maptools/qgsappmaptools.cpp @@ -26,27 +26,10 @@ #include "qgsmaptooltextannotation.h" #include "qgsmaptoolhtmlannotation.h" #include "qgsmaptoolannotation.h" -#include "qgsmaptoolcircle2points.h" -#include "qgsmaptoolcircle3points.h" -#include "qgsmaptoolcircle2tangentspoint.h" #include "qgsmaptoolmeasureangle.h" #include "qgsmaptoolmeasurebearing.h" #include "qgsmaptoolformannotation.h" #include "qgsmaptoolsvgannotation.h" -#include "qgsmaptoolcircularstringcurvepoint.h" -#include "qgsmaptoolcircularstringradius.h" -#include "qgsmaptoolcircle3tangents.h" -#include "qgsmaptoolcirclecenterpoint.h" -#include "qgsmaptoolellipsecenter2points.h" -#include "qgsmaptoolellipsecenterpoint.h" -#include "qgsmaptoolellipseextent.h" -#include "qgsmaptoolellipsefoci.h" -#include "qgsmaptoolrectangle3points.h" -#include "qgsmaptoolrectanglecenter.h" -#include "qgsmaptoolrectangleextent.h" -#include "qgsmaptoolregularpolygon2points.h" -#include "qgsmaptoolregularpolygoncentercorner.h" -#include "qgsmaptoolregularpolygoncenterpoint.h" #include "qgsmaptoolrotatefeature.h" #include "qgsmaptoolscalefeature.h" #include "qgsmaptoolmovefeature.h" @@ -71,45 +54,9 @@ #include "qgsmaptoolpinlabels.h" #include "qgsmaptooloffsetpointsymbol.h" #include "qgsmaptooleditmeshframe.h" -#include "qgsspinbox.h" #include "qgssettingsregistrycore.h" #include "qgsmaptoolmodifyannotation.h" -// -// QgsStreamDigitizingSettingsAction -// - -QgsStreamDigitizingSettingsAction::QgsStreamDigitizingSettingsAction( QWidget *parent ) - : QWidgetAction( parent ) -{ - QGridLayout *gLayout = new QGridLayout(); - gLayout->setContentsMargins( 3, 2, 3, 2 ); - - mStreamToleranceSpinBox = new QgsSpinBox(); - mStreamToleranceSpinBox->setSuffix( tr( "px" ) ); - mStreamToleranceSpinBox->setKeyboardTracking( false ); - mStreamToleranceSpinBox->setRange( 1, 200 ); - mStreamToleranceSpinBox->setWrapping( false ); - mStreamToleranceSpinBox->setSingleStep( 1 ); - mStreamToleranceSpinBox->setClearValue( 2 ); - mStreamToleranceSpinBox->setValue( QgsSettingsRegistryCore::settingsDigitizingStreamTolerance.value() ); - - QLabel *label = new QLabel( tr( "Streaming Tolerance" ) ); - gLayout->addWidget( label, 1, 0 ); - gLayout->addWidget( mStreamToleranceSpinBox, 1, 1 ); - connect( mStreamToleranceSpinBox, qOverload( &QgsSpinBox::valueChanged ), this, [ = ]( int value ) - { - QgsSettingsRegistryCore::settingsDigitizingStreamTolerance.setValue( value ); - } ); - - QWidget *w = new QWidget( parent ); - w->setLayout( gLayout ); - setDefaultWidget( w ); -} - -QgsStreamDigitizingSettingsAction::~QgsStreamDigitizingSettingsAction() = default; - - // // QgsAppMapTools // @@ -131,25 +78,6 @@ QgsAppMapTools::QgsAppMapTools( QgsMapCanvas *canvas, QgsAdvancedDigitizingDockW mTools.insert( Tool::SvgAnnotation, new QgsMapToolSvgAnnotation( canvas ) ); mTools.insert( Tool::Annotation, new QgsMapToolAnnotation( canvas ) ); mTools.insert( Tool::AddFeature, new QgsMapToolAddFeature( canvas, QgsMapToolCapture::CaptureNone ) ); - QgsMapToolCapture *addFeatureTool = qobject_cast< QgsMapToolCapture *>( mTools.value( Tool::AddFeature ) ); - mTools.insert( Tool::CircularStringCurvePoint, new QgsMapToolCircularStringCurvePoint( addFeatureTool, canvas ) ); - mTools.insert( Tool::CircularStringRadius, new QgsMapToolCircularStringRadius( addFeatureTool, canvas ) ); - mTools.insert( Tool::Circle2Points, new QgsMapToolCircle2Points( addFeatureTool, canvas ) ); - mTools.insert( Tool::Circle3Points, new QgsMapToolCircle3Points( addFeatureTool, canvas ) ); - mTools.insert( Tool::Circle3Tangents, new QgsMapToolCircle3Tangents( addFeatureTool, canvas ) ); - mTools.insert( Tool::Circle2TangentsPoint, new QgsMapToolCircle2TangentsPoint( addFeatureTool, canvas ) ); - mTools.insert( Tool::CircleCenterPoint, new QgsMapToolCircleCenterPoint( addFeatureTool, canvas ) ); - mTools.insert( Tool::EllipseCenter2Points, new QgsMapToolEllipseCenter2Points( addFeatureTool, canvas ) ); - mTools.insert( Tool::EllipseCenterPoint, new QgsMapToolEllipseCenterPoint( addFeatureTool, canvas ) ); - mTools.insert( Tool::EllipseExtent, new QgsMapToolEllipseExtent( addFeatureTool, canvas ) ); - mTools.insert( Tool::EllipseFoci, new QgsMapToolEllipseFoci( addFeatureTool, canvas ) ); - mTools.insert( Tool::RectangleCenterPoint, new QgsMapToolRectangleCenter( addFeatureTool, canvas ) ); - mTools.insert( Tool::RectangleExtent, new QgsMapToolRectangleExtent( addFeatureTool, canvas ) ); - mTools.insert( Tool::Rectangle3PointsDistance, new QgsMapToolRectangle3Points( addFeatureTool, canvas, QgsMapToolRectangle3Points::DistanceMode ) ); - mTools.insert( Tool::Rectangle3PointsProjected, new QgsMapToolRectangle3Points( addFeatureTool, canvas, QgsMapToolRectangle3Points::ProjectedMode ) ); - mTools.insert( Tool::RegularPolygon2Points, new QgsMapToolRegularPolygon2Points( addFeatureTool, canvas ) ); - mTools.insert( Tool::RegularPolygonCenterPoint, new QgsMapToolRegularPolygonCenterPoint( addFeatureTool, canvas ) ); - mTools.insert( Tool::RegularPolygonCenterCorner, new QgsMapToolRegularPolygonCenterCorner( addFeatureTool, canvas ) ); mTools.insert( Tool::MoveFeature, new QgsMapToolMoveFeature( canvas, QgsMapToolMoveFeature::Move ) ); mTools.insert( Tool::MoveFeatureCopy, new QgsMapToolMoveFeature( canvas, QgsMapToolMoveFeature::CopyMove ) ); mTools.insert( Tool::RotateFeature, new QgsMapToolRotateFeature( canvas ) ); @@ -181,8 +109,6 @@ QgsAppMapTools::QgsAppMapTools( QgsMapCanvas *canvas, QgsAdvancedDigitizingDockW mTools.insert( Tool::ChangeLabelProperties, new QgsMapToolChangeLabelProperties( canvas, cadDock ) ); mTools.insert( Tool::EditMeshFrame, new QgsMapToolEditMeshFrame( canvas ) ); mTools.insert( Tool::AnnotationEdit, new QgsMapToolModifyAnnotation( canvas, cadDock ) ); - - mStreamDigitizingSettingsAction = new QgsStreamDigitizingSettingsAction( QgisApp::instance() ); } QgsAppMapTools::~QgsAppMapTools() @@ -210,8 +136,4 @@ QList QgsAppMapTools::captureTools() const return res; } -QWidgetAction *QgsAppMapTools::streamDigitizingSettingsAction() -{ - return mStreamDigitizingSettingsAction; -} diff --git a/src/app/maptools/qgsappmaptools.h b/src/app/maptools/qgsappmaptools.h index dbd78468a31d..f8df1b297ddf 100644 --- a/src/app/maptools/qgsappmaptools.h +++ b/src/app/maptools/qgsappmaptools.h @@ -19,7 +19,6 @@ #include #include #include -#include class QgsMapTool; @@ -27,21 +26,6 @@ class QgsMapToolCapture; class QgsMapCanvas; class QgsAdvancedDigitizingDockWidget; -class QgsSpinBox; - -class QgsStreamDigitizingSettingsAction: public QWidgetAction -{ - Q_OBJECT - - public: - - QgsStreamDigitizingSettingsAction( QWidget *parent = nullptr ); - ~QgsStreamDigitizingSettingsAction() override; - - private: - QgsSpinBox *mStreamToleranceSpinBox = nullptr; -}; - class QgsAppMapTools { @@ -58,24 +42,6 @@ class QgsAppMapTools MeasureAngle, MeasureBearing, AddFeature, - CircularStringCurvePoint, - CircularStringRadius, - Circle2Points, - Circle3Points, - Circle3Tangents, - Circle2TangentsPoint, - CircleCenterPoint, - EllipseCenter2Points, - EllipseCenterPoint, - EllipseExtent, - EllipseFoci, - RectangleCenterPoint, - RectangleExtent, - Rectangle3PointsDistance, - Rectangle3PointsProjected, - RegularPolygon2Points, - RegularPolygonCenterPoint, - RegularPolygonCenterCorner, MoveFeature, MoveFeatureCopy, OffsetCurve, @@ -139,15 +105,9 @@ class QgsAppMapTools */ QList< QgsMapToolCapture * > captureTools() const; - /** - * Returns the stream digitizing settings action; - */ - QWidgetAction *streamDigitizingSettingsAction(); - private: QHash< Tool, QPointer< QgsMapTool > > mTools; - QgsStreamDigitizingSettingsAction *mStreamDigitizingSettingsAction = nullptr; // Disable copying as we have pointer members. QgsAppMapTools( const QgsAppMapTools & ) = delete; diff --git a/src/app/maptools/qgsmaptoolsdigitizingtechniquemanager.cpp b/src/app/maptools/qgsmaptoolsdigitizingtechniquemanager.cpp new file mode 100644 index 000000000000..96336ed34d11 --- /dev/null +++ b/src/app/maptools/qgsmaptoolsdigitizingtechniquemanager.cpp @@ -0,0 +1,306 @@ +/*************************************************************************** + qgsmaptoolsdigitizingtechniquemanager.cpp + ---------------------- + begin : January 2022 + copyright : (C) 2022 by Denis Rouzaud + email : denis@opengis.ch + ***************************************************************************/ + +/*************************************************************************** + * * + * 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 "qgsmaptoolsdigitizingtechniquemanager.h" +#include "qgisapp.h" +#include "qgsappmaptools.h" +#include "qgsmaptoolcapture.h" +#include "qgsmaptoolshaperegistry.h" +#include "qgsgui.h" +#include "qgsmapcanvas.h" +#include "qgsspinbox.h" +#include "qgssettingsregistrycore.h" + + +#include +#include +#include + +QgsMapToolsDigitizingTechniqueManager::QgsMapToolsDigitizingTechniqueManager( QObject *parent ) + : QObject( parent ) +{ + mTechniqueActions.insert( QgsMapToolCapture::CaptureTechnique::StraightSegments, QgisApp::instance()->mActionDigitizeWithSegment ); + mTechniqueActions.insert( QgsMapToolCapture::CaptureTechnique::CircularString, QgisApp::instance()->mActionDigitizeWithCurve ); + mTechniqueActions.insert( QgsMapToolCapture::CaptureTechnique::Streaming, QgisApp::instance()->mActionStreamDigitize ); + mTechniqueActions.insert( QgsMapToolCapture::CaptureTechnique::Shape, QgisApp::instance()->mActionDigitizeShape ); + + mDigitizeModeToolButton = new QToolButton(); + mDigitizeModeToolButton->setPopupMode( QToolButton::MenuButtonPopup ); +} + +void QgsMapToolsDigitizingTechniqueManager::setupCanvasTools() +{ + const QList< QgsMapToolCapture * > captureTools = QgisApp::instance()->captureTools(); + for ( QgsMapToolCapture *tool : captureTools ) + { + connect( tool->action(), &QAction::toggled, this, [this, tool]( bool checked ) { enableDigitizingTechniqueActions( checked, tool->action() ); } ); + } +} + +void QgsMapToolsDigitizingTechniqueManager::setupToolBars() +{ + // digitize mode button + QMenu *digitizeMenu = new QMenu( mDigitizeModeToolButton ); + QActionGroup *actionGroup = new QActionGroup( digitizeMenu ); + + QMap::const_iterator it = mTechniqueActions.constBegin(); + for ( ; it != mTechniqueActions.constEnd(); ++ it ) + { + digitizeMenu->addAction( it.value() ); + actionGroup->addAction( it.value() ); + connect( it.value(), &QAction::triggered, this, [ = ]( bool checked ) + { + Q_UNUSED( checked ); + setCaptureTechnique( it.key() ); + } ); + } + QgisApp::instance()->mActionStreamDigitize->setShortcut( tr( "R", "Keyboard shortcut: toggle stream digitizing" ) ); + + mStreamDigitizingSettingsAction = new QgsStreamDigitizingSettingsAction( QgisApp::instance() ); + + digitizeMenu->addSeparator(); + digitizeMenu->addAction( mStreamDigitizingSettingsAction ); + mDigitizeModeToolButton->setMenu( digitizeMenu ); + + const QgsMapToolCapture::CaptureTechnique technique = settingsDigitizingTechnique.value(); + switch ( technique ) + { + case QgsMapToolCapture::CaptureTechnique::StraightSegments: + mDigitizeModeToolButton->setDefaultAction( QgisApp::instance()->mActionDigitizeWithSegment ); + break; + case QgsMapToolCapture::CaptureTechnique::CircularString: + mDigitizeModeToolButton->setDefaultAction( QgisApp::instance()->mActionDigitizeWithCurve ); + break; + case QgsMapToolCapture::CaptureTechnique::Streaming: + mDigitizeModeToolButton->setDefaultAction( QgisApp::instance()->mActionStreamDigitize ); + break; + case QgsMapToolCapture::CaptureTechnique::Shape: + mDigitizeModeToolButton->setDefaultAction( QgisApp::instance()->mActionDigitizeShape ); + break; + } + + QgisApp::instance()->mAdvancedDigitizeToolBar->insertWidget( QgisApp::instance()->mAdvancedDigitizeToolBar->actions().at( 0 ), mDigitizeModeToolButton ); + + // Digitizing shape tools + const QList mapTools = QgsGui::mapToolShapeRegistry()->mapToolMetadatas(); + for ( const QgsMapToolShapeMetadata *metadata : mapTools ) + { + QToolButton *shapeButton = nullptr; + if ( !mShapeCategoryButtons.contains( metadata->category() ) ) + { + shapeButton = new QToolButton( QgisApp::instance()->mShapeDigitizeToolBar ); + shapeButton->setPopupMode( QToolButton::MenuButtonPopup ); + shapeButton->setMenu( new QMenu( ) ); + + QgisApp::instance()->mShapeDigitizeToolBar->addWidget( shapeButton ); + QObject::connect( shapeButton, &QToolButton::triggered, this, [ = ]( QAction * action ) {setShapeTool( action->data().toString() );} ); + + mShapeCategoryButtons.insert( metadata->category(), shapeButton ); + } + else + { + shapeButton = mShapeCategoryButtons[metadata->category()]; + } + + QMenu *shapeMenu = shapeButton->menu(); + QAction *action = new QAction( metadata->icon(), metadata->name(), shapeMenu ); + action->setCheckable( true ); + action->setData( metadata->id() ); + shapeMenu->addAction( action ); + QString defaultToolId = settingMapToolShapeDefaultForShape.value( qgsEnumValueToKey( metadata->category() ) ); + if ( defaultToolId.isEmpty() ) + { + // if no default tool for category, take the first one + defaultToolId = metadata->id(); + settingMapToolShapeDefaultForShape.setValue( metadata->id(), qgsEnumValueToKey( metadata->category() ) ); + } + if ( defaultToolId == metadata->id() ) + shapeButton->setDefaultAction( action ); + + mShapeActions.insert( metadata->id(), action ); + } +} + +QgsMapToolsDigitizingTechniqueManager::~QgsMapToolsDigitizingTechniqueManager() +{ + +} + +void QgsMapToolsDigitizingTechniqueManager::setCaptureTechnique( QgsMapToolCapture::CaptureTechnique technique, bool alsoSetShapeTool ) +{ + settingsDigitizingTechnique.setValue( technique ); + + mTechniqueActions.value( technique )->setChecked( true ); + + switch ( technique ) + { + case QgsMapToolCapture::StraightSegments: + mDigitizeModeToolButton->setDefaultAction( QgisApp::instance()->mActionDigitizeWithSegment ); + break; + case QgsMapToolCapture::CircularString: + mDigitizeModeToolButton->setDefaultAction( QgisApp::instance()->mActionDigitizeWithCurve ); + break; + case QgsMapToolCapture::Streaming: + mDigitizeModeToolButton->setDefaultAction( QgisApp::instance()->mActionStreamDigitize ); + break; + case QgsMapToolCapture::Shape: + mDigitizeModeToolButton->setDefaultAction( QgisApp::instance()->mActionDigitizeShape ); + break; + } + + // QgisApp::captureTools returns all registered capture tools + the eventual current capture tool + const QList< QgsMapToolCapture * > tools = QgisApp::instance()->captureTools(); + for ( QgsMapToolCapture *tool : tools ) + { + if ( tool->supportsTechnique( technique ) ) + { + tool->setCurrentCaptureTechnique( technique ); + } + } + + if ( technique == QgsMapToolCapture::Shape && alsoSetShapeTool ) + { + setShapeTool( settingMapToolShapeCurrent.value() ); + } + else if ( technique != QgsMapToolCapture::Shape ) + { + // uncheck all the shape tools + QHash::iterator sit = mShapeActions.begin(); + for ( ; sit != mShapeActions.end(); ++ sit ) + sit.value()->setChecked( false ); + } +} + +void QgsMapToolsDigitizingTechniqueManager::setShapeTool( const QString &shapeToolId ) +{ + QAction *action = nullptr; + + const QgsMapToolShapeMetadata *md = QgsGui::mapToolShapeRegistry()->mapToolMetadata( shapeToolId ); + if ( md ) + { + settingMapToolShapeDefaultForShape.setValue( md->id(), qgsEnumValueToKey( md->category() ) ); + settingMapToolShapeCurrent.setValue( md->id() ); + QToolButton *bt = mShapeCategoryButtons.value( md->category() ); + action = mShapeActions.value( md->id() ); + if ( bt && action ) + bt->setDefaultAction( action ); + } + QHash::iterator sit = mShapeActions.begin(); + for ( ; sit != mShapeActions.end(); ++ sit ) + sit.value()->setChecked( sit.value() == action ); + + setCaptureTechnique( QgsMapToolCapture::Shape, false ); + + // QgisApp::captureTools returns all registered capture tools + the eventual current capture tool + const QList< QgsMapToolCapture * > tools = QgisApp::instance()->captureTools(); + for ( QgsMapToolCapture *tool : tools ) + { + if ( tool->supportsTechnique( QgsMapToolCapture::CaptureTechnique::Shape ) ) + { + tool->setCurrentShapeMapTool( md ); + } + } +} + +void QgsMapToolsDigitizingTechniqueManager::enableDigitizingTechniqueActions( bool enabled, QAction *triggeredFromToolAction ) +{ + QgsSettings settings; + + // QgisApp::captureTools returns all registered capture tools + the eventual current capture tool + const QList< QgsMapToolCapture * > tools = QgisApp::instance()->captureTools(); + + const QgsMapToolCapture::CaptureTechnique currentTechnique = settingsDigitizingTechnique.value(); + const QString currentShapeToolId = settingMapToolShapeCurrent.value(); + + QSet< QgsMapToolCapture::CaptureTechnique > supportedTechniques; + if ( enabled ) + { + for ( QgsMapToolCapture *tool : tools ) + { + if ( triggeredFromToolAction == tool->action() || ( !triggeredFromToolAction && QgisApp::instance()->mapCanvas()->mapTool() == tool ) ) + { + for ( QgsMapToolCapture::CaptureTechnique technique : mTechniqueActions.keys() ) + { + if ( tool->supportsTechnique( technique ) ) + supportedTechniques.insert( technique ); + } + break; + } + } + } + + QMap::const_iterator cit = mTechniqueActions.constBegin(); + for ( ; cit != mTechniqueActions.constEnd(); ++ cit ) + { + cit.value()->setEnabled( enabled && supportedTechniques.contains( cit.key() ) ); + cit.value()->setChecked( cit.value()->isEnabled() && currentTechnique == cit.key() ); + } + + QHash::const_iterator sit = mShapeActions.constBegin(); + for ( ; sit != mShapeActions.constEnd(); ++ sit ) + { + sit.value()->setEnabled( enabled && supportedTechniques.contains( QgsMapToolCapture::CaptureTechnique::Shape ) ); + sit.value()->setChecked( currentTechnique == QgsMapToolCapture::CaptureTechnique::Shape && sit.value()->isEnabled() && sit.key() == currentShapeToolId ); + } + + for ( QgsMapToolCapture *tool : tools ) + { + if ( tool->supportsTechnique( currentTechnique ) ) + { + tool->setCurrentCaptureTechnique( currentTechnique ); + if ( currentTechnique == QgsMapToolCapture::CaptureTechnique::Shape ) + { + QgsMapToolShapeMetadata *md = QgsGui::mapToolShapeRegistry()->mapToolMetadata( settingMapToolShapeCurrent.value() ); + tool->setCurrentShapeMapTool( md ); + } + } + } +} + +// +// QgsStreamDigitizingSettingsAction +// + +QgsStreamDigitizingSettingsAction::QgsStreamDigitizingSettingsAction( QWidget *parent ) + : QWidgetAction( parent ) +{ + QGridLayout *gLayout = new QGridLayout(); + gLayout->setContentsMargins( 3, 2, 3, 2 ); + + mStreamToleranceSpinBox = new QgsSpinBox(); + mStreamToleranceSpinBox->setSuffix( tr( "px" ) ); + mStreamToleranceSpinBox->setKeyboardTracking( false ); + mStreamToleranceSpinBox->setRange( 1, 200 ); + mStreamToleranceSpinBox->setWrapping( false ); + mStreamToleranceSpinBox->setSingleStep( 1 ); + mStreamToleranceSpinBox->setClearValue( 2 ); + mStreamToleranceSpinBox->setValue( QgsSettingsRegistryCore::settingsDigitizingStreamTolerance.value() ); + + QLabel *label = new QLabel( tr( "Streaming Tolerance" ) ); + gLayout->addWidget( label, 1, 0 ); + gLayout->addWidget( mStreamToleranceSpinBox, 1, 1 ); + connect( mStreamToleranceSpinBox, qOverload( &QgsSpinBox::valueChanged ), this, [ = ]( int value ) + { + QgsSettingsRegistryCore::settingsDigitizingStreamTolerance.setValue( value ); + } ); + + QWidget *w = new QWidget( parent ); + w->setLayout( gLayout ); + setDefaultWidget( w ); +} + +QgsStreamDigitizingSettingsAction::~QgsStreamDigitizingSettingsAction() = default; diff --git a/src/app/maptools/qgsmaptoolsdigitizingtechniquemanager.h b/src/app/maptools/qgsmaptoolsdigitizingtechniquemanager.h new file mode 100644 index 000000000000..73ec6a2585e3 --- /dev/null +++ b/src/app/maptools/qgsmaptoolsdigitizingtechniquemanager.h @@ -0,0 +1,84 @@ +/*************************************************************************** + qgsmaptoolsdigitizingtechniquemanager.h + ---------------------- + begin : January 2022 + copyright : (C) 2022 by Denis Rouzaud + email : denis@opengis.ch + ***************************************************************************/ + +/*************************************************************************** + * * + * 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 QGSMAPTOOLSDIGITIZINGTECHNIQUEMANAGER_H +#define QGSMAPTOOLSDIGITIZINGTECHNIQUEMANAGER_H + +#include "qgis_app.h" +#include "qgssettingsentry.h" +#include "qgsmaptoolcapture.h" +#include "qgsmaptoolshapeabstract.h" + +#include + + +class QgsSpinBox; + +class QAction; +class QToolButton; + + +template class APP_EXPORT QgsSettingsEntryEnumFlag; + + +class APP_EXPORT QgsStreamDigitizingSettingsAction: public QWidgetAction +{ + Q_OBJECT + + public: + + QgsStreamDigitizingSettingsAction( QWidget *parent = nullptr ); + ~QgsStreamDigitizingSettingsAction() override; + + private: + QgsSpinBox *mStreamToleranceSpinBox = nullptr; +}; + +class APP_EXPORT QgsMapToolsDigitizingTechniqueManager : public QObject +{ + Q_OBJECT + public: + static const inline QgsSettingsEntryEnumFlag settingsDigitizingTechnique = QgsSettingsEntryEnumFlag( QStringLiteral( "/qgis/digitizing/technique" ), QgsSettings::NoSection, QgsMapToolCapture::CaptureTechnique::StraightSegments ) SIP_SKIP; + + static const inline QgsSettingsEntryString settingMapToolShapeDefaultForShape = QgsSettingsEntryString( QStringLiteral( "/qgis/digitizing/shape-map-tools/%1/default" ), QgsSettings::NoSection, QString(), QObject::tr( "Default map tool for given shape category" ) ) SIP_SKIP; + static const inline QgsSettingsEntryString settingMapToolShapeCurrent = QgsSettingsEntryString( QStringLiteral( "/qgis/digitizing/shape-map-tools/current" ), QgsSettings::NoSection, QString(), QObject::tr( "Current shape map tool" ) ) SIP_SKIP; + + QgsMapToolsDigitizingTechniqueManager( QObject *parent ); + ~QgsMapToolsDigitizingTechniqueManager(); + void setupToolBars(); + void setupCanvasTools(); + + public slots: + void enableDigitizingTechniqueActions( bool enabled, QAction *triggeredFromToolAction = nullptr ); + + + private slots: + void setCaptureTechnique( QgsMapToolCapture::CaptureTechnique technique, bool alsoSetShapeTool = true ); + void setShapeTool( const QString &shapeToolId ); + + private: + QMap mTechniqueActions; + QHash mShapeActions; + QMap mShapeCategoryButtons; + + QToolButton *mDigitizeModeToolButton = nullptr; + QgsStreamDigitizingSettingsAction *mStreamDigitizingSettingsAction = nullptr; + + +}; + +#endif // QGSMAPTOOLSDIGITIZINGTECHNIQUEMANAGER_H diff --git a/src/app/maptools/qgsmaptoolshapecircle2points.cpp b/src/app/maptools/qgsmaptoolshapecircle2points.cpp new file mode 100644 index 000000000000..a79d4d908c6c --- /dev/null +++ b/src/app/maptools/qgsmaptoolshapecircle2points.cpp @@ -0,0 +1,85 @@ +/*************************************************************************** + qgsmaptoolshapecircle2points.cpp - map tool for adding circle + from 2 points + --------------------- + begin : July 2017 + copyright : (C) 2017 by Loïc Bartoletti + email : lbartoletti at tuxfamily dot org + *************************************************************************** + * * + * 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 "qgsmaptoolshapecircle2points.h" +#include "qgsgeometryrubberband.h" +#include "qgsmapcanvas.h" +#include "qgsmapmouseevent.h" +#include "qgsmaptoolcapture.h" +#include "qgsapplication.h" + +const QString QgsMapToolShapeCircle2PointsMetadata::TOOL_ID = QStringLiteral( "circle-from-2-points" ); + +QString QgsMapToolShapeCircle2PointsMetadata::id() const +{ + return QgsMapToolShapeCircle2PointsMetadata::TOOL_ID; +} + +QString QgsMapToolShapeCircle2PointsMetadata::name() const +{ + return QObject::tr( "Circle from 2 points" ); +} + +QIcon QgsMapToolShapeCircle2PointsMetadata::icon() const +{ + return QgsApplication::getThemeIcon( QStringLiteral( "/mActionCircle2Points.svg" ) ); +} + +QgsMapToolShapeAbstract::ShapeCategory QgsMapToolShapeCircle2PointsMetadata::category() const +{ + return QgsMapToolShapeAbstract::ShapeCategory::Circle; +} + +QgsMapToolShapeAbstract *QgsMapToolShapeCircle2PointsMetadata::factory( QgsMapToolCapture *parentTool ) const +{ + return new QgsMapToolShapeCircle2Points( parentTool ); +} + + +bool QgsMapToolShapeCircle2Points::cadCanvasReleaseEvent( QgsMapMouseEvent *e, QgsMapToolCapture::CaptureMode mode ) +{ + if ( e->button() == Qt::LeftButton ) + { + if ( mPoints.isEmpty() ) + mPoints.append( mParentTool->mapPoint( *e ) ); + + if ( !mTempRubberBand ) + { + QgsWkbTypes::GeometryType type = mode == QgsMapToolCapture::CapturePolygon ? QgsWkbTypes::PolygonGeometry : QgsWkbTypes::LineGeometry; + mTempRubberBand = mParentTool->createGeometryRubberBand( type, true ); + mTempRubberBand->show(); + } + } + else if ( e->button() == Qt::RightButton ) + { + mPoints.append( mParentTool->mapPoint( *e ) ); + addCircleToParentTool(); + return true; + } + + return false; +} + +void QgsMapToolShapeCircle2Points::cadCanvasMoveEvent( QgsMapMouseEvent *e, QgsMapToolCapture::CaptureMode mode ) +{ + Q_UNUSED( mode ) + if ( !mTempRubberBand ) + return; + + mCircle = QgsCircle::from2Points( mPoints.at( 0 ), mParentTool->mapPoint( *e ) ); + mTempRubberBand->setGeometry( mCircle.toCircularString( true ) ); +} + diff --git a/src/app/maptools/qgsmaptoolshapecircle2points.h b/src/app/maptools/qgsmaptoolshapecircle2points.h new file mode 100644 index 000000000000..402810c68d63 --- /dev/null +++ b/src/app/maptools/qgsmaptoolshapecircle2points.h @@ -0,0 +1,52 @@ +/*************************************************************************** + qgsmaptoolshapecircle2points.h - map tool for adding circle + from 2 points + --------------------- + begin : July 2017 + copyright : (C) 2017 by Loïc Bartoletti + email : lbartoletti at tuxfamily dot org + *************************************************************************** + * * + * 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 QGSMAPTOOLSHAPECIRCLE2POINTS_H +#define QGSMAPTOOLSHAPECIRCLE2POINTS_H + +#include "qgsmaptoolshapecircleabstract.h" +#include "qgis_app.h" +#include "qgsmaptoolshaperegistry.h" + + +class APP_EXPORT QgsMapToolShapeCircle2PointsMetadata : public QgsMapToolShapeMetadata +{ + public: + QgsMapToolShapeCircle2PointsMetadata() + : QgsMapToolShapeMetadata() + {} + + static const QString TOOL_ID; + + QString id() const override; + QString name() const override; + QIcon icon() const override; + QgsMapToolShapeAbstract::ShapeCategory category() const override; + QgsMapToolShapeAbstract *factory( QgsMapToolCapture *parentTool ) const override; +}; + +class APP_EXPORT QgsMapToolShapeCircle2Points : public QgsMapToolShapeCircleAbstract +{ + public: + QgsMapToolShapeCircle2Points( QgsMapToolCapture *parentTool ) + : QgsMapToolShapeCircleAbstract( QgsMapToolShapeCircle2PointsMetadata::TOOL_ID, parentTool ) + {} + + bool cadCanvasReleaseEvent( QgsMapMouseEvent *e, QgsMapToolCapture::CaptureMode mode ) override; + void cadCanvasMoveEvent( QgsMapMouseEvent *e, QgsMapToolCapture::CaptureMode mode ) override; +}; + +#endif // QGSMAPTOOLSHAPECIRCLE2POINTS_H diff --git a/src/app/qgsmaptoolcircle2tangentspoint.cpp b/src/app/maptools/qgsmaptoolshapecircle2tangentspoint.cpp similarity index 71% rename from src/app/qgsmaptoolcircle2tangentspoint.cpp rename to src/app/maptools/qgsmaptoolshapecircle2tangentspoint.cpp index 458781a2bdbe..4f7f529ff6b2 100644 --- a/src/app/qgsmaptoolcircle2tangentspoint.cpp +++ b/src/app/maptools/qgsmaptoolshapecircle2tangentspoint.cpp @@ -1,5 +1,5 @@ /*************************************************************************** - qgsmaptoolcircle2tangentspoint.h - map tool for adding circle + qgsmaptoolshapecircle2tangentspoint.h - map tool for adding circle from 2 tangents and a point --------------------- begin : July 2017 @@ -14,7 +14,7 @@ * * ***************************************************************************/ -#include "qgsmaptoolcircle2tangentspoint.h" +#include "qgsmaptoolshapecircle2tangentspoint.h" #include "qgsgeometryrubberband.h" #include "qgsadvanceddigitizingdockwidget.h" #include "qgssnappingutils.h" @@ -29,36 +29,47 @@ #include #include "qgsmapmouseevent.h" #include "qgsmessagebar.h" -#include "qgssnapindicator.h" +#include "qgsmaptoolcapture.h" +#include "qgsapplication.h" -QgsMapToolCircle2TangentsPoint::QgsMapToolCircle2TangentsPoint( QgsMapToolCapture *parentTool, - QgsMapCanvas *canvas, CaptureMode mode ) - : QgsMapToolAddCircle( parentTool, canvas, mode ) +const QString QgsMapToolShapeCircle2TangentsPointMetadata::TOOL_ID = QStringLiteral( "circle-from-2-tangents-1-point" ); + +QString QgsMapToolShapeCircle2TangentsPointMetadata::id() const { - mToolName = tr( "Add circle from 2 tangents and a point" ); + return QgsMapToolShapeCircle2TangentsPointMetadata::TOOL_ID; } -QgsMapToolCircle2TangentsPoint::~QgsMapToolCircle2TangentsPoint() +QString QgsMapToolShapeCircle2TangentsPointMetadata::name() const { - deleteRadiusSpinBox(); + return QObject::tr( "Circle from 2 tangents and a point" ); } -void QgsMapToolCircle2TangentsPoint::cadCanvasReleaseEvent( QgsMapMouseEvent *e ) +QIcon QgsMapToolShapeCircle2TangentsPointMetadata::icon() const { + return QgsApplication::getThemeIcon( QStringLiteral( "/mActionCircle2TangentsPoint.svg" ) ); +} - const QgsPoint mapPoint( e->mapPoint() ); +QgsMapToolShapeAbstract::ShapeCategory QgsMapToolShapeCircle2TangentsPointMetadata::category() const +{ + return QgsMapToolShapeAbstract::ShapeCategory::Circle; +} - if ( !currentVectorLayer() ) - { - notifyNotVectorLayer(); - clean(); - stopCapturing(); - e->ignore(); - return; - } +QgsMapToolShapeAbstract *QgsMapToolShapeCircle2TangentsPointMetadata::factory( QgsMapToolCapture *parentTool ) const +{ + return new QgsMapToolShapeCircle2TangentsPoint( parentTool ); +} + +QgsMapToolShapeCircle2TangentsPoint::~QgsMapToolShapeCircle2TangentsPoint() +{ + deleteRadiusSpinBox(); +} + +bool QgsMapToolShapeCircle2TangentsPoint::cadCanvasReleaseEvent( QgsMapMouseEvent *e, QgsMapToolCapture::CaptureMode mode ) +{ + Q_UNUSED( mode ) EdgesOnlyFilter filter; - const QgsPointLocator::Match match = mCanvas->snappingUtils()->snapToMap( mapPoint, &filter ); + const QgsPointLocator::Match match = mParentTool->canvas()->snappingUtils()->snapToMap( mParentTool->mapPoint( *e ), &filter ); QgsPointXY p1, p2; @@ -83,8 +94,7 @@ void QgsMapToolCircle2TangentsPoint::cadCanvasReleaseEvent( QgsMapMouseEvent *e { QgisApp::instance()->messageBar()->pushMessage( tr( "Error" ), tr( "Segments are parallels" ), Qgis::MessageLevel::Critical ); - deactivate(); - activate(); + clean(); } else createRadiusSpinBox(); @@ -92,36 +102,26 @@ void QgsMapToolCircle2TangentsPoint::cadCanvasReleaseEvent( QgsMapMouseEvent *e } else if ( e->button() == Qt::RightButton ) { - mPoints.clear(); - if ( mTempRubberBand ) - { - delete mTempRubberBand; - mTempRubberBand = nullptr; - } - - qDeleteAll( mRubberBands ); - mRubberBands.clear(); - - deleteRadiusSpinBox(); - mCenters.clear(); - release( e ); + addCircleToParentTool(); + return true; } + + return false; } -void QgsMapToolCircle2TangentsPoint::cadCanvasMoveEvent( QgsMapMouseEvent *e ) +void QgsMapToolShapeCircle2TangentsPoint::cadCanvasMoveEvent( QgsMapMouseEvent *e, QgsMapToolCapture::CaptureMode mode ) { const QgsPoint mapPoint( e->mapPoint() ); - mSnapIndicator->setMatch( e->mapPointMatch() ); - EdgesOnlyFilter filter; - const QgsPointLocator::Match match = mCanvas->snappingUtils()->snapToMap( mapPoint, &filter ); + const QgsPointLocator::Match match = mParentTool->canvas()->snappingUtils()->snapToMap( mapPoint, &filter ); if ( mPoints.size() < 2 * 2 ) { if ( !mTempRubberBand ) { - mTempRubberBand = createGeometryRubberBand( mLayerType, true ); + QgsWkbTypes::GeometryType type = mode == QgsMapToolCapture::CapturePolygon ? QgsWkbTypes::PolygonGeometry : QgsWkbTypes::LineGeometry; + mTempRubberBand = mParentTool->createGeometryRubberBand( type, true ); mTempRubberBand->show(); } else @@ -157,7 +157,7 @@ void QgsMapToolCircle2TangentsPoint::cadCanvasMoveEvent( QgsMapMouseEvent *e ) } } -void QgsMapToolCircle2TangentsPoint::getPossibleCenter( ) +void QgsMapToolShapeCircle2TangentsPoint::getPossibleCenter( ) { mCenters.clear(); @@ -198,7 +198,7 @@ void QgsMapToolCircle2TangentsPoint::getPossibleCenter( ) } } -void QgsMapToolCircle2TangentsPoint::createRadiusSpinBox() +void QgsMapToolShapeCircle2TangentsPoint::createRadiusSpinBox() { deleteRadiusSpinBox(); mRadiusSpinBox = new QgsDoubleSpinBox(); @@ -209,10 +209,10 @@ void QgsMapToolCircle2TangentsPoint::createRadiusSpinBox() mRadiusSpinBox->setValue( mRadius ); QgisApp::instance()->addUserInputWidget( mRadiusSpinBox ); mRadiusSpinBox->setFocus( Qt::TabFocusReason ); - QObject::connect( mRadiusSpinBox, qOverload< double >( &QDoubleSpinBox::valueChanged ), this, &QgsMapToolCircle2TangentsPoint::radiusSpinBoxChanged ); + QObject::connect( mRadiusSpinBox, qOverload< double >( &QDoubleSpinBox::valueChanged ), this, &QgsMapToolShapeCircle2TangentsPoint::radiusSpinBoxChanged ); } -void QgsMapToolCircle2TangentsPoint::deleteRadiusSpinBox() +void QgsMapToolShapeCircle2TangentsPoint::deleteRadiusSpinBox() { if ( mRadiusSpinBox ) { @@ -221,7 +221,7 @@ void QgsMapToolCircle2TangentsPoint::deleteRadiusSpinBox() } } -void QgsMapToolCircle2TangentsPoint::radiusSpinBoxChanged( double radius ) +void QgsMapToolShapeCircle2TangentsPoint::radiusSpinBoxChanged( double radius ) { mRadius = radius; getPossibleCenter( ); @@ -233,7 +233,7 @@ void QgsMapToolCircle2TangentsPoint::radiusSpinBoxChanged( double radius ) const std::unique_ptr rb( new QgsMultiPolygon() ); for ( int i = 0; i < mCenters.size(); ++i ) { - std::unique_ptr tempRB( createGeometryRubberBand( QgsWkbTypes::PointGeometry, true ) ); + std::unique_ptr tempRB( mParentTool->createGeometryRubberBand( QgsWkbTypes::PointGeometry, true ) ); std::unique_ptr tempCenter( new QgsPoint( mCenters.at( i ) ) ); tempRB->setGeometry( tempCenter.release() ); tempRB->show(); @@ -241,3 +241,15 @@ void QgsMapToolCircle2TangentsPoint::radiusSpinBoxChanged( double radius ) } } } + + +void QgsMapToolShapeCircle2TangentsPoint::clean() +{ + qDeleteAll( mRubberBands ); + mRubberBands.clear(); + + deleteRadiusSpinBox(); + mCenters.clear(); + + QgsMapToolShapeCircleAbstract::clean(); +} diff --git a/src/app/qgsmaptoolcircle2tangentspoint.h b/src/app/maptools/qgsmaptoolshapecircle2tangentspoint.h similarity index 53% rename from src/app/qgsmaptoolcircle2tangentspoint.h rename to src/app/maptools/qgsmaptoolshapecircle2tangentspoint.h index accef94a6c1c..2b57fc8c3f30 100644 --- a/src/app/qgsmaptoolcircle2tangentspoint.h +++ b/src/app/maptools/qgsmaptoolshapecircle2tangentspoint.h @@ -1,5 +1,5 @@ /*************************************************************************** - qgsmaptoolcircle2tangentspoint.h - map tool for adding circle + qgsmaptoolshapecircle2tangentspoint.h - map tool for adding circle from 2 tangents and a point --------------------- begin : July 2017 @@ -14,25 +14,46 @@ * * ***************************************************************************/ -#ifndef QGSMAPTOOLCIRCLE2TANGENTSPOINT_H -#define QGSMAPTOOLCIRCLE2TANGENTSPOINT_H +#ifndef QGSMAPTOOLSHAPECIRCLE2TANGENTSPOINT_H +#define QGSMAPTOOLSHAPECIRCLE2TANGENTSPOINT_H #include "qgspointlocator.h" -#include "qgsmaptooladdcircle.h" +#include "qgsmaptoolshapecircleabstract.h" #include "qspinbox.h" +#include "qgsmaptoolshaperegistry.h" + class QSpinBox; -class QgsMapToolCircle2TangentsPoint: public QgsMapToolAddCircle +class APP_EXPORT QgsMapToolShapeCircle2TangentsPointMetadata : public QgsMapToolShapeMetadata +{ + public: + QgsMapToolShapeCircle2TangentsPointMetadata() + : QgsMapToolShapeMetadata() + {} + + static const QString TOOL_ID; + + QString id() const override; + QString name() const override; + QIcon icon() const override; + QgsMapToolShapeAbstract::ShapeCategory category() const override; + QgsMapToolShapeAbstract *factory( QgsMapToolCapture *parentTool ) const override; +}; + +class QgsMapToolShapeCircle2TangentsPoint: public QgsMapToolShapeCircleAbstract { Q_OBJECT public: - QgsMapToolCircle2TangentsPoint( QgsMapToolCapture *parentTool, QgsMapCanvas *canvas, CaptureMode mode = CaptureLine ); - ~QgsMapToolCircle2TangentsPoint() override; + QgsMapToolShapeCircle2TangentsPoint( QgsMapToolCapture *parentTool ) : QgsMapToolShapeCircleAbstract( QgsMapToolShapeCircle2TangentsPointMetadata::TOOL_ID, parentTool ) {} + ~QgsMapToolShapeCircle2TangentsPoint() override; + + bool cadCanvasReleaseEvent( QgsMapMouseEvent *e, QgsMapToolCapture::CaptureMode mode ) override; + void cadCanvasMoveEvent( QgsMapMouseEvent *e, QgsMapToolCapture::CaptureMode mode ) override; + + void clean() override; - void cadCanvasReleaseEvent( QgsMapMouseEvent *e ) override; - void cadCanvasMoveEvent( QgsMapMouseEvent *e ) override; public slots: void radiusSpinBoxChanged( double radius ); @@ -53,4 +74,4 @@ class QgsMapToolCircle2TangentsPoint: public QgsMapToolAddCircle QVector mRubberBands; }; -#endif // QGSMAPTOOLCIRCLE2TANGENTSPOINT_H +#endif // QGSMAPTOOLSHAPECIRCLE2TANGENTSPOINT_H diff --git a/src/app/maptools/qgsmaptoolshapecircle3points.cpp b/src/app/maptools/qgsmaptoolshapecircle3points.cpp new file mode 100644 index 000000000000..cd53c85deefd --- /dev/null +++ b/src/app/maptools/qgsmaptoolshapecircle3points.cpp @@ -0,0 +1,102 @@ +/*************************************************************************** + qgsmaptoolshapecircle3points.h - map tool for adding circle + from 3 points + --------------------- + begin : July 2017 + copyright : (C) 2017 by Loïc Bartoletti + email : lbartoletti at tuxfamily dot org + *************************************************************************** + * * + * 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 "qgsmaptoolshapecircle3points.h" +#include "qgsgeometryrubberband.h" +#include "qgslinestring.h" +#include "qgsmapcanvas.h" +#include "qgspoint.h" +#include "qgsmapmouseevent.h" +#include "qgsmaptoolcapture.h" +#include "qgsapplication.h" + +const QString QgsMapToolShapeCircle3PointsMetadata::TOOL_ID = QStringLiteral( "circle-from-3-points" ); + +QString QgsMapToolShapeCircle3PointsMetadata::id() const +{ + return QgsMapToolShapeCircle3PointsMetadata::TOOL_ID; +} + +QString QgsMapToolShapeCircle3PointsMetadata::name() const +{ + return QObject::tr( "Circle from 3 points" ); +} + +QIcon QgsMapToolShapeCircle3PointsMetadata::icon() const +{ + return QgsApplication::getThemeIcon( QStringLiteral( "/mActionCircle3Points.svg" ) ); +} + +QgsMapToolShapeAbstract::ShapeCategory QgsMapToolShapeCircle3PointsMetadata::category() const +{ + return QgsMapToolShapeAbstract::ShapeCategory::Circle; +} + +QgsMapToolShapeAbstract *QgsMapToolShapeCircle3PointsMetadata::factory( QgsMapToolCapture *parentTool ) const +{ + return new QgsMapToolShapeCircle3Points( parentTool ); +} + +bool QgsMapToolShapeCircle3Points::cadCanvasReleaseEvent( QgsMapMouseEvent *e, QgsMapToolCapture::CaptureMode mode ) +{ + if ( e->button() == Qt::LeftButton ) + { + if ( mPoints.size() < 2 ) + mPoints.append( mParentTool->mapPoint( *e ) ); + if ( !mPoints.isEmpty() && !mTempRubberBand ) + { + QgsWkbTypes::GeometryType type = mode == QgsMapToolCapture::CapturePolygon ? QgsWkbTypes::PolygonGeometry : QgsWkbTypes::LineGeometry; + mTempRubberBand = mParentTool->createGeometryRubberBand( type, true ); + mTempRubberBand->show(); + } + } + else if ( e->button() == Qt::RightButton ) + { + mPoints.append( mParentTool->mapPoint( *e ) ); + addCircleToParentTool(); + return true; + } + + return false; +} + +void QgsMapToolShapeCircle3Points::cadCanvasMoveEvent( QgsMapMouseEvent *e, QgsMapToolCapture::CaptureMode mode ) +{ + Q_UNUSED( mode ) + + if ( !mTempRubberBand ) + return; + + switch ( mPoints.size() ) + { + case 1: + { + std::unique_ptr line( new QgsLineString() ); + line->addVertex( mPoints.at( 0 ) ); + line->addVertex( mParentTool->mapPoint( *e ) ); + mTempRubberBand->setGeometry( line.release() ); + } + break; + case 2: + { + mCircle = QgsCircle::from3Points( mPoints.at( 0 ), mPoints.at( 1 ), mParentTool->mapPoint( *e ) ); + mTempRubberBand->setGeometry( mCircle.toCircularString( true ) ); + } + break; + default: + break; + } +} diff --git a/src/app/maptools/qgsmaptoolshapecircle3points.h b/src/app/maptools/qgsmaptoolshapecircle3points.h new file mode 100644 index 000000000000..34eaf2cfc669 --- /dev/null +++ b/src/app/maptools/qgsmaptoolshapecircle3points.h @@ -0,0 +1,51 @@ +/*************************************************************************** + qgsmaptoolshapecircle3points.h - map tool for adding circle + from 3 points + --------------------- + begin : July 2017 + copyright : (C) 2017 by Loïc Bartoletti + email : lbartoletti at tuxfamily dot org + *************************************************************************** + * * + * 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 3 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#ifndef QGSMAPTOOLSHAPECIRCLE3POINTS_H +#define QGSMAPTOOLSHAPECIRCLE3POINTS_H + +#include "qgsmaptoolshapecircleabstract.h" +#include "qgis_app.h" +#include "qgsmaptoolshaperegistry.h" + +class APP_EXPORT QgsMapToolShapeCircle3PointsMetadata : public QgsMapToolShapeMetadata +{ + public: + QgsMapToolShapeCircle3PointsMetadata() + : QgsMapToolShapeMetadata() + {} + + static const QString TOOL_ID; + + QString id() const override; + QString name() const override; + QIcon icon() const override; + QgsMapToolShapeAbstract::ShapeCategory category() const override; + QgsMapToolShapeAbstract *factory( QgsMapToolCapture *parentTool ) const override; +}; + +class APP_EXPORT QgsMapToolShapeCircle3Points: public QgsMapToolShapeCircleAbstract +{ + Q_OBJECT + + public: + QgsMapToolShapeCircle3Points( QgsMapToolCapture *parentTool ) : QgsMapToolShapeCircleAbstract( QgsMapToolShapeCircle3PointsMetadata::TOOL_ID, parentTool ) {} + + bool cadCanvasReleaseEvent( QgsMapMouseEvent *e, QgsMapToolCapture::CaptureMode mode ) override; + void cadCanvasMoveEvent( QgsMapMouseEvent *e, QgsMapToolCapture::CaptureMode mode ) override; +}; + +#endif // QGSMAPTOOLSHAPECIRCLE3POINTS_H diff --git a/src/app/qgsmaptoolcircle3tangents.cpp b/src/app/maptools/qgsmaptoolshapecircle3tangents.cpp similarity index 62% rename from src/app/qgsmaptoolcircle3tangents.cpp rename to src/app/maptools/qgsmaptoolshapecircle3tangents.cpp index 533bd8add827..0a5e9a3beb60 100644 --- a/src/app/qgsmaptoolcircle3tangents.cpp +++ b/src/app/maptools/qgsmaptoolshapecircle3tangents.cpp @@ -1,5 +1,5 @@ /*************************************************************************** - qgsmaptoolcircle3tangents.h - map tool for adding circle + qgsmaptoolshapecircle3tangents.h - map tool for adding circle from 3 tangents --------------------- begin : July 2017 @@ -14,7 +14,7 @@ * * ***************************************************************************/ -#include "qgsmaptoolcircle3tangents.h" +#include "qgsmaptoolshapecircle3tangents.h" #include "qgsgeometryrubberband.h" #include "qgsadvanceddigitizingdockwidget.h" #include "qgslinestring.h" @@ -24,16 +24,37 @@ #include "qgisapp.h" #include "qgsmapmouseevent.h" #include "qgsmessagebar.h" -#include "qgssnapindicator.h" +#include "qgsmaptoolcapture.h" +#include "qgsapplication.h" +const QString QgsMapToolShapeCircle3TangentsMetadata::TOOL_ID = QStringLiteral( "circle-from-3-tangents" ); -QgsMapToolCircle3Tangents::QgsMapToolCircle3Tangents( QgsMapToolCapture *parentTool, - QgsMapCanvas *canvas, CaptureMode mode ) - : QgsMapToolAddCircle( parentTool, canvas, mode ) +QString QgsMapToolShapeCircle3TangentsMetadata::id() const { - mToolName = tr( "Add circle from 3 tangents" ); + return QgsMapToolShapeCircle3TangentsMetadata::TOOL_ID; } +QString QgsMapToolShapeCircle3TangentsMetadata::name() const +{ + return QObject::tr( "Circle from 3 tangents" ); +} + +QIcon QgsMapToolShapeCircle3TangentsMetadata::icon() const +{ + return QgsApplication::getThemeIcon( QStringLiteral( "/mActionCircle3Tangents.svg" ) ); +} + +QgsMapToolShapeAbstract::ShapeCategory QgsMapToolShapeCircle3TangentsMetadata::category() const +{ + return QgsMapToolShapeAbstract::ShapeCategory::Circle; +} + +QgsMapToolShapeAbstract *QgsMapToolShapeCircle3TangentsMetadata::factory( QgsMapToolCapture *parentTool ) const +{ + return new QgsMapToolShapeCircle3Tangents( parentTool ); +} + + static QgsPoint getFirstPointOnParallels( const QgsPoint p1_line1, const QgsPoint p2_line1, const QgsPoint pos_line1, const QgsPoint p1_line2, const QgsPoint p2_line2, const QgsPoint pos_line2, const QgsPoint p1_line3, const QgsPoint p2_line3 ) { QgsPoint intersection; @@ -47,21 +68,14 @@ static QgsPoint getFirstPointOnParallels( const QgsPoint p1_line1, const QgsPoin return QgsPoint(); } -void QgsMapToolCircle3Tangents::cadCanvasReleaseEvent( QgsMapMouseEvent *e ) +bool QgsMapToolShapeCircle3Tangents::cadCanvasReleaseEvent( QgsMapMouseEvent *e, QgsMapToolCapture::CaptureMode mode ) { - const QgsPoint point = mapPoint( *e ); + Q_UNUSED( mode ) - if ( !currentVectorLayer() ) - { - notifyNotVectorLayer(); - clean(); - stopCapturing(); - e->ignore(); - return; - } + const QgsPoint point = mParentTool->mapPoint( *e ); EdgesOnlyFilter filter; - const QgsPointLocator::Match match = mCanvas->snappingUtils()->snapToMap( point, &filter ); + const QgsPointLocator::Match match = mParentTool->canvas()->snappingUtils()->snapToMap( point, &filter ); QgsPointXY p1, p2; @@ -69,10 +83,10 @@ void QgsMapToolCircle3Tangents::cadCanvasReleaseEvent( QgsMapMouseEvent *e ) { if ( match.isValid() && ( mPoints.size() <= 2 * 2 ) ) { - mPosPoints.append( mapPoint( match.point() ) ); + mPosPoints.append( mParentTool->mapPoint( match.point() ) ); match.edgePoints( p1, p2 ); - mPoints.append( mapPoint( p1 ) ); - mPoints.append( mapPoint( p2 ) ); + mPoints.append( mParentTool->mapPoint( p1 ) ); + mPoints.append( mParentTool->mapPoint( p2 ) ); } } else if ( e->button() == Qt::RightButton ) @@ -80,8 +94,8 @@ void QgsMapToolCircle3Tangents::cadCanvasReleaseEvent( QgsMapMouseEvent *e ) if ( match.isValid() && ( mPoints.size() == 4 ) ) { match.edgePoints( p1, p2 ); - mPoints.append( mapPoint( p1 ) ); - mPoints.append( mapPoint( p2 ) ); + mPoints.append( mParentTool->mapPoint( p1 ) ); + mPoints.append( mParentTool->mapPoint( p2 ) ); const QgsPoint pos = getFirstPointOnParallels( mPoints.at( 0 ), mPoints.at( 1 ), mPosPoints.at( 0 ), mPoints.at( 2 ), mPoints.at( 3 ), mPosPoints.at( 1 ), mPoints.at( 4 ), mPoints.at( 5 ) ); mCircle = QgsCircle::from3Tangents( mPoints.at( 0 ), mPoints.at( 1 ), mPoints.at( 2 ), mPoints.at( 3 ), mPoints.at( 4 ), mPoints.at( 5 ), 1E-8, pos ); if ( mCircle.isEmpty() ) @@ -93,22 +107,25 @@ void QgsMapToolCircle3Tangents::cadCanvasReleaseEvent( QgsMapMouseEvent *e ) mTempRubberBand = nullptr; } } - release( e ); + + addCircleToParentTool(); + return true; } + + return false; } -void QgsMapToolCircle3Tangents::cadCanvasMoveEvent( QgsMapMouseEvent *e ) +void QgsMapToolShapeCircle3Tangents::cadCanvasMoveEvent( QgsMapMouseEvent *e, QgsMapToolCapture::CaptureMode mode ) { - const QgsPoint point = mapPoint( *e ); - - mSnapIndicator->setMatch( e->mapPointMatch() ); + const QgsPoint point = mParentTool->mapPoint( *e ); EdgesOnlyFilter filter; - const QgsPointLocator::Match match = mCanvas->snappingUtils()->snapToMap( point, &filter ); + const QgsPointLocator::Match match = mParentTool->canvas()->snappingUtils()->snapToMap( point, &filter ); if ( !mTempRubberBand ) { - mTempRubberBand = createGeometryRubberBand( mLayerType, true ); + QgsWkbTypes::GeometryType type = mode == QgsMapToolCapture::CapturePolygon ? QgsWkbTypes::PolygonGeometry : QgsWkbTypes::LineGeometry; + mTempRubberBand = mParentTool->createGeometryRubberBand( type, true ); mTempRubberBand->show(); } else @@ -129,20 +146,18 @@ void QgsMapToolCircle3Tangents::cadCanvasMoveEvent( QgsMapMouseEvent *e ) { std::unique_ptr line( new QgsLineString() ); - line->addVertex( mapPoint( p1 ) ); - line->addVertex( mapPoint( p2 ) ); + line->addVertex( mParentTool->mapPoint( p1 ) ); + line->addVertex( mParentTool->mapPoint( p2 ) ); mTempRubberBand->setGeometry( line.release() ); mTempRubberBand->show(); - - } } } -void QgsMapToolCircle3Tangents::clean( ) +void QgsMapToolShapeCircle3Tangents::clean( ) { mPosPoints.clear(); - QgsMapToolAddCircle::clean(); + QgsMapToolShapeCircleAbstract::clean(); } diff --git a/src/app/maptools/qgsmaptoolshapecircle3tangents.h b/src/app/maptools/qgsmaptoolshapecircle3tangents.h new file mode 100644 index 000000000000..310335bde244 --- /dev/null +++ b/src/app/maptools/qgsmaptoolshapecircle3tangents.h @@ -0,0 +1,56 @@ +/*************************************************************************** + qgsmaptoolshapecircle3tangents.h - map tool for adding circle + from 3 tangents + --------------------- + begin : July 2017 + copyright : (C) 2017 by Loïc Bartoletti + email : lbartoletti at tuxfamily dot org + *************************************************************************** + * * + * 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 3 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#ifndef QGSMAPTOOLSHAPECIRCLE3TANGENTS_H +#define QGSMAPTOOLSHAPECIRCLE3TANGENTS_H + +#include "qgspointlocator.h" +#include "qgsmaptoolshapecircleabstract.h" +#include "qgsmaptoolshaperegistry.h" + +class APP_EXPORT QgsMapToolShapeCircle3TangentsMetadata : public QgsMapToolShapeMetadata +{ + public: + QgsMapToolShapeCircle3TangentsMetadata() + : QgsMapToolShapeMetadata() + {} + + static const QString TOOL_ID; + + QString id() const override; + QString name() const override; + QIcon icon() const override; + QgsMapToolShapeAbstract::ShapeCategory category() const override; + QgsMapToolShapeAbstract *factory( QgsMapToolCapture *parentTool ) const override; +}; + +class QgsMapToolShapeCircle3Tangents: public QgsMapToolShapeCircleAbstract +{ + Q_OBJECT + + public: + QgsMapToolShapeCircle3Tangents( QgsMapToolCapture *parentTool ) : QgsMapToolShapeCircleAbstract( QgsMapToolShapeCircle3TangentsMetadata::TOOL_ID, parentTool ) {} + + bool cadCanvasReleaseEvent( QgsMapMouseEvent *e, QgsMapToolCapture::CaptureMode mode ) override; + void cadCanvasMoveEvent( QgsMapMouseEvent *e, QgsMapToolCapture::CaptureMode mode ) override; + void clean() override; + + private: + //! Snapped points on the segments. Useful to determine which circle to choose in case of there are two parallels + QVector mPosPoints; +}; + +#endif // QGSMAPTOOLSHAPECIRCLE3TANGENTS_H diff --git a/src/app/qgsmaptooladdcircle.cpp b/src/app/maptools/qgsmaptoolshapecircleabstract.cpp similarity index 60% rename from src/app/qgsmaptooladdcircle.cpp rename to src/app/maptools/qgsmaptoolshapecircleabstract.cpp index d01ad39b4100..f63ed72368a9 100644 --- a/src/app/qgsmaptooladdcircle.cpp +++ b/src/app/maptools/qgsmaptoolshapecircleabstract.cpp @@ -1,5 +1,5 @@ /*************************************************************************** - qgsmaptooladdcircle.cpp - map tool for adding circle + qgsmaptoolshapecircleabstract.cpp - map tool for adding circle --------------------- begin : July 2017 copyright : (C) 2017 @@ -13,42 +13,23 @@ * * ***************************************************************************/ -#include "qgsmaptooladdcircle.h" -#include "qgscompoundcurve.h" -#include "qgscurvepolygon.h" -#include "qgsgeometryrubberband.h" -#include "qgsgeometryutils.h" -#include "qgslinestring.h" -#include "qgsmapcanvas.h" -#include "qgspoint.h" -#include "qgisapp.h" -#include "qgssnapindicator.h" +#include "qgsmaptoolshapecircleabstract.h" +#include "qgsmaptoolcapture.h" -QgsMapToolAddCircle::QgsMapToolAddCircle( QgsMapToolCapture *parentTool, QgsMapCanvas *canvas, CaptureMode mode ) - : QgsMapToolAddAbstract( parentTool, canvas, mode ) +void QgsMapToolShapeCircleAbstract::clean() { - mToolName = tr( "Add circle" ); + mCircle = QgsCircle(); + QgsMapToolShapeAbstract::clean(); } -void QgsMapToolAddCircle::deactivate() +void QgsMapToolShapeCircleAbstract::addCircleToParentTool() { if ( !mParentTool || mCircle.isEmpty() ) - { return; - } mParentTool->clearCurve(); std::unique_ptr lineString( mCircle.toCircularString() ); mParentTool->addCurve( lineString.release() ); - clean(); - - QgsMapToolCapture::deactivate(); -} - -void QgsMapToolAddCircle::clean() -{ - QgsMapToolAddAbstract::clean(); - mCircle = QgsCircle(); } diff --git a/src/app/qgsmaptooladdcircle.h b/src/app/maptools/qgsmaptoolshapecircleabstract.h similarity index 66% rename from src/app/qgsmaptooladdcircle.h rename to src/app/maptools/qgsmaptoolshapecircleabstract.h index cffaae3415a0..8348915007ae 100644 --- a/src/app/qgsmaptooladdcircle.h +++ b/src/app/maptools/qgsmaptoolshapecircleabstract.h @@ -1,5 +1,5 @@ /*************************************************************************** - qgsmaptooladdcircle.h - map tool for adding circle + qgsmaptoolshapecircleabstract.h - map tool for adding circle --------------------- begin : July 2017 copyright : (C) 2017 @@ -13,34 +13,41 @@ * * ***************************************************************************/ -#ifndef QGSMAPTOOLADDCIRCLE_H -#define QGSMAPTOOLADDCIRCLE_H +#ifndef QGSMAPTOOLSHAPECIRCLEABSTRACT_H +#define QGSMAPTOOLSHAPECIRCLEABSTRACT_H -#include "qgsmaptooladdabstract.h" +#include "qgsmaptoolshapeabstract.h" #include "qgscircle.h" #include "qgis_app.h" +#include "qgsmaptoolshaperegistry.h" +#include "qgspointlocator.h" + + struct EdgesOnlyFilter : public QgsPointLocator::MatchFilter { bool acceptMatch( const QgsPointLocator::Match &m ) override { return m.hasEdge(); } }; -class APP_EXPORT QgsMapToolAddCircle: public QgsMapToolAddAbstract + +class APP_EXPORT QgsMapToolShapeCircleAbstract: public QgsMapToolShapeAbstract { Q_OBJECT public: - QgsMapToolAddCircle( QgsMapToolCapture *parentTool, QgsMapCanvas *canvas, CaptureMode mode = CaptureLine ); + QgsMapToolShapeCircleAbstract( const QString &id, QgsMapToolCapture *parentTool ) : QgsMapToolShapeAbstract( id, parentTool ) {} + + virtual ~QgsMapToolShapeCircleAbstract() = default; - void deactivate() override; void clean() override; protected: - explicit QgsMapToolAddCircle( QgsMapCanvas *canvas ) = delete; //forbidden + + void addCircleToParentTool(); //! Circle QgsCircle mCircle; }; -#endif // QGSMAPTOOLADDCIRCLE_H +#endif // QGSMAPTOOLSHAPECIRCLEABSTRACT_H diff --git a/src/app/maptools/qgsmaptoolshapecirclecenterpoint.cpp b/src/app/maptools/qgsmaptoolshapecirclecenterpoint.cpp new file mode 100644 index 000000000000..9c6400ade931 --- /dev/null +++ b/src/app/maptools/qgsmaptoolshapecirclecenterpoint.cpp @@ -0,0 +1,90 @@ +/*************************************************************************** + qgmaptoolshapecirclecenterpoint.cpp - map tool for adding circle + from center and a point + --------------------- + begin : July 2017 + copyright : (C) 2017 by Loïc Bartoletti + email : lbartoletti at tuxfamily dot org + *************************************************************************** + * * + * 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 "qgsmaptoolshapecirclecenterpoint.h" +#include "qgsgeometryrubberband.h" +#include "qgsmapcanvas.h" +#include "qgspoint.h" +#include "qgsmapmouseevent.h" +#include "qgsmaptoolcapture.h" +#include "qgsapplication.h" + +const QString QgsMapToolShapeCircleCenterPointMetadata::TOOL_ID = QStringLiteral( "circle-by-a-center-point-and-another-point" ); + +QString QgsMapToolShapeCircleCenterPointMetadata::id() const +{ + return QgsMapToolShapeCircleCenterPointMetadata::TOOL_ID; +} + +QString QgsMapToolShapeCircleCenterPointMetadata::name() const +{ + return QObject::tr( "Circle by a center point and another point" ); +} + +QIcon QgsMapToolShapeCircleCenterPointMetadata::icon() const +{ + return QgsApplication::getThemeIcon( QStringLiteral( "/mActionCircleCenterPoint.svg" ) ); +} + +QgsMapToolShapeAbstract::ShapeCategory QgsMapToolShapeCircleCenterPointMetadata::category() const +{ + return QgsMapToolShapeAbstract::ShapeCategory::Circle; +} + +QgsMapToolShapeAbstract *QgsMapToolShapeCircleCenterPointMetadata::factory( QgsMapToolCapture *parentTool ) const +{ + return new QgsMapToolShapeCircleCenterPoint( parentTool ); +} + + +bool QgsMapToolShapeCircleCenterPoint::cadCanvasReleaseEvent( QgsMapMouseEvent *e, QgsMapToolCapture::CaptureMode mode ) +{ + const QgsPoint point = mParentTool->mapPoint( *e ); + + if ( e->button() == Qt::LeftButton ) + { + if ( mPoints.empty() ) + mPoints.append( point ); + + if ( !mTempRubberBand ) + { + QgsWkbTypes::GeometryType type = mode == QgsMapToolCapture::CapturePolygon ? QgsWkbTypes::PolygonGeometry : QgsWkbTypes::LineGeometry; + mTempRubberBand = mParentTool->createGeometryRubberBand( type, true ); + mTempRubberBand->show(); + } + + } + else if ( e->button() == Qt::RightButton ) + { + mPoints.append( point ); + addCircleToParentTool(); + return true; + } + return false; +} + +void QgsMapToolShapeCircleCenterPoint::cadCanvasMoveEvent( QgsMapMouseEvent *e, QgsMapToolCapture::CaptureMode mode ) +{ + Q_UNUSED( mode ) + + const QgsPoint point = mParentTool->mapPoint( *e ); + + if ( mTempRubberBand ) + { + mCircle = QgsCircle::fromCenterPoint( mPoints.at( 0 ), point ); + mTempRubberBand->setGeometry( mCircle.toCircularString( true ) ); + } +} diff --git a/src/app/maptools/qgsmaptoolshapecirclecenterpoint.h b/src/app/maptools/qgsmaptoolshapecirclecenterpoint.h new file mode 100644 index 000000000000..b51be861a044 --- /dev/null +++ b/src/app/maptools/qgsmaptoolshapecirclecenterpoint.h @@ -0,0 +1,51 @@ +/*************************************************************************** + qgmaptoolshapecirclecenterpoint.h - map tool for adding circle + from center and a point + --------------------- + begin : July 2017 + copyright : (C) 2017 by Loïc Bartoletti + email : lbartoletti at tuxfamily dot org + *************************************************************************** + * * + * 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 QGSMAPTOOLSHAPECIRCLECENTERPOINT_H +#define QGSMAPTOOLSHAPECIRCLECENTERPOINT_H + +#include "qgsmaptoolshapecircleabstract.h" +#include "qgis_app.h" +#include "qgsmaptoolshaperegistry.h" + +class APP_EXPORT QgsMapToolShapeCircleCenterPointMetadata : public QgsMapToolShapeMetadata +{ + public: + QgsMapToolShapeCircleCenterPointMetadata() + : QgsMapToolShapeMetadata() + {} + + static const QString TOOL_ID; + + QString id() const override; + QString name() const override; + QIcon icon() const override; + QgsMapToolShapeAbstract::ShapeCategory category() const override; + QgsMapToolShapeAbstract *factory( QgsMapToolCapture *parentTool ) const override; +}; + +class APP_EXPORT QgsMapToolShapeCircleCenterPoint: public QgsMapToolShapeCircleAbstract +{ + Q_OBJECT + + public: + QgsMapToolShapeCircleCenterPoint( QgsMapToolCapture *parentTool ) : QgsMapToolShapeCircleAbstract( QgsMapToolShapeCircleCenterPointMetadata::TOOL_ID, parentTool ) {} + + bool cadCanvasReleaseEvent( QgsMapMouseEvent *e, QgsMapToolCapture::CaptureMode mode ) override; + void cadCanvasMoveEvent( QgsMapMouseEvent *e, QgsMapToolCapture::CaptureMode mode ) override; +}; + +#endif // QGSMAPTOOLSHAPECIRCLECENTERPOINT_H diff --git a/src/app/qgsmaptooladdcircularstring.cpp b/src/app/maptools/qgsmaptoolshapecircularstringabstract.cpp similarity index 54% rename from src/app/qgsmaptooladdcircularstring.cpp rename to src/app/maptools/qgsmaptoolshapecircularstringabstract.cpp index 3f9a7e7498f2..e3a820e4c938 100644 --- a/src/app/qgsmaptooladdcircularstring.cpp +++ b/src/app/maptools/qgsmaptoolshapecircularstringabstract.cpp @@ -1,5 +1,5 @@ /*************************************************************************** - qgsmaptooladdcircularstring.h - map tool for adding circular strings + qgsmaptoolshapecircularstringabstract.h - map tool for adding circular strings --------------------- begin : December 2014 copyright : (C) 2014 by Marco Hugentobler @@ -13,7 +13,7 @@ * * ***************************************************************************/ -#include "qgsmaptooladdcircularstring.h" +#include "qgsmaptoolshapecircularstringabstract.h" #include "qgscircularstring.h" #include "qgscompoundcurve.h" #include "qgscurvepolygon.h" @@ -23,46 +23,42 @@ #include "qgsmapcanvas.h" #include "qgspoint.h" #include "qgisapp.h" -#include "qgssnapindicator.h" +#include "qgsmaptoolcapture.h" -QgsMapToolAddCircularString::QgsMapToolAddCircularString( QgsMapToolCapture *parentTool, QgsMapCanvas *canvas, CaptureMode mode ) - : QgsMapToolCapture( canvas, QgisApp::instance()->cadDockWidget(), mode ) - , mParentTool( parentTool ) +QgsMapToolShapeCircularStringAbstract::QgsMapToolShapeCircularStringAbstract( const QString &id, QgsMapToolCapture *parentTool ) + : QgsMapToolShapeAbstract( id, parentTool ) , mShowCenterPointRubberBand( false ) - , mSnapIndicator( std::make_unique< QgsSnapIndicator>( canvas ) ) -{ - mToolName = tr( "Add circular string" ); - connect( QgisApp::instance(), &QgisApp::newProject, this, &QgsMapToolAddCircularString::stopCapturing ); - connect( QgisApp::instance(), &QgisApp::projectRead, this, &QgsMapToolAddCircularString::stopCapturing ); -} +{} -QgsMapToolAddCircularString::~QgsMapToolAddCircularString() +QgsMapToolShapeCircularStringAbstract::~QgsMapToolShapeCircularStringAbstract() { delete mRubberBand; delete mTempRubberBand; removeCenterPointRubberBand(); } -void QgsMapToolAddCircularString::keyPressEvent( QKeyEvent *e ) -{ - if ( e && e->isAutoRepeat() ) - { - return; - } - if ( e && e->key() == Qt::Key_R ) +void QgsMapToolShapeCircularStringAbstract::keyPressEvent( QKeyEvent *e ) +{ + if ( e && !e->isAutoRepeat() && e->key() == Qt::Key_R ) { mShowCenterPointRubberBand = true; createCenterPointRubberBand(); + e->accept(); + } + else if ( e ) + { + e->ignore(); } +} - if ( ( e && e->key() == Qt::Key_Escape ) || ( ( e && e->key() == Qt::Key_Backspace ) && ( mPoints.size() == 1 ) ) ) +void QgsMapToolShapeCircularStringAbstract::undo() +{ + if ( mPoints.size() == 1 ) { clean(); - if ( mParentTool ) - mParentTool->keyPressEvent( e ); } - if ( ( e && e->key() == Qt::Key_Backspace ) && ( mPoints.size() > 1 ) ) + if ( mPoints.size() > 1 ) { mPoints.removeLast(); std::unique_ptr geomRubberBand( new QgsCircularString() ); @@ -84,93 +80,50 @@ void QgsMapToolAddCircularString::keyPressEvent( QKeyEvent *e ) mTempRubberBand->moveVertex( idx, mPoints.last() ); updateCenterPointRubberBand( mPoints.last() ); } - - if ( mParentTool ) - mParentTool->keyPressEvent( e ); - } } -void QgsMapToolAddCircularString::keyReleaseEvent( QKeyEvent *e ) +void QgsMapToolShapeCircularStringAbstract::keyReleaseEvent( QKeyEvent *e ) { - if ( e && e->isAutoRepeat() ) - { - return; - } - - if ( e && e->key() == Qt::Key_R ) + if ( e && !e->isAutoRepeat() && e->key() == Qt::Key_R ) { removeCenterPointRubberBand(); mShowCenterPointRubberBand = false; + e->accept(); } -} - -void QgsMapToolAddCircularString::deactivate() -{ - if ( !mParentTool || mPoints.size() < 3 ) + else if ( e ) { - return; + e->ignore(); } - - if ( mPoints.size() % 2 == 0 ) //a valid circularstring needs to have an odd number of vertices - { - mPoints.removeLast(); - } - - QgsCircularString *c = new QgsCircularString(); - c->setPoints( mPoints ); - mParentTool->addCurve( c ); - clean(); - QgsMapToolCapture::deactivate(); } -void QgsMapToolAddCircularString::activate() +void QgsMapToolShapeCircularStringAbstract::activate( QgsMapToolCapture::CaptureMode mode, const QgsPoint &lastCapturedMapPoint ) { - - QgsVectorLayer *vLayer = static_cast( QgisApp::instance()->activeLayer() ); - if ( vLayer ) - mLayerType = vLayer->geometryType(); - if ( mParentTool ) + if ( mPoints.isEmpty() && !lastCapturedMapPoint.isEmpty() ) { - mParentTool->deleteTempRubberBand(); - if ( mPoints.isEmpty() ) + mPoints.append( lastCapturedMapPoint ); + if ( !mTempRubberBand ) { - // if the parent tool has a curve, use its last point as the first point in this curve - const QgsCompoundCurve *compoundCurve = mParentTool->captureCurve(); - if ( compoundCurve && compoundCurve->nCurves() > 0 ) - { - const QgsCurve *curve = compoundCurve->curveAt( compoundCurve->nCurves() - 1 ); - if ( curve ) - { - //mParentTool->captureCurve() is in layer coordinates, but we need map coordinates - const QgsPoint endPointLayerCoord = curve->endPoint(); - const QgsPoint mapPoint = toMapCoordinates( mCanvas->currentLayer(), endPointLayerCoord ); - mPoints.append( mapPoint ); - if ( !mTempRubberBand ) - { - mTempRubberBand = createGeometryRubberBand( mLayerType, true ); - mTempRubberBand->show(); - } - QgsCircularString *c = new QgsCircularString(); - QgsPointSequence rubberBandPoints = mPoints; - rubberBandPoints.append( QgsPoint( mapPoint ) ); - c->setPoints( rubberBandPoints ); - mTempRubberBand->setGeometry( c ); - } - } + QgsWkbTypes::GeometryType type = mode == QgsMapToolCapture::CapturePolygon ? QgsWkbTypes::PolygonGeometry : QgsWkbTypes::LineGeometry; + mTempRubberBand = mParentTool->createGeometryRubberBand( type, true ); + mTempRubberBand->show(); } + QgsCircularString *c = new QgsCircularString(); + QgsPointSequence rubberBandPoints = mPoints; + rubberBandPoints.append( lastCapturedMapPoint ); + c->setPoints( rubberBandPoints ); + mTempRubberBand->setGeometry( c ); } - QgsMapToolCapture::activate(); } -void QgsMapToolAddCircularString::createCenterPointRubberBand() +void QgsMapToolShapeCircularStringAbstract::createCenterPointRubberBand() { if ( !mShowCenterPointRubberBand || mPoints.size() < 2 || mPoints.size() % 2 != 0 ) { return; } - mCenterPointRubberBand = createGeometryRubberBand( QgsWkbTypes::PolygonGeometry ); + mCenterPointRubberBand = mParentTool->createGeometryRubberBand( QgsWkbTypes::PolygonGeometry ); mCenterPointRubberBand->show(); if ( mTempRubberBand ) @@ -185,7 +138,7 @@ void QgsMapToolAddCircularString::createCenterPointRubberBand() } } -void QgsMapToolAddCircularString::updateCenterPointRubberBand( const QgsPoint &pt ) +void QgsMapToolShapeCircularStringAbstract::updateCenterPointRubberBand( const QgsPoint &pt ) { if ( !mShowCenterPointRubberBand || !mCenterPointRubberBand || mPoints.size() < 2 ) { @@ -228,23 +181,20 @@ void QgsMapToolAddCircularString::updateCenterPointRubberBand( const QgsPoint &p mCenterPointRubberBand->show(); } -void QgsMapToolAddCircularString::removeCenterPointRubberBand() +void QgsMapToolShapeCircularStringAbstract::removeCenterPointRubberBand() { delete mCenterPointRubberBand; mCenterPointRubberBand = nullptr; } -void QgsMapToolAddCircularString::release( QgsMapMouseEvent *e ) +void QgsMapToolShapeCircularStringAbstract::addCurveToParentTool() { - deactivate(); - if ( mParentTool ) - { - mParentTool->canvasReleaseEvent( e ); - } - activate(); + QgsCircularString *c = new QgsCircularString(); + c->setPoints( mPoints ); + mParentTool->addCurve( c ); } -void QgsMapToolAddCircularString::clean() +void QgsMapToolShapeCircularStringAbstract::clean() { mPoints.clear(); delete mRubberBand; diff --git a/src/app/qgsmaptooladdcircularstring.h b/src/app/maptools/qgsmaptoolshapecircularstringabstract.h similarity index 56% rename from src/app/qgsmaptooladdcircularstring.h rename to src/app/maptools/qgsmaptoolshapecircularstringabstract.h index deed6e13613c..083fbe7c4bae 100644 --- a/src/app/qgsmaptooladdcircularstring.h +++ b/src/app/maptools/qgsmaptoolshapecircularstringabstract.h @@ -1,5 +1,5 @@ /*************************************************************************** - qgsmaptooladdcircularstring.h - map tool for adding circular strings + qgsmaptoolshapecircularstringabstract.h - map tool for adding circular strings --------------------- begin : December 2014 copyright : (C) 2014 by Marco Hugentobler @@ -13,47 +13,35 @@ * * ***************************************************************************/ -#ifndef QGSMAPTOOLADDCIRCULARSTRING_H -#define QGSMAPTOOLADDCIRCULARSTRING_H +#ifndef QGSMAPTOOLSHAPECIRCULARSTRINGABSTRACT_H +#define QGSMAPTOOLSHAPECIRCULARSTRINGABSTRACT_H -#include "qgsmaptoolcapture.h" +#include "qgsmaptoolshapeabstract.h" #include "qgis_app.h" class QgsGeometryRubberBand; -class QgsSnapIndicator; -class APP_EXPORT QgsMapToolAddCircularString: public QgsMapToolCapture + +class APP_EXPORT QgsMapToolShapeCircularStringAbstract: public QgsMapToolShapeAbstract { Q_OBJECT public: - QgsMapToolAddCircularString( QgsMapToolCapture *parentTool, QgsMapCanvas *canvas, CaptureMode mode = CaptureLine ); - ~QgsMapToolAddCircularString() override; + QgsMapToolShapeCircularStringAbstract( const QString &id, QgsMapToolCapture *parentTool ); + ~QgsMapToolShapeCircularStringAbstract() override; void keyPressEvent( QKeyEvent *e ) override; void keyReleaseEvent( QKeyEvent *e ) override; - void deactivate() override; - - void activate() override; + void activate( QgsMapToolCapture::CaptureMode mode, const QgsPoint &lastCapturedMapPoint ) override; - //! Clean drawings on map canvas void clean() override; - /*private slots: - void setParentTool( QgsMapTool *newTool, QgsMapTool *oldTool );*/ + void undo() override; protected: - //! Convenient method to release (activate/deactivate) tools - void release( QgsMapMouseEvent *e ); + void addCurveToParentTool(); - /** - * The parent map tool, e.g. the add feature tool. - * Completed circular strings will be added to this tool by calling its addCurve() method. - */ - QPointer mParentTool; - //! Circular string points (in map coordinates) - QgsPointSequence mPoints; //! The rubberband to show the already completed circular strings QgsGeometryRubberBand *mRubberBand = nullptr; //! The rubberband to show the circular string currently working on @@ -66,11 +54,6 @@ class APP_EXPORT QgsMapToolAddCircularString: public QgsMapToolCapture void createCenterPointRubberBand(); void updateCenterPointRubberBand( const QgsPoint &pt ); void removeCenterPointRubberBand(); - //! Layer type which will be used for rubberband - QgsWkbTypes::GeometryType mLayerType = QgsWkbTypes::LineGeometry; - - //! Snapping indicators - std::unique_ptr mSnapIndicator; }; -#endif // QGSMAPTOOLADDCIRCULARSTRING_H +#endif // QGSMAPTOOLSHAPECIRCULARSTRINGABSTRACT_H diff --git a/src/app/qgsmaptoolcircularstringradius.cpp b/src/app/maptools/qgsmaptoolshapecircularstringradius.cpp similarity index 62% rename from src/app/qgsmaptoolcircularstringradius.cpp rename to src/app/maptools/qgsmaptoolshapecircularstringradius.cpp index 600af65216b3..7b95df4f901a 100644 --- a/src/app/qgsmaptoolcircularstringradius.cpp +++ b/src/app/maptools/qgsmaptoolshapecircularstringradius.cpp @@ -1,5 +1,5 @@ /*************************************************************************** - qgsmaptoolcircularstringradius.h - map tool for adding circular strings + qgsmaptoolshapecircularstringradius.h - map tool for adding circular strings --------------------- begin : Feb 2015 copyright : (C) 2015 by Marco Hugentobler @@ -13,7 +13,7 @@ * * ***************************************************************************/ -#include "qgsmaptoolcircularstringradius.h" +#include "qgsmaptoolshapecircularstringradius.h" #include "qgisapp.h" #include "qgscircularstring.h" #include "qgscompoundcurve.h" @@ -23,37 +23,50 @@ #include "qgspoint.h" #include "qgsstatusbar.h" #include "qgsmapmouseevent.h" -#include "qgssnapindicator.h" +#include "qgsmaptoolcapture.h" #include "qgsdoublespinbox.h" #include +#include "qgsapplication.h" -QgsMapToolCircularStringRadius::QgsMapToolCircularStringRadius( QgsMapToolCapture *parentTool, QgsMapCanvas *canvas, CaptureMode mode ) - : QgsMapToolAddCircularString( parentTool, canvas, mode ) - , mTemporaryEndPoint( QgsPoint() ) - , mRadius( 0.0 ) +const QString QgsMapToolShapeCircularStringRadiusMetadata::TOOL_ID = QStringLiteral( "circular-string-by-radius" ); +QString QgsMapToolShapeCircularStringRadiusMetadata::id() const { - mToolName = tr( "Add circular string by radius" ); + return QgsMapToolShapeCircularStringRadiusMetadata::TOOL_ID; } -void QgsMapToolCircularStringRadius::deactivate() +QString QgsMapToolShapeCircularStringRadiusMetadata::name() const +{ + return QObject::tr( "Circular string by radius" ); +} + +QIcon QgsMapToolShapeCircularStringRadiusMetadata::icon() const +{ + return QgsApplication::getThemeIcon( QStringLiteral( "/mActionCircularStringRadius.svg" ) ); +} + +QgsMapToolShapeAbstract::ShapeCategory QgsMapToolShapeCircularStringRadiusMetadata::category() const +{ + return QgsMapToolShapeAbstract::ShapeCategory::Curve; +} + +QgsMapToolShapeAbstract *QgsMapToolShapeCircularStringRadiusMetadata::factory( QgsMapToolCapture *parentTool ) const +{ + return new QgsMapToolShapeCircularStringRadius( parentTool ); +} + + +void QgsMapToolShapeCircularStringRadius::deactivate() { deleteRadiusSpinBox(); - QgsMapToolAddCircularString::deactivate(); + clean(); } -void QgsMapToolCircularStringRadius::cadCanvasReleaseEvent( QgsMapMouseEvent *e ) +bool QgsMapToolShapeCircularStringRadius::cadCanvasReleaseEvent( QgsMapMouseEvent *e, QgsMapToolCapture::CaptureMode mode ) { - const QgsPoint point = mapPoint( *e ); + mCaptureMode = mode; - if ( !currentVectorLayer() ) - { - notifyNotVectorLayer(); - clean(); - stopCapturing(); - e->ignore(); - return; - } + const QgsPoint point = mParentTool->mapPoint( *e ); if ( e->button() == Qt::LeftButton ) { @@ -95,14 +108,16 @@ void QgsMapToolCircularStringRadius::cadCanvasReleaseEvent( QgsMapMouseEvent *e { if ( !( mPoints.size() % 2 ) ) mPoints.removeLast(); - release( e ); + addCurveToParentTool(); + return true; } + + return false; } -void QgsMapToolCircularStringRadius::cadCanvasMoveEvent( QgsMapMouseEvent *e ) +void QgsMapToolShapeCircularStringRadius::cadCanvasMoveEvent( QgsMapMouseEvent *e, QgsMapToolCapture::CaptureMode mode ) { - - mSnapIndicator->setMatch( e->mapPointMatch() ); + mCaptureMode = mode; if ( !mPoints.isEmpty() ) { @@ -111,7 +126,7 @@ void QgsMapToolCircularStringRadius::cadCanvasMoveEvent( QgsMapMouseEvent *e ) } } -void QgsMapToolCircularStringRadius::recalculateRubberBand() +void QgsMapToolShapeCircularStringRadius::recalculateRubberBand() { if ( mPoints.size() >= 3 ) { @@ -119,13 +134,14 @@ void QgsMapToolCircularStringRadius::recalculateRubberBand() const int rubberBandSize = mPoints.size() - ( mPoints.size() + 1 ) % 2; cString->setPoints( mPoints.mid( 0, rubberBandSize ) ); delete mRubberBand; - mRubberBand = createGeometryRubberBand( mLayerType ); + QgsWkbTypes::GeometryType type = mCaptureMode == QgsMapToolCapture::CapturePolygon ? QgsWkbTypes::PolygonGeometry : QgsWkbTypes::LineGeometry; + mRubberBand = mParentTool->createGeometryRubberBand( type ); mRubberBand->setGeometry( cString ); mRubberBand->show(); } } -void QgsMapToolCircularStringRadius::recalculateTempRubberBand( const QgsPointXY &mousePosition ) +void QgsMapToolShapeCircularStringRadius::recalculateTempRubberBand( const QgsPointXY &mousePosition ) { QgsPointSequence rubberBandPoints; if ( !( mPoints.size() % 2 ) ) @@ -145,17 +161,18 @@ void QgsMapToolCircularStringRadius::recalculateTempRubberBand( const QgsPointXY else { rubberBandPoints.append( mPoints.last() ); - rubberBandPoints.append( mapPoint( mousePosition ) ); + rubberBandPoints.append( mParentTool->mapPoint( mousePosition ) ); } QgsCircularString *cString = new QgsCircularString(); cString->setPoints( rubberBandPoints ); delete mTempRubberBand; - mTempRubberBand = createGeometryRubberBand( mLayerType, true ); + QgsWkbTypes::GeometryType type = mCaptureMode == QgsMapToolCapture::CapturePolygon ? QgsWkbTypes::PolygonGeometry : QgsWkbTypes::LineGeometry; + mTempRubberBand = mParentTool->createGeometryRubberBand( type, true ); mTempRubberBand->setGeometry( cString ); mTempRubberBand->show(); } -void QgsMapToolCircularStringRadius::createRadiusSpinBox() +void QgsMapToolShapeCircularStringRadius::createRadiusSpinBox() { deleteRadiusSpinBox(); mRadiusSpinBox = new QgsDoubleSpinBox(); @@ -164,11 +181,11 @@ void QgsMapToolCircularStringRadius::createRadiusSpinBox() mRadiusSpinBox->setPrefix( tr( "Radius: " ) ); mRadiusSpinBox->setValue( mRadius ); QgisApp::instance()->addUserInputWidget( mRadiusSpinBox ); - connect( mRadiusSpinBox, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ), this, &QgsMapToolCircularStringRadius::updateRadiusFromSpinBox ); + connect( mRadiusSpinBox, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ), this, &QgsMapToolShapeCircularStringRadius::updateRadiusFromSpinBox ); mRadiusSpinBox->setFocus( Qt::TabFocusReason ); } -void QgsMapToolCircularStringRadius::deleteRadiusSpinBox() +void QgsMapToolShapeCircularStringRadius::deleteRadiusSpinBox() { if ( mRadiusSpinBox ) { @@ -178,8 +195,8 @@ void QgsMapToolCircularStringRadius::deleteRadiusSpinBox() } } -void QgsMapToolCircularStringRadius::updateRadiusFromSpinBox( double radius ) +void QgsMapToolShapeCircularStringRadius::updateRadiusFromSpinBox( double radius ) { mRadius = radius; - recalculateTempRubberBand( toMapCoordinates( mCanvas->mouseLastXY() ).toQPointF() ); + recalculateTempRubberBand( mParentTool->toMapCoordinates( mParentTool->canvas()->mouseLastXY() ).toQPointF() ); } diff --git a/src/app/qgsmaptoolcircularstringradius.h b/src/app/maptools/qgsmaptoolshapecircularstringradius.h similarity index 52% rename from src/app/qgsmaptoolcircularstringradius.h rename to src/app/maptools/qgsmaptoolshapecircularstringradius.h index 68435f077abe..e2cb97d9efe3 100644 --- a/src/app/qgsmaptoolcircularstringradius.h +++ b/src/app/maptools/qgsmaptoolshapecircularstringradius.h @@ -1,5 +1,5 @@ /*************************************************************************** - qgsmaptoolcircularstringradius.h - map tool for adding circular strings + qgsmaptoolshapecircularstringradius.h - map tool for adding circular strings by two points and radius --------------------- begin : Feb 2015 @@ -14,23 +14,44 @@ * * ***************************************************************************/ -#ifndef QGSMAPTOOLCIRCULARSTRINGRADIUS_H -#define QGSMAPTOOLCIRCULARSTRINGRADIUS_H +#ifndef QGSMAPTOOLSHAPECIRCULARSTRINGRADIUS_H +#define QGSMAPTOOLSHAPECIRCULARSTRINGRADIUS_H -#include "qgsmaptooladdcircularstring.h" +#include "qgsmaptoolshapecircularstringabstract.h" #include "qgspoint.h" #include "qgis_app.h" +#include "qgsmaptoolshaperegistry.h" class QDoubleSpinBox; -class APP_EXPORT QgsMapToolCircularStringRadius: public QgsMapToolAddCircularString +class APP_EXPORT QgsMapToolShapeCircularStringRadiusMetadata : public QgsMapToolShapeMetadata +{ + public: + QgsMapToolShapeCircularStringRadiusMetadata() + : QgsMapToolShapeMetadata() + {} + + static const QString TOOL_ID; + + QString id() const override; + QString name() const override; + QIcon icon() const override; + QgsMapToolShapeAbstract::ShapeCategory category() const override; + QgsMapToolShapeAbstract *factory( QgsMapToolCapture *parentTool ) const override; +}; + +class APP_EXPORT QgsMapToolShapeCircularStringRadius: public QgsMapToolShapeCircularStringAbstract { Q_OBJECT public: - QgsMapToolCircularStringRadius( QgsMapToolCapture *parentTool, QgsMapCanvas *canvas, CaptureMode mode = CaptureLine ); + QgsMapToolShapeCircularStringRadius( QgsMapToolCapture *parentTool ) + : QgsMapToolShapeCircularStringAbstract( QgsMapToolShapeCircularStringRadiusMetadata::TOOL_ID, parentTool ) + , mTemporaryEndPoint( QgsPoint() ) + , mRadius( 0.0 ) + {} - void cadCanvasReleaseEvent( QgsMapMouseEvent *e ) override; - void cadCanvasMoveEvent( QgsMapMouseEvent *e ) override; + bool cadCanvasReleaseEvent( QgsMapMouseEvent *e, QgsMapToolCapture::CaptureMode mode ) override; + void cadCanvasMoveEvent( QgsMapMouseEvent *e, QgsMapToolCapture::CaptureMode mode ) override; void deactivate() override; private slots: @@ -40,6 +61,7 @@ class APP_EXPORT QgsMapToolCircularStringRadius: public QgsMapToolAddCircularStr QgsPoint mTemporaryEndPoint; double mRadius; QDoubleSpinBox *mRadiusSpinBox = nullptr; + QgsMapToolCapture::CaptureMode mCaptureMode = QgsMapToolCapture::CaptureMode::CaptureLine; //! recalculate the rubberband void recalculateRubberBand(); @@ -51,4 +73,4 @@ class APP_EXPORT QgsMapToolCircularStringRadius: public QgsMapToolAddCircularStr void deleteRadiusSpinBox(); }; -#endif // QGSMAPTOOLCIRCULARSTRINGRADIUS_H +#endif // QGSMAPTOOLSHAPECIRCULARSTRINGRADIUS_H diff --git a/src/app/qgsmaptooladdellipse.cpp b/src/app/maptools/qgsmaptoolshapeellipseabstract.cpp similarity index 66% rename from src/app/qgsmaptooladdellipse.cpp rename to src/app/maptools/qgsmaptoolshapeellipseabstract.cpp index 4e948505c845..78365adaee18 100644 --- a/src/app/qgsmaptooladdellipse.cpp +++ b/src/app/maptools/qgsmaptoolshapeellipseabstract.cpp @@ -1,5 +1,5 @@ /*************************************************************************** - qgsmaptooladdellipse.cpp - map tool for adding ellipse + qgsmaptoolshapeellipseabstract.cpp - map tool for adding ellipse --------------------- begin : July 2017 copyright : (C) 2017 @@ -13,40 +13,27 @@ * * ***************************************************************************/ -#include "qgsmaptooladdellipse.h" +#include "qgsmaptoolshapeellipseabstract.h" #include "qgsgeometryrubberband.h" -#include "qgsgeometryutils.h" #include "qgslinestring.h" -#include "qgsmapcanvas.h" -#include "qgspoint.h" -#include "qgisapp.h" -#include "qgssnapindicator.h" +#include "qgsmaptoolcapture.h" -QgsMapToolAddEllipse::QgsMapToolAddEllipse( QgsMapToolCapture *parentTool, QgsMapCanvas *canvas, CaptureMode mode ) - : QgsMapToolAddAbstract( parentTool, canvas, mode ) -{ - mToolName = tr( "Add ellipse" ); -} -void QgsMapToolAddEllipse::deactivate() +void QgsMapToolShapeEllipseAbstract::addEllipseToParentTool() { if ( !mParentTool || mEllipse.isEmpty() ) - { return; - } mParentTool->clearCurve(); std::unique_ptr ls( mEllipse.toLineString( segments() ) ); mParentTool->addCurve( ls.release() ); - clean(); - QgsMapToolCapture::deactivate(); } -void QgsMapToolAddEllipse::clean() +void QgsMapToolShapeEllipseAbstract::clean() { - QgsMapToolAddAbstract::clean(); mEllipse = QgsEllipse(); + QgsMapToolShapeAbstract::clean(); } diff --git a/src/app/qgsmaptooladdellipse.h b/src/app/maptools/qgsmaptoolshapeellipseabstract.h similarity index 72% rename from src/app/qgsmaptooladdellipse.h rename to src/app/maptools/qgsmaptoolshapeellipseabstract.h index 19b91c8a428f..3f60b75b9c83 100644 --- a/src/app/qgsmaptooladdellipse.h +++ b/src/app/maptools/qgsmaptoolshapeellipseabstract.h @@ -1,5 +1,5 @@ /*************************************************************************** - qgsmaptooladdellipse.h - map tool for adding ellipse + qgsmaptoolshapeellipseabstract.h - map tool for adding ellipse --------------------- begin : July 2017 copyright : (C) 2017 @@ -13,10 +13,10 @@ * * ***************************************************************************/ -#ifndef QGSMAPTOOLADDELLIPSE_H -#define QGSMAPTOOLADDELLIPSE_H +#ifndef QGSMAPTOOLSHAPEELLIPSEABSTRACT_H +#define QGSMAPTOOLSHAPEELLIPSEABSTRACT_H -#include "qgsmaptooladdabstract.h" +#include "qgsmaptoolshapecircleabstract.h" #include "qgsellipse.h" #include "qgssettingsregistrycore.h" #include "qgis_app.h" @@ -24,17 +24,18 @@ class QgsGeometryRubberBand; class QgsSnapIndicator; -class APP_EXPORT QgsMapToolAddEllipse: public QgsMapToolAddAbstract +class APP_EXPORT QgsMapToolShapeEllipseAbstract: public QgsMapToolShapeAbstract { Q_OBJECT public: - QgsMapToolAddEllipse( QgsMapToolCapture *parentTool, QgsMapCanvas *canvas, CaptureMode mode = CaptureLine ); + QgsMapToolShapeEllipseAbstract( const QString &id, QgsMapToolCapture *parentTool ) + : QgsMapToolShapeAbstract( id, parentTool ) + {} - void deactivate() override; void clean() override; protected: - explicit QgsMapToolAddEllipse( QgsMapCanvas *canvas ) = delete; //forbidden + void addEllipseToParentTool(); //! Ellipse QgsEllipse mEllipse; @@ -43,4 +44,4 @@ class APP_EXPORT QgsMapToolAddEllipse: public QgsMapToolAddAbstract unsigned int segments( ) { return QgsSettingsRegistryCore::settingsDigitizingOffsetQuadSeg.value() * 12; } }; -#endif // QGSMAPTOOLADDELLIPSE_H +#endif // QGSMAPTOOLSHAPEELLIPSEABSTRACT_H diff --git a/src/app/qgsmaptoolellipsecenter2points.cpp b/src/app/maptools/qgsmaptoolshapeellipsecenter2points.cpp similarity index 52% rename from src/app/qgsmaptoolellipsecenter2points.cpp rename to src/app/maptools/qgsmaptoolshapeellipsecenter2points.cpp index 1a423fcfeb98..3dd0006b0bef 100644 --- a/src/app/qgsmaptoolellipsecenter2points.cpp +++ b/src/app/maptools/qgsmaptoolshapeellipsecenter2points.cpp @@ -1,5 +1,5 @@ /*************************************************************************** - qgsmaptoolellipsecenter2points.cpp - map tool for adding ellipse + qgsmaptoolshapeellipsecenter2points.cpp - map tool for adding ellipse from center and 2 points --------------------- begin : July 2017 @@ -14,34 +14,46 @@ * * ***************************************************************************/ -#include "qgsmaptoolellipsecenter2points.h" +#include "qgsmaptoolshapeellipsecenter2points.h" #include "qgsgeometryrubberband.h" #include "qgslinestring.h" #include "qgsmapcanvas.h" #include "qgspoint.h" #include "qgsmapmouseevent.h" -#include "qgssnapindicator.h" +#include "qgsmaptoolcapture.h" #include +#include "qgsapplication.h" -QgsMapToolEllipseCenter2Points::QgsMapToolEllipseCenter2Points( QgsMapToolCapture *parentTool, - QgsMapCanvas *canvas, CaptureMode mode ) - : QgsMapToolAddEllipse( parentTool, canvas, mode ) +const QString QgsMapToolShapeEllipseCenter2PointsMetadata::TOOL_ID = QStringLiteral( "ellipse-center-2-points" ); + +QString QgsMapToolShapeEllipseCenter2PointsMetadata::id() const { + return QgsMapToolShapeEllipseCenter2PointsMetadata::TOOL_ID; } -void QgsMapToolEllipseCenter2Points::cadCanvasReleaseEvent( QgsMapMouseEvent *e ) +QString QgsMapToolShapeEllipseCenter2PointsMetadata::name() const { - const QgsPoint point = mapPoint( *e ); + return QObject::tr( "Ellipse from center and 2 points" ); +} - if ( !currentVectorLayer() ) - { - notifyNotVectorLayer(); - clean(); - stopCapturing(); - e->ignore(); - return; - } +QIcon QgsMapToolShapeEllipseCenter2PointsMetadata::icon() const +{ + return QgsApplication::getThemeIcon( QStringLiteral( "/mActionEllipseCenter2Points.svg" ) ); +} + +QgsMapToolShapeAbstract::ShapeCategory QgsMapToolShapeEllipseCenter2PointsMetadata::category() const +{ + return QgsMapToolShapeAbstract::ShapeCategory::Ellipse; +} +QgsMapToolShapeAbstract *QgsMapToolShapeEllipseCenter2PointsMetadata::factory( QgsMapToolCapture *parentTool ) const +{ + return new QgsMapToolShapeEllipseCenter2Points( parentTool ); +} + +bool QgsMapToolShapeEllipseCenter2Points::cadCanvasReleaseEvent( QgsMapMouseEvent *e, QgsMapToolCapture::CaptureMode mode ) +{ + const QgsPoint point = mParentTool->mapPoint( *e ); if ( e->button() == Qt::LeftButton ) { @@ -50,21 +62,25 @@ void QgsMapToolEllipseCenter2Points::cadCanvasReleaseEvent( QgsMapMouseEvent *e if ( !mPoints.isEmpty() && !mTempRubberBand ) { - mTempRubberBand = createGeometryRubberBand( mLayerType, true ); + QgsWkbTypes::GeometryType type = mode == QgsMapToolCapture::CapturePolygon ? QgsWkbTypes::PolygonGeometry : QgsWkbTypes::LineGeometry; + mTempRubberBand = mParentTool->createGeometryRubberBand( type, true ); mTempRubberBand->show(); } } else if ( e->button() == Qt::RightButton ) { - release( e ); + addEllipseToParentTool(); + return true; } + + return false; } -void QgsMapToolEllipseCenter2Points::cadCanvasMoveEvent( QgsMapMouseEvent *e ) +void QgsMapToolShapeEllipseCenter2Points::cadCanvasMoveEvent( QgsMapMouseEvent *e, QgsMapToolCapture::CaptureMode mode ) { - const QgsPoint point = mapPoint( *e ); + Q_UNUSED( mode ) - mSnapIndicator->setMatch( e->mapPointMatch() ); + const QgsPoint point = mParentTool->mapPoint( *e ); if ( mTempRubberBand ) { diff --git a/src/app/maptools/qgsmaptoolshapeellipsecenter2points.h b/src/app/maptools/qgsmaptoolshapeellipsecenter2points.h new file mode 100644 index 000000000000..9e37a46e2de9 --- /dev/null +++ b/src/app/maptools/qgsmaptoolshapeellipsecenter2points.h @@ -0,0 +1,53 @@ +/*************************************************************************** + qgsmaptoolshapeellipsecenter2points.h - map tool for adding ellipse + from center and 2 points + --------------------- + begin : July 2017 + copyright : (C) 2017 by Loïc Bartoletti + email : lbartoletti at tuxfamily dot org + *************************************************************************** + * * + * 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 3 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#ifndef QGSMAPTOOLSHAPEELLIPSECENTER2POINTS_H +#define QGSMAPTOOLSHAPEELLIPSECENTER2POINTS_H + +#include "qgsmaptoolshapeellipseabstract.h" +#include "qgis_app.h" +#include "qgsmaptoolshaperegistry.h" + +class APP_EXPORT QgsMapToolShapeEllipseCenter2PointsMetadata : public QgsMapToolShapeMetadata +{ + public: + QgsMapToolShapeEllipseCenter2PointsMetadata() + : QgsMapToolShapeMetadata() + {} + + static const QString TOOL_ID; + + QString id() const override; + QString name() const override; + QIcon icon() const override; + QgsMapToolShapeAbstract::ShapeCategory category() const override; + QgsMapToolShapeAbstract *factory( QgsMapToolCapture *parentTool ) const override; +}; + +class APP_EXPORT QgsMapToolShapeEllipseCenter2Points: public QgsMapToolShapeEllipseAbstract +{ + Q_OBJECT + + public: + QgsMapToolShapeEllipseCenter2Points( QgsMapToolCapture *parentTool ) + : QgsMapToolShapeEllipseAbstract( QgsMapToolShapeEllipseCenter2PointsMetadata::TOOL_ID, parentTool ) + {} + + bool cadCanvasReleaseEvent( QgsMapMouseEvent *e, QgsMapToolCapture::CaptureMode mode ) override; + void cadCanvasMoveEvent( QgsMapMouseEvent *e, QgsMapToolCapture::CaptureMode mode ) override; +}; + +#endif // QGSMAPTOOLSHAPEELLIPSECENTER2POINTS_H diff --git a/src/app/maptools/qgsmaptoolshapeellipsecenterpoint.cpp b/src/app/maptools/qgsmaptoolshapeellipsecenterpoint.cpp new file mode 100644 index 000000000000..72f5d13649a5 --- /dev/null +++ b/src/app/maptools/qgsmaptoolshapeellipsecenterpoint.cpp @@ -0,0 +1,89 @@ +/*************************************************************************** + qgmaptoolellipsecenterpoint.cpp - map tool for adding ellipse + from center and a point + --------------------- + begin : July 2017 + copyright : (C) 2017 by Loïc Bartoletti + email : lbartoletti at tuxfamily dot org + *************************************************************************** + * * + * 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 "qgsmaptoolshapeellipsecenterpoint.h" +#include "qgsgeometryrubberband.h" +#include "qgsmapcanvas.h" +#include "qgspoint.h" +#include "qgsmapmouseevent.h" +#include "qgsmaptoolcapture.h" +#include "qgsapplication.h" + +const QString QgsMapToolShapeEllipseCenterPointMetadata::TOOL_ID = QStringLiteral( "ellipse-center-point" ); + +QString QgsMapToolShapeEllipseCenterPointMetadata::id() const +{ + return QgsMapToolShapeEllipseCenterPointMetadata::TOOL_ID; +} + +QString QgsMapToolShapeEllipseCenterPointMetadata::name() const +{ + return QObject::tr( "Ellipse from center and a point" ); +} + +QIcon QgsMapToolShapeEllipseCenterPointMetadata::icon() const +{ + return QgsApplication::getThemeIcon( QStringLiteral( "/mActionEllipseCenterPoint.svg" ) ); +} + +QgsMapToolShapeAbstract::ShapeCategory QgsMapToolShapeEllipseCenterPointMetadata::category() const +{ + return QgsMapToolShapeAbstract::ShapeCategory::Ellipse; +} + +QgsMapToolShapeAbstract *QgsMapToolShapeEllipseCenterPointMetadata::factory( QgsMapToolCapture *parentTool ) const +{ + return new QgsMapToolShapeEllipseCenterPoint( parentTool ); +} + + +bool QgsMapToolShapeEllipseCenterPoint::cadCanvasReleaseEvent( QgsMapMouseEvent *e, QgsMapToolCapture::CaptureMode mode ) +{ + const QgsPoint point = mParentTool->mapPoint( *e ); + + if ( e->button() == Qt::LeftButton ) + { + if ( mPoints.empty() ) + mPoints.append( point ); + + if ( !mTempRubberBand ) + { + QgsWkbTypes::GeometryType type = mode == QgsMapToolCapture::CapturePolygon ? QgsWkbTypes::PolygonGeometry : QgsWkbTypes::LineGeometry; + mTempRubberBand = mParentTool->createGeometryRubberBand( type, true ); + mTempRubberBand->show(); + } + } + else if ( e->button() == Qt::RightButton ) + { + addEllipseToParentTool(); + return true; + } + + return false; +} + +void QgsMapToolShapeEllipseCenterPoint::cadCanvasMoveEvent( QgsMapMouseEvent *e, QgsMapToolCapture::CaptureMode mode ) +{ + Q_UNUSED( mode ) + + const QgsPoint point = mParentTool->mapPoint( *e ); + + if ( mTempRubberBand ) + { + mEllipse = QgsEllipse::fromCenterPoint( mPoints.at( 0 ), point ); + mTempRubberBand->setGeometry( mEllipse.toPolygon( segments() ) ); + } +} diff --git a/src/app/maptools/qgsmaptoolshapeellipsecenterpoint.h b/src/app/maptools/qgsmaptoolshapeellipsecenterpoint.h new file mode 100644 index 000000000000..bdd8145081e9 --- /dev/null +++ b/src/app/maptools/qgsmaptoolshapeellipsecenterpoint.h @@ -0,0 +1,51 @@ +/*************************************************************************** + qgmaptoolellipsecenterpoint.h - map tool for adding ellipse + from center and a point + --------------------- + begin : July 2017 + copyright : (C) 2017 by Loïc Bartoletti + email : lbartoletti at tuxfamily dot org + *************************************************************************** + * * + * 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 QGSMAPTOOLSHAPEELLIPSECENTERPOINT_H +#define QGSMAPTOOLSHAPEELLIPSECENTERPOINT_H + +#include "qgsmaptoolshapeellipseabstract.h" +#include "qgis_app.h" +#include "qgsmaptoolshaperegistry.h" + +class APP_EXPORT QgsMapToolShapeEllipseCenterPointMetadata : public QgsMapToolShapeMetadata +{ + public: + QgsMapToolShapeEllipseCenterPointMetadata() + : QgsMapToolShapeMetadata() + {} + + static const QString TOOL_ID; + + QString id() const override; + QString name() const override; + QIcon icon() const override; + QgsMapToolShapeAbstract::ShapeCategory category() const override; + QgsMapToolShapeAbstract *factory( QgsMapToolCapture *parentTool ) const override; +}; + +class APP_EXPORT QgsMapToolShapeEllipseCenterPoint: public QgsMapToolShapeEllipseAbstract +{ + Q_OBJECT + + public: + QgsMapToolShapeEllipseCenterPoint( QgsMapToolCapture *parentTool ) : QgsMapToolShapeEllipseAbstract( QgsMapToolShapeEllipseCenterPointMetadata::TOOL_ID, parentTool ) {} + + bool cadCanvasReleaseEvent( QgsMapMouseEvent *e, QgsMapToolCapture::CaptureMode mode ) override; + void cadCanvasMoveEvent( QgsMapMouseEvent *e, QgsMapToolCapture::CaptureMode mode ) override; +}; + +#endif // QGSMAPTOOLSHAPEELLIPSECENTERPOINT_H diff --git a/src/app/qgsmaptoolellipseextent.cpp b/src/app/maptools/qgsmaptoolshapeellipseextent.cpp similarity index 51% rename from src/app/qgsmaptoolellipseextent.cpp rename to src/app/maptools/qgsmaptoolshapeellipseextent.cpp index 0a5bb212f669..a81629a2f5ee 100644 --- a/src/app/qgsmaptoolellipseextent.cpp +++ b/src/app/maptools/qgsmaptoolshapeellipseextent.cpp @@ -1,5 +1,5 @@ /*************************************************************************** - qgmaptoolellipseextent.cpp - map tool for adding ellipse + qgmaptoolshapeellipseextent.cpp - map tool for adding ellipse from extent --------------------- begin : July 2017 @@ -14,34 +14,52 @@ * * ***************************************************************************/ -#include "qgsmaptoolellipseextent.h" +#include "qgsmaptoolshapeellipseextent.h" #include "qgsgeometryrubberband.h" #include "qgsmapcanvas.h" #include "qgspoint.h" #include "qgsgeometryutils.h" #include "qgslinestring.h" #include "qgsmapmouseevent.h" -#include "qgssnapindicator.h" +#include "qgsmaptoolcapture.h" +#include "qgsapplication.h" +const QString QgsMapToolShapeEllipseExtentMetadata::TOOL_ID = QStringLiteral( "ellipse-from-extent" ); -QgsMapToolEllipseExtent::QgsMapToolEllipseExtent( QgsMapToolCapture *parentTool, - QgsMapCanvas *canvas, CaptureMode mode ) - : QgsMapToolAddEllipse( parentTool, canvas, mode ) +QString QgsMapToolShapeEllipseExtentMetadata::id() const { + return QgsMapToolShapeEllipseExtentMetadata::TOOL_ID; } -void QgsMapToolEllipseExtent::cadCanvasReleaseEvent( QgsMapMouseEvent *e ) +QString QgsMapToolShapeEllipseExtentMetadata::name() const { - const QgsPoint point = mapPoint( *e ); + return QObject::tr( "Ellipse from Extent" ); +} + +QIcon QgsMapToolShapeEllipseExtentMetadata::icon() const +{ + return QgsApplication::getThemeIcon( QStringLiteral( "/mActionEllipseExtent.svg" ) ); +} + +QgsMapToolShapeAbstract::ShapeCategory QgsMapToolShapeEllipseExtentMetadata::category() const +{ + return QgsMapToolShapeAbstract::ShapeCategory::Ellipse; +} + +QgsMapToolShapeAbstract *QgsMapToolShapeEllipseExtentMetadata::factory( QgsMapToolCapture *parentTool ) const +{ + return new QgsMapToolShapeEllipseExtent( parentTool ); +} - if ( !currentVectorLayer() ) - { - notifyNotVectorLayer(); - clean(); - stopCapturing(); - e->ignore(); - return; - } + +QgsMapToolShapeEllipseExtent::QgsMapToolShapeEllipseExtent( QgsMapToolCapture *parentTool ) + : QgsMapToolShapeEllipseAbstract( QgsMapToolShapeEllipseExtentMetadata::TOOL_ID, parentTool ) +{ +} + +bool QgsMapToolShapeEllipseExtent::cadCanvasReleaseEvent( QgsMapMouseEvent *e, QgsMapToolCapture::CaptureMode mode ) +{ + const QgsPoint point = mParentTool->mapPoint( *e ); if ( e->button() == Qt::LeftButton ) { @@ -50,21 +68,25 @@ void QgsMapToolEllipseExtent::cadCanvasReleaseEvent( QgsMapMouseEvent *e ) if ( !mTempRubberBand ) { - mTempRubberBand = createGeometryRubberBand( mLayerType, true ); + QgsWkbTypes::GeometryType type = mode == QgsMapToolCapture::CapturePolygon ? QgsWkbTypes::PolygonGeometry : QgsWkbTypes::LineGeometry; + mTempRubberBand = mParentTool->createGeometryRubberBand( type, true ); mTempRubberBand->show(); } } else if ( e->button() == Qt::RightButton ) { - release( e ); + addEllipseToParentTool(); + return true; } + + return false; } -void QgsMapToolEllipseExtent::cadCanvasMoveEvent( QgsMapMouseEvent *e ) +void QgsMapToolShapeEllipseExtent::cadCanvasMoveEvent( QgsMapMouseEvent *e, QgsMapToolCapture::CaptureMode mode ) { - const QgsPoint point = mapPoint( *e ); + Q_UNUSED( mode ) - mSnapIndicator->setMatch( e->mapPointMatch() ); + const QgsPoint point = mParentTool->mapPoint( *e ); if ( mTempRubberBand ) { @@ -72,7 +94,7 @@ void QgsMapToolEllipseExtent::cadCanvasMoveEvent( QgsMapMouseEvent *e ) { case 1: { - if ( qgsDoubleNear( mCanvas->rotation(), 0.0 ) ) + if ( qgsDoubleNear( mParentTool->canvas()->rotation(), 0.0 ) ) { mEllipse = QgsEllipse::fromExtent( mPoints.at( 0 ), point ); mTempRubberBand->setGeometry( mEllipse.toPolygon( segments() ) ); diff --git a/src/app/maptools/qgsmaptoolshapeellipseextent.h b/src/app/maptools/qgsmaptoolshapeellipseextent.h new file mode 100644 index 000000000000..01ca27b1f048 --- /dev/null +++ b/src/app/maptools/qgsmaptoolshapeellipseextent.h @@ -0,0 +1,51 @@ +/*************************************************************************** + qgmaptoolshapeellipseextent.h - map tool for adding ellipse + from extent + --------------------- + begin : July 2017 + copyright : (C) 2017 by Loïc Bartoletti + email : lbartoletti at tuxfamily dot org + *************************************************************************** + * * + * 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 QGSMAPTOOLSHAPEELLIPSEEXTENT_H +#define QGSMAPTOOLSHAPEELLIPSEEXTENT_H + +#include "qgsmaptoolshapeellipseabstract.h" +#include "qgis_app.h" +#include "qgsmaptoolshaperegistry.h" + +class APP_EXPORT QgsMapToolShapeEllipseExtentMetadata : public QgsMapToolShapeMetadata +{ + public: + QgsMapToolShapeEllipseExtentMetadata() + : QgsMapToolShapeMetadata() + {} + + static const QString TOOL_ID; + + QString id() const override; + QString name() const override; + QIcon icon() const override; + QgsMapToolShapeAbstract::ShapeCategory category() const override; + QgsMapToolShapeAbstract *factory( QgsMapToolCapture *parentTool ) const override; +}; + +class APP_EXPORT QgsMapToolShapeEllipseExtent: public QgsMapToolShapeEllipseAbstract +{ + Q_OBJECT + + public: + QgsMapToolShapeEllipseExtent( QgsMapToolCapture *parentTool ); + + bool cadCanvasReleaseEvent( QgsMapMouseEvent *e, QgsMapToolCapture::CaptureMode mode ) override; + void cadCanvasMoveEvent( QgsMapMouseEvent *e, QgsMapToolCapture::CaptureMode mode ) override; +}; + +#endif // QGSMAPTOOLSHAPEELLIPSEEXTENT_H diff --git a/src/app/qgsmaptoolellipsefoci.cpp b/src/app/maptools/qgsmaptoolshapeellipsefoci.cpp similarity index 51% rename from src/app/qgsmaptoolellipsefoci.cpp rename to src/app/maptools/qgsmaptoolshapeellipsefoci.cpp index 5b54b5299ab4..00f283d090e7 100644 --- a/src/app/qgsmaptoolellipsefoci.cpp +++ b/src/app/maptools/qgsmaptoolshapeellipsefoci.cpp @@ -1,5 +1,5 @@ /*************************************************************************** - qgmaptoolellipsefoci.cpp - map tool for adding ellipse + qgmaptoolshapeellipsefoci.cpp - map tool for adding ellipse from foci and a point --------------------- begin : July 2017 @@ -14,33 +14,51 @@ * * ***************************************************************************/ -#include "qgsmaptoolellipsefoci.h" +#include "qgsmaptoolshapeellipsefoci.h" #include "qgsgeometryrubberband.h" #include "qgslinestring.h" #include "qgsmapcanvas.h" #include "qgspoint.h" #include "qgsmapmouseevent.h" -#include "qgssnapindicator.h" +#include "qgsmaptoolcapture.h" #include +#include "qgsapplication.h" -QgsMapToolEllipseFoci::QgsMapToolEllipseFoci( QgsMapToolCapture *parentTool, - QgsMapCanvas *canvas, CaptureMode mode ) - : QgsMapToolAddEllipse( parentTool, canvas, mode ) +const QString QgsMapToolShapeEllipseFociMetadata::TOOL_ID = QStringLiteral( "ellipse-from-foci" ); + +QString QgsMapToolShapeEllipseFociMetadata::id() const { + return QgsMapToolShapeEllipseFociMetadata::TOOL_ID; } -void QgsMapToolEllipseFoci::cadCanvasReleaseEvent( QgsMapMouseEvent *e ) +QString QgsMapToolShapeEllipseFociMetadata::name() const { - const QgsPoint point = mapPoint( *e ); + return QObject::tr( "Ellipse from Foci" ); +} - if ( !currentVectorLayer() ) - { - notifyNotVectorLayer(); - clean(); - stopCapturing(); - e->ignore(); - return; - } +QIcon QgsMapToolShapeEllipseFociMetadata::icon() const +{ + return QgsApplication::getThemeIcon( QStringLiteral( "/mActionEllipseFoci.svg" ) ); +} + +QgsMapToolShapeAbstract::ShapeCategory QgsMapToolShapeEllipseFociMetadata::category() const +{ + return QgsMapToolShapeAbstract::ShapeCategory::Ellipse; +} + +QgsMapToolShapeAbstract *QgsMapToolShapeEllipseFociMetadata::factory( QgsMapToolCapture *parentTool ) const +{ + return new QgsMapToolShapeEllipseFoci( parentTool ); +} + +QgsMapToolShapeEllipseFoci::QgsMapToolShapeEllipseFoci( QgsMapToolCapture *parentTool ) + : QgsMapToolShapeEllipseAbstract( QgsMapToolShapeEllipseFociMetadata::TOOL_ID, parentTool ) +{ +} + +bool QgsMapToolShapeEllipseFoci::cadCanvasReleaseEvent( QgsMapMouseEvent *e, QgsMapToolCapture::CaptureMode mode ) +{ + const QgsPoint point = mParentTool->mapPoint( *e ); if ( e->button() == Qt::LeftButton ) { @@ -49,21 +67,25 @@ void QgsMapToolEllipseFoci::cadCanvasReleaseEvent( QgsMapMouseEvent *e ) if ( !mTempRubberBand ) { - mTempRubberBand = createGeometryRubberBand( mLayerType, true ); + QgsWkbTypes::GeometryType type = mode == QgsMapToolCapture::CapturePolygon ? QgsWkbTypes::PolygonGeometry : QgsWkbTypes::LineGeometry; + mTempRubberBand = mParentTool->createGeometryRubberBand( type, true ); mTempRubberBand->show(); } } else if ( e->button() == Qt::RightButton ) { - release( e ); + addEllipseToParentTool(); + return true; } + + return false; } -void QgsMapToolEllipseFoci::cadCanvasMoveEvent( QgsMapMouseEvent *e ) +void QgsMapToolShapeEllipseFoci::cadCanvasMoveEvent( QgsMapMouseEvent *e, QgsMapToolCapture::CaptureMode mode ) { - const QgsPoint point = mapPoint( *e ); + Q_UNUSED( mode ) - mSnapIndicator->setMatch( e->mapPointMatch() ); + const QgsPoint point = mParentTool->mapPoint( *e ); if ( mTempRubberBand ) { diff --git a/src/app/maptools/qgsmaptoolshapeellipsefoci.h b/src/app/maptools/qgsmaptoolshapeellipsefoci.h new file mode 100644 index 000000000000..123cb6cf6d8a --- /dev/null +++ b/src/app/maptools/qgsmaptoolshapeellipsefoci.h @@ -0,0 +1,51 @@ +/*************************************************************************** + qgmaptoolshapeellipsefoci.h - map tool for adding ellipse + from foci and a point + --------------------- + begin : July 2017 + copyright : (C) 2017 by Loïc Bartoletti + email : lbartoletti at tuxfamily dot org + *************************************************************************** + * * + * 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 3 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#ifndef QGSMAPTOOLSHAPEELLIPSEFOCI_H +#define QGSMAPTOOLSHAPEELLIPSEFOCI_H + +#include "qgsmaptoolshapeellipseabstract.h" +#include "qgis_app.h" +#include "qgsmaptoolshaperegistry.h" + +class APP_EXPORT QgsMapToolShapeEllipseFociMetadata : public QgsMapToolShapeMetadata +{ + public: + QgsMapToolShapeEllipseFociMetadata() + : QgsMapToolShapeMetadata() + {} + + static const QString TOOL_ID; + + QString id() const override; + QString name() const override; + QIcon icon() const override; + QgsMapToolShapeAbstract::ShapeCategory category() const override; + QgsMapToolShapeAbstract *factory( QgsMapToolCapture *parentTool ) const override; +}; + +class APP_EXPORT QgsMapToolShapeEllipseFoci: public QgsMapToolShapeEllipseAbstract +{ + Q_OBJECT + + public: + QgsMapToolShapeEllipseFoci( QgsMapToolCapture *parentTool ); + + bool cadCanvasReleaseEvent( QgsMapMouseEvent *e, QgsMapToolCapture::CaptureMode mode ) override; + void cadCanvasMoveEvent( QgsMapMouseEvent *e, QgsMapToolCapture::CaptureMode mode ) override; +}; + +#endif // QGSMAPTOOLSHAPEELLIPSEFOCI_H diff --git a/src/app/maptools/qgsmaptoolshaperectangle3points.cpp b/src/app/maptools/qgsmaptoolshaperectangle3points.cpp new file mode 100644 index 000000000000..de96f86e883e --- /dev/null +++ b/src/app/maptools/qgsmaptoolshaperectangle3points.cpp @@ -0,0 +1,168 @@ +/*************************************************************************** + qgsmaptoolshaperectangle3points.cpp - map tool for adding rectangle + from 3 points + --------------------- + begin : September 2017 + copyright : (C) 2017 by Loïc Bartoletti + email : lbartoletti at tuxfamily dot org +*************************************************************************** +* * +* 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 3 of the License, or * +* (at your option) any later version. * +* * +***************************************************************************/ + +#include "qgsmaptoolshaperectangle3points.h" +#include "qgsgeometryrubberband.h" +#include "qgsgeometryutils.h" +#include "qgslinestring.h" +#include "qgsmapcanvas.h" +#include "qgspoint.h" +#include "qgsmapmouseevent.h" +#include +#include "qgsmaptoolcapture.h" +#include "qgsapplication.h" + +const QString QgsMapToolShapeRectangle3PointsMetadata::TOOL_ID_DISTANCE = QStringLiteral( "rectangle-from-3-points-distance" ); +const QString QgsMapToolShapeRectangle3PointsMetadata::TOOL_ID_PROJECTED = QStringLiteral( "rectangle-from-3-points-projected" ); + +QString QgsMapToolShapeRectangle3PointsMetadata::id() const +{ + switch ( mCreateMode ) + { + case CreateMode::Distance: + return QgsMapToolShapeRectangle3PointsMetadata::TOOL_ID_DISTANCE; + case CreateMode::Projected: + return QgsMapToolShapeRectangle3PointsMetadata::TOOL_ID_PROJECTED; + } +} + +QString QgsMapToolShapeRectangle3PointsMetadata::name() const +{ + switch ( mCreateMode ) + { + case CreateMode::Distance: + return QObject::tr( "Rectangle from 3 points (distance)" ); + case CreateMode::Projected: + return QObject::tr( "Rectangle from 3 points (projected)" ); + } +} + +QIcon QgsMapToolShapeRectangle3PointsMetadata::icon() const +{ + switch ( mCreateMode ) + { + case CreateMode::Distance: + return QgsApplication::getThemeIcon( QStringLiteral( "/mActionRectangle3PointsDistance.svg" ) ); + case CreateMode::Projected: + return QgsApplication::getThemeIcon( QStringLiteral( "/mActionRectangle3PointsProjected.svg" ) ); + } + + return QIcon(); +} + +QgsMapToolShapeAbstract::ShapeCategory QgsMapToolShapeRectangle3PointsMetadata::category() const +{ + return QgsMapToolShapeAbstract::ShapeCategory::Rectangle; +} + +QgsMapToolShapeAbstract *QgsMapToolShapeRectangle3PointsMetadata::factory( QgsMapToolCapture *parentTool ) const +{ + return new QgsMapToolShapeRectangle3Points( id(), mCreateMode, parentTool ); +} + +QgsMapToolShapeRectangle3Points::QgsMapToolShapeRectangle3Points( const QString &id, QgsMapToolShapeRectangle3PointsMetadata::CreateMode createMode, QgsMapToolCapture *parentTool ) + : QgsMapToolShapeRectangleAbstract( id, parentTool ), + mCreateMode( createMode ) +{ +} + + +bool QgsMapToolShapeRectangle3Points::cadCanvasReleaseEvent( QgsMapMouseEvent *e, QgsMapToolCapture::CaptureMode mode ) +{ + QgsPoint point = mParentTool->mapPoint( *e ); + + if ( e->button() == Qt::LeftButton ) + { + bool is3D = false; + QgsVectorLayer *currentLayer = qobject_cast( mParentTool->canvas()->currentLayer() ); + if ( currentLayer ) + is3D = QgsWkbTypes::hasZ( currentLayer->wkbType() ); + + if ( is3D && !point.is3D() ) + point.addZValue( mParentTool->defaultZValue() ); + + if ( mPoints.size() < 2 ) + { + mPoints.append( point ); + } + + QgsWkbTypes::GeometryType type = mode == QgsMapToolCapture::CapturePolygon ? QgsWkbTypes::PolygonGeometry : QgsWkbTypes::LineGeometry; + + if ( !mPoints.isEmpty() && !mTempRubberBand ) + { + mTempRubberBand = mParentTool->createGeometryRubberBand( type, true ); + mTempRubberBand->show(); + } + if ( mPoints.size() == 3 ) + { + delete mTempRubberBand; + mTempRubberBand = mParentTool->createGeometryRubberBand( type, true ); // recreate rubberband for polygon + } + } + else if ( e->button() == Qt::RightButton ) + { + addRectangleToParentTool(); + return true; + } + + return false; +} + +void QgsMapToolShapeRectangle3Points::cadCanvasMoveEvent( QgsMapMouseEvent *e, QgsMapToolCapture::CaptureMode mode ) +{ + Q_UNUSED( mode ) + + QgsPoint point = mParentTool->mapPoint( *e ); + + if ( mTempRubberBand ) + { + switch ( mPoints.size() ) + { + case 1: + { + std::unique_ptr line( new QgsLineString() ); + line->addVertex( mPoints.at( 0 ) ); + line->addVertex( point ); + mTempRubberBand->setGeometry( line.release() ); + } + break; + case 2: + { + bool is3D = false; + QgsVectorLayer *currentLayer = qobject_cast( mParentTool->canvas()->currentLayer() ); + if ( currentLayer ) + is3D = QgsWkbTypes::hasZ( currentLayer->wkbType() ); + + if ( is3D && !point.is3D() ) + point.addZValue( mParentTool->defaultZValue() ); + + switch ( mCreateMode ) + { + case QgsMapToolShapeRectangle3PointsMetadata::CreateMode::Distance: + mRectangle = QgsQuadrilateral::rectangleFrom3Points( mPoints.at( 0 ), mPoints.at( 1 ), point, QgsQuadrilateral::Distance ); + break; + case QgsMapToolShapeRectangle3PointsMetadata::CreateMode::Projected: + mRectangle = QgsQuadrilateral::rectangleFrom3Points( mPoints.at( 0 ), mPoints.at( 1 ), point, QgsQuadrilateral::Projected ); + break; + } + mTempRubberBand->setGeometry( mRectangle.toPolygon( ) ); + } + break; + default: + break; + } + } +} diff --git a/src/app/maptools/qgsmaptoolshaperectangle3points.h b/src/app/maptools/qgsmaptoolshaperectangle3points.h new file mode 100644 index 000000000000..72e0819fd43e --- /dev/null +++ b/src/app/maptools/qgsmaptoolshaperectangle3points.h @@ -0,0 +1,69 @@ +/*************************************************************************** + qgsmaptoolshaperectangle3points.h - map tool for adding rectangle + from 3 points + --------------------- + begin : September 2017 + copyright : (C) 2017 by Loïc Bartoletti + email : lbartoletti at tuxfamily dot org +*************************************************************************** +* * +* 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 3 of the License, or * +* (at your option) any later version. * +* * +***************************************************************************/ + +#ifndef QGSMAPTOOLSHAPERECTANGLE3POINTS_H +#define QGSMAPTOOLSHAPERECTANGLE3POINTS_H + +#include "qgsmaptoolshaperectangleabstract.h" +#include "qgis_app.h" +#include "qgsmaptoolshaperegistry.h" + +class APP_EXPORT QgsMapToolShapeRectangle3PointsMetadata : public QgsMapToolShapeMetadata +{ + Q_GADGET + public: + enum class CreateMode + { + Distance, + Projected, + }; + Q_ENUM( CreateMode ) + + QgsMapToolShapeRectangle3PointsMetadata( CreateMode createMode ) + : QgsMapToolShapeMetadata() + , mCreateMode( createMode ) + {} + + static const QString TOOL_ID_PROJECTED; + static const QString TOOL_ID_DISTANCE; + + QString id() const override; + QString name() const override; + QIcon icon() const override; + QgsMapToolShapeAbstract::ShapeCategory category() const override; + QgsMapToolShapeAbstract *factory( QgsMapToolCapture *parentTool ) const override; + + private: + CreateMode mCreateMode; + +}; + +class APP_EXPORT QgsMapToolShapeRectangle3Points: public QgsMapToolShapeRectangleAbstract +{ + Q_OBJECT + + public: + + QgsMapToolShapeRectangle3Points( const QString &id, QgsMapToolShapeRectangle3PointsMetadata::CreateMode createMode, QgsMapToolCapture *parentTool ); + + bool cadCanvasReleaseEvent( QgsMapMouseEvent *e, QgsMapToolCapture::CaptureMode mode ) override; + void cadCanvasMoveEvent( QgsMapMouseEvent *e, QgsMapToolCapture::CaptureMode mode ) override; + + private: + QgsMapToolShapeRectangle3PointsMetadata::CreateMode mCreateMode; +}; + +#endif // QGSMAPTOOLSHAPERECTANGLE3POINTS_H diff --git a/src/app/qgsmaptooladdrectangle.cpp b/src/app/maptools/qgsmaptoolshaperectangleabstract.cpp similarity index 72% rename from src/app/qgsmaptooladdrectangle.cpp rename to src/app/maptools/qgsmaptoolshaperectangleabstract.cpp index 028066ed550f..cdc5dbd5429a 100644 --- a/src/app/qgsmaptooladdrectangle.cpp +++ b/src/app/maptools/qgsmaptoolshaperectangleabstract.cpp @@ -1,5 +1,5 @@ /*************************************************************************** - qgsmaptooladdrectangle.h - map tool for adding rectangle + qgsmaptoolshaperectangleabstract.h - map tool for adding rectangle --------------------- begin : July 2017 copyright : (C) 2017 @@ -13,25 +13,18 @@ * * ***************************************************************************/ -#include "qgsmaptooladdrectangle.h" +#include "qgsmaptoolshaperectangleabstract.h" #include "qgscompoundcurve.h" #include "qgscurvepolygon.h" #include "qgslinestring.h" #include "qgspolygon.h" #include "qgsgeometryrubberband.h" -#include "qgsgeometryutils.h" -#include "qgsmapcanvas.h" #include "qgspoint.h" #include "qgisapp.h" -#include "qgssnapindicator.h" +#include "qgsmaptoolcapture.h" -QgsMapToolAddRectangle::QgsMapToolAddRectangle( QgsMapToolCapture *parentTool, QgsMapCanvas *canvas, CaptureMode mode ) - : QgsMapToolAddAbstract( parentTool, canvas, mode ) -{ - mToolName = tr( "Add rectangle" ); -} -void QgsMapToolAddRectangle::deactivate( ) +void QgsMapToolShapeRectangleAbstract::addRectangleToParentTool( ) { if ( !mParentTool || !mRectangle.isValid() ) { @@ -45,7 +38,7 @@ void QgsMapToolAddRectangle::deactivate( ) for ( const QgsPoint &point : std::as_const( mPoints ) ) { if ( QgsWkbTypes::hasZ( point.wkbType() ) && - point.z() != defaultZValue() ) + point.z() != mParentTool->defaultZValue() ) { lineString->dropZValue(); lineString->addZValue( point.z() ); @@ -54,13 +47,10 @@ void QgsMapToolAddRectangle::deactivate( ) } mParentTool->addCurve( lineString.release() ); - clean(); - - QgsMapToolCapture::deactivate(); } -void QgsMapToolAddRectangle::clean() +void QgsMapToolShapeRectangleAbstract::clean() { - QgsMapToolAddAbstract::clean(); mRectangle = QgsQuadrilateral(); + QgsMapToolShapeAbstract::clean(); } diff --git a/src/app/qgsmaptooladdrectangle.h b/src/app/maptools/qgsmaptoolshaperectangleabstract.h similarity index 67% rename from src/app/qgsmaptooladdrectangle.h rename to src/app/maptools/qgsmaptoolshaperectangleabstract.h index 2e5fefe7d77b..a0a77df51f72 100644 --- a/src/app/qgsmaptooladdrectangle.h +++ b/src/app/maptools/qgsmaptoolshaperectangleabstract.h @@ -1,5 +1,5 @@ /*************************************************************************** - qgsmaptooladdrectangle.h - map tool for adding rectangle + qgsmaptoolshaperectangleabstract.h - map tool for adding rectangle --------------------- begin : July 2017 copyright : (C) 2017 @@ -13,29 +13,30 @@ * * ***************************************************************************/ -#ifndef QGSMAPTOOLADDRECTANGLE_H -#define QGSMAPTOOLADDRECTANGLE_H +#ifndef QGSMAPTOOLSHAPERECTANGLEABSTRACT_H +#define QGSMAPTOOLSHAPERECTANGLEABSTRACT_H -#include "qgsmaptooladdabstract.h" +#include "qgsmaptoolshapecircleabstract.h" #include "qgspolygon.h" #include "qgsquadrilateral.h" #include "qgis_app.h" -class APP_EXPORT QgsMapToolAddRectangle: public QgsMapToolAddAbstract +class APP_EXPORT QgsMapToolShapeRectangleAbstract: public QgsMapToolShapeAbstract { Q_OBJECT public: - QgsMapToolAddRectangle( QgsMapToolCapture *parentTool, QgsMapCanvas *canvas, CaptureMode mode = CaptureLine ); + QgsMapToolShapeRectangleAbstract( const QString &id, QgsMapToolCapture *parentTool ) + : QgsMapToolShapeAbstract( id, parentTool ) + {} - void deactivate( ) override; void clean() override; protected: - explicit QgsMapToolAddRectangle( QgsMapCanvas *canvas ) = delete; //forbidden + void addRectangleToParentTool(); //! Rectangle QgsQuadrilateral mRectangle; }; -#endif // QGSMAPTOOLADDRECTANGLE_H +#endif // QGSMAPTOOLSHAPERECTANGLEABSTRACT_H diff --git a/src/app/qgsmaptoolrectanglecenter.cpp b/src/app/maptools/qgsmaptoolshaperectanglecenter.cpp similarity index 52% rename from src/app/qgsmaptoolrectanglecenter.cpp rename to src/app/maptools/qgsmaptoolshaperectanglecenter.cpp index c0ff6827a5ed..f8afaa28491f 100644 --- a/src/app/qgsmaptoolrectanglecenter.cpp +++ b/src/app/maptools/qgsmaptoolshaperectanglecenter.cpp @@ -1,5 +1,5 @@ /*************************************************************************** - qgsmaptoolrectanglecenter.cpp - map tool for adding rectangle + qgsmaptoolshaperectanglecenter.cpp - map tool for adding rectangle from center and a point --------------------- begin : July 2017 @@ -14,37 +14,49 @@ * * ***************************************************************************/ -#include "qgsmaptoolrectanglecenter.h" +#include "qgsmaptoolshaperectanglecenter.h" #include "qgsgeometryrubberband.h" #include "qgsgeometryutils.h" #include "qgsmapcanvas.h" #include "qgslinestring.h" #include "qgspoint.h" #include "qgsmapmouseevent.h" -#include "qgssnapindicator.h" +#include "qgsmaptoolcapture.h" #include "qgsquadrilateral.h" +#include "qgsapplication.h" #include -QgsMapToolRectangleCenter::QgsMapToolRectangleCenter( QgsMapToolCapture *parentTool, - QgsMapCanvas *canvas, CaptureMode mode ) - : QgsMapToolAddRectangle( parentTool, canvas, mode ) +const QString QgsMapToolShapeRectangleCenterMetadata::TOOL_ID = QStringLiteral( "rectangle-from-center-and-a-point" ); + +QString QgsMapToolShapeRectangleCenterMetadata::id() const { - mToolName = tr( "Add rectangle from center and a point" ); + return QgsMapToolShapeRectangleCenterMetadata::TOOL_ID; } -void QgsMapToolRectangleCenter::cadCanvasReleaseEvent( QgsMapMouseEvent *e ) +QString QgsMapToolShapeRectangleCenterMetadata::name() const { - const QgsPoint point = mapPoint( *e ); + return QObject::tr( "Rectangle from center and a point" ); +} - if ( !currentVectorLayer() ) - { - notifyNotVectorLayer(); - clean(); - stopCapturing(); - e->ignore(); - return; - } +QIcon QgsMapToolShapeRectangleCenterMetadata::icon() const +{ + return QgsApplication::getThemeIcon( QStringLiteral( "/mActionRectangleCenter.svg" ) ); +} + +QgsMapToolShapeAbstract::ShapeCategory QgsMapToolShapeRectangleCenterMetadata::category() const +{ + return QgsMapToolShapeAbstract::ShapeCategory::Rectangle; +} + +QgsMapToolShapeAbstract *QgsMapToolShapeRectangleCenterMetadata::factory( QgsMapToolCapture *parentTool ) const +{ + return new QgsMapToolShapeRectangleCenter( parentTool ); +} + +bool QgsMapToolShapeRectangleCenter::cadCanvasReleaseEvent( QgsMapMouseEvent *e, QgsMapToolCapture::CaptureMode mode ) +{ + const QgsPoint point = mParentTool->mapPoint( *e ); if ( e->button() == Qt::LeftButton ) { @@ -53,23 +65,26 @@ void QgsMapToolRectangleCenter::cadCanvasReleaseEvent( QgsMapMouseEvent *e ) if ( !mTempRubberBand ) { - mTempRubberBand = createGeometryRubberBand( mLayerType, true ); + QgsWkbTypes::GeometryType type = mode == QgsMapToolCapture::CapturePolygon ? QgsWkbTypes::PolygonGeometry : QgsWkbTypes::LineGeometry; + mTempRubberBand = mParentTool->createGeometryRubberBand( type, true ); mTempRubberBand->show(); } } else if ( e->button() == Qt::RightButton ) { mPoints.append( point ); - - release( e ); + addRectangleToParentTool(); + return true; } + + return false; } -void QgsMapToolRectangleCenter::cadCanvasMoveEvent( QgsMapMouseEvent *e ) +void QgsMapToolShapeRectangleCenter::cadCanvasMoveEvent( QgsMapMouseEvent *e, QgsMapToolCapture::CaptureMode mode ) { - const QgsPoint point = mapPoint( *e ); + Q_UNUSED( mode ) - mSnapIndicator->setMatch( e->mapPointMatch() ); + const QgsPoint point = mParentTool->mapPoint( *e ); if ( mTempRubberBand ) { diff --git a/src/app/maptools/qgsmaptoolshaperectanglecenter.h b/src/app/maptools/qgsmaptoolshaperectanglecenter.h new file mode 100644 index 000000000000..1cece565fcf8 --- /dev/null +++ b/src/app/maptools/qgsmaptoolshaperectanglecenter.h @@ -0,0 +1,53 @@ +/*************************************************************************** + qgsmaptoolshaperectanglecenter.h - map tool for adding rectangle + from center and a point + --------------------- + begin : July 2017 + copyright : (C) 2017 by Loïc Bartoletti + email : lbartoletti at tuxfamily dot org + *************************************************************************** + * * + * 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 3 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#ifndef QGSMAPTOOLSHAPERECTANGLECENTER_H +#define QGSMAPTOOLSHAPERECTANGLECENTER_H + +#include "qgsmaptoolshaperectangleabstract.h" +#include "qgis_app.h" +#include "qgsmaptoolshaperegistry.h" + +class APP_EXPORT QgsMapToolShapeRectangleCenterMetadata : public QgsMapToolShapeMetadata +{ + public: + QgsMapToolShapeRectangleCenterMetadata() + : QgsMapToolShapeMetadata() + {} + + static const QString TOOL_ID; + + QString id() const override; + QString name() const override; + QIcon icon() const override; + QgsMapToolShapeAbstract::ShapeCategory category() const override; + QgsMapToolShapeAbstract *factory( QgsMapToolCapture *parentTool ) const override; +}; + +class APP_EXPORT QgsMapToolShapeRectangleCenter: public QgsMapToolShapeRectangleAbstract +{ + Q_OBJECT + + public: + QgsMapToolShapeRectangleCenter( QgsMapToolCapture *parentTool ) + : QgsMapToolShapeRectangleAbstract( QgsMapToolShapeRectangleCenterMetadata::TOOL_ID, parentTool ) + {} + + bool cadCanvasReleaseEvent( QgsMapMouseEvent *e, QgsMapToolCapture::CaptureMode mode ) override; + void cadCanvasMoveEvent( QgsMapMouseEvent *e, QgsMapToolCapture::CaptureMode mode ) override; +}; + +#endif // QGSMAPTOOLSHAPERECTANGLECENTER_H diff --git a/src/app/qgsmaptoolrectangleextent.cpp b/src/app/maptools/qgsmaptoolshaperectangleextent.cpp similarity index 52% rename from src/app/qgsmaptoolrectangleextent.cpp rename to src/app/maptools/qgsmaptoolshaperectangleextent.cpp index eeab860c5157..9e054517361e 100644 --- a/src/app/qgsmaptoolrectangleextent.cpp +++ b/src/app/maptools/qgsmaptoolshaperectangleextent.cpp @@ -1,5 +1,5 @@ /*************************************************************************** - qgsmaptoolrectangleextent.cpp - map tool for adding rectangle + qgsmaptoolshaperectangleextent.cpp - map tool for adding rectangle from extent --------------------- begin : July 2017 @@ -14,35 +14,47 @@ * * ***************************************************************************/ -#include "qgsmaptoolrectangleextent.h" +#include "qgsmaptoolshaperectangleextent.h" #include "qgsgeometryrubberband.h" #include "qgsgeometryutils.h" #include "qgsmapcanvas.h" #include "qgslinestring.h" #include "qgspoint.h" #include "qgsmapmouseevent.h" -#include "qgssnapindicator.h" +#include "qgsmaptoolcapture.h" #include +#include "qgsapplication.h" -QgsMapToolRectangleExtent::QgsMapToolRectangleExtent( QgsMapToolCapture *parentTool, - QgsMapCanvas *canvas, CaptureMode mode ) - : QgsMapToolAddRectangle( parentTool, canvas, mode ) +const QString QgsMapToolShapeRectangleExtentMetadata::TOOL_ID = QStringLiteral( "rectangle-from-extent" ); + +QString QgsMapToolShapeRectangleExtentMetadata::id() const { - mToolName = tr( "Add rectangle from extent" ); + return QgsMapToolShapeRectangleExtentMetadata::TOOL_ID; } -void QgsMapToolRectangleExtent::cadCanvasReleaseEvent( QgsMapMouseEvent *e ) +QString QgsMapToolShapeRectangleExtentMetadata::name() const { - const QgsPoint point = mapPoint( *e ); + return QObject::tr( "Rectangle from extent" ); +} - if ( !currentVectorLayer() ) - { - notifyNotVectorLayer(); - clean(); - stopCapturing(); - e->ignore(); - return; - } +QIcon QgsMapToolShapeRectangleExtentMetadata::icon() const +{ + return QgsApplication::getThemeIcon( QStringLiteral( "/mActionRectangleExtent.svg" ) ); +} + +QgsMapToolShapeAbstract::ShapeCategory QgsMapToolShapeRectangleExtentMetadata::category() const +{ + return QgsMapToolShapeAbstract::ShapeCategory::Rectangle; +} + +QgsMapToolShapeAbstract *QgsMapToolShapeRectangleExtentMetadata::factory( QgsMapToolCapture *parentTool ) const +{ + return new QgsMapToolShapeRectangleExtent( parentTool ); +} + +bool QgsMapToolShapeRectangleExtent::cadCanvasReleaseEvent( QgsMapMouseEvent *e, QgsMapToolCapture::CaptureMode mode ) +{ + const QgsPoint point = mParentTool->mapPoint( *e ); if ( e->button() == Qt::LeftButton ) { @@ -51,23 +63,26 @@ void QgsMapToolRectangleExtent::cadCanvasReleaseEvent( QgsMapMouseEvent *e ) if ( !mTempRubberBand ) { - mTempRubberBand = createGeometryRubberBand( mLayerType, true ); + QgsWkbTypes::GeometryType type = mode == QgsMapToolCapture::CapturePolygon ? QgsWkbTypes::PolygonGeometry : QgsWkbTypes::LineGeometry; + mTempRubberBand = mParentTool->createGeometryRubberBand( type, true ); mTempRubberBand->show(); } } else if ( e->button() == Qt::RightButton ) { mPoints.append( point ); - - release( e ); + addRectangleToParentTool(); + return true; } + + return false; } -void QgsMapToolRectangleExtent::cadCanvasMoveEvent( QgsMapMouseEvent *e ) +void QgsMapToolShapeRectangleExtent::cadCanvasMoveEvent( QgsMapMouseEvent *e, QgsMapToolCapture::CaptureMode mode ) { - const QgsPoint point = mapPoint( *e ); + Q_UNUSED( mode ) - mSnapIndicator->setMatch( e->mapPointMatch() ); + const QgsPoint point = mParentTool->mapPoint( *e ); if ( mTempRubberBand ) { diff --git a/src/app/maptools/qgsmaptoolshaperectangleextent.h b/src/app/maptools/qgsmaptoolshaperectangleextent.h new file mode 100644 index 000000000000..b13f2013ef81 --- /dev/null +++ b/src/app/maptools/qgsmaptoolshaperectangleextent.h @@ -0,0 +1,53 @@ +/*************************************************************************** + qgsmaptoolshaperectangleextent.h - map tool for adding rectangle + from extent + --------------------- + begin : July 2017 + copyright : (C) 2017 by Loïc Bartoletti + email : lbartoletti at tuxfamily dot org + *************************************************************************** + * * + * 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 3 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#ifndef QGSMAPTOOLSHAPERECTANGLEEXTENT_H +#define QGSMAPTOOLSHAPERECTANGLEEXTENT_H + +#include "qgsmaptoolshaperectangleabstract.h" +#include "qgis_app.h" +#include "qgsmaptoolshaperegistry.h" + +class APP_EXPORT QgsMapToolShapeRectangleExtentMetadata : public QgsMapToolShapeMetadata +{ + public: + QgsMapToolShapeRectangleExtentMetadata() + : QgsMapToolShapeMetadata() + {} + + static const QString TOOL_ID; + + QString id() const override; + QString name() const override; + QIcon icon() const override; + QgsMapToolShapeAbstract::ShapeCategory category() const override; + QgsMapToolShapeAbstract *factory( QgsMapToolCapture *parentTool ) const override; +}; + +class APP_EXPORT QgsMapToolShapeRectangleExtent: public QgsMapToolShapeRectangleAbstract +{ + Q_OBJECT + + public: + QgsMapToolShapeRectangleExtent( QgsMapToolCapture *parentTool ) + : QgsMapToolShapeRectangleAbstract( QgsMapToolShapeRectangleExtentMetadata::TOOL_ID, parentTool ) + {} + + bool cadCanvasReleaseEvent( QgsMapMouseEvent *e, QgsMapToolCapture::CaptureMode mode ) override; + void cadCanvasMoveEvent( QgsMapMouseEvent *e, QgsMapToolCapture::CaptureMode mode ) override; +}; + +#endif // QGSMAPTOOLSHAPERECTANGLEEXTENT_H diff --git a/src/app/maptools/qgsmaptoolshaperegularpolygon2points.cpp b/src/app/maptools/qgsmaptoolshaperegularpolygon2points.cpp new file mode 100644 index 000000000000..26ab154e995a --- /dev/null +++ b/src/app/maptools/qgsmaptoolshaperegularpolygon2points.cpp @@ -0,0 +1,100 @@ +/*************************************************************************** + qgsmaptoolshaperegularpolygon2points.cpp - map tool for adding regular + polygon from 2 points + --------------------- + begin : July 2017 + copyright : (C) 2017 by Loïc Bartoletti + email : lbartoletti at tuxfamily dot org + *************************************************************************** + * * + * 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 "qgsmaptoolshaperegularpolygon2points.h" +#include "qgsgeometryrubberband.h" +#include "qgsmapcanvas.h" +#include "qgspoint.h" +#include "qgsmapmouseevent.h" +#include "qgsmaptoolcapture.h" +#include "qgsapplication.h" + +const QString QgsMapToolShapeRegularPolygon2PointsMetadata::TOOL_ID = QStringLiteral( "regular-polygon-from-2-points" ); + +QString QgsMapToolShapeRegularPolygon2PointsMetadata::id() const +{ + return QgsMapToolShapeRegularPolygon2PointsMetadata::TOOL_ID; +} + +QString QgsMapToolShapeRegularPolygon2PointsMetadata::name() const +{ + return QObject::tr( "Regular polygon from 2 points" ); +} + +QIcon QgsMapToolShapeRegularPolygon2PointsMetadata::icon() const +{ + return QgsApplication::getThemeIcon( QStringLiteral( "/mActionRegularPolygon2Points.svg" ) ); +} + +QgsMapToolShapeAbstract::ShapeCategory QgsMapToolShapeRegularPolygon2PointsMetadata::category() const +{ + return QgsMapToolShapeAbstract::ShapeCategory::Circle; +} + +QgsMapToolShapeAbstract *QgsMapToolShapeRegularPolygon2PointsMetadata::factory( QgsMapToolCapture *parentTool ) const +{ + return new QgsMapToolShapeRegularPolygon2Points( parentTool ); +} + + +QgsMapToolShapeRegularPolygon2Points::~QgsMapToolShapeRegularPolygon2Points() +{ + if ( mNumberSidesSpinBox ) + { + deleteNumberSidesSpinBox(); + } +} + +bool QgsMapToolShapeRegularPolygon2Points::cadCanvasReleaseEvent( QgsMapMouseEvent *e, QgsMapToolCapture::CaptureMode mode ) +{ + const QgsPoint point = mParentTool->mapPoint( *e ); + + if ( e->button() == Qt::LeftButton ) + { + if ( mPoints.empty() ) + mPoints.append( point ); + + if ( !mTempRubberBand ) + { + QgsWkbTypes::GeometryType type = mode == QgsMapToolCapture::CapturePolygon ? QgsWkbTypes::PolygonGeometry : QgsWkbTypes::LineGeometry; + mTempRubberBand = mParentTool->createGeometryRubberBand( type, true ); + mTempRubberBand->show(); + + createNumberSidesSpinBox(); + } + } + else if ( e->button() == Qt::RightButton ) + { + mPoints.append( point ); + addRegularPolygonToParentTool(); + return true; + } + + return false; +} + +void QgsMapToolShapeRegularPolygon2Points::cadCanvasMoveEvent( QgsMapMouseEvent *e, QgsMapToolCapture::CaptureMode mode ) +{ + Q_UNUSED( mode ) + + const QgsPoint point = mParentTool->mapPoint( *e ); + + if ( mTempRubberBand ) + { + mRegularPolygon = QgsRegularPolygon( mPoints.at( 0 ), point, mNumberSidesSpinBox->value() ); + mTempRubberBand->setGeometry( mRegularPolygon.toPolygon() ); + } +} diff --git a/src/app/maptools/qgsmaptoolshaperegularpolygon2points.h b/src/app/maptools/qgsmaptoolshaperegularpolygon2points.h new file mode 100644 index 000000000000..98a01603ab54 --- /dev/null +++ b/src/app/maptools/qgsmaptoolshaperegularpolygon2points.h @@ -0,0 +1,56 @@ +/*************************************************************************** + qgmaptoolshaperegularpolygon2points.h - map tool for adding regular + polygon from 2 points + --------------------- + begin : July 2017 + copyright : (C) 2017 by Loïc Bartoletti + email : lbartoletti at tuxfamily dot org + *************************************************************************** + * * + * 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 QGSMAPTOOLSHAPEREGULARPOLYGON2POINTS_H +#define QGSMAPTOOLSHAPEREGULARPOLYGON2POINTS_H + +#include "qgsmaptoolshaperegularpolygonabstract.h" +#include "qgis_app.h" +#include "qgsmaptoolshaperegistry.h" + +class APP_EXPORT QgsMapToolShapeRegularPolygon2PointsMetadata : public QgsMapToolShapeMetadata +{ + public: + QgsMapToolShapeRegularPolygon2PointsMetadata() + : QgsMapToolShapeMetadata() + {} + + static const QString TOOL_ID; + + QString id() const override; + QString name() const override; + QIcon icon() const override; + QgsMapToolShapeAbstract::ShapeCategory category() const override; + QgsMapToolShapeAbstract *factory( QgsMapToolCapture *parentTool ) const override; +}; + +class APP_EXPORT QgsMapToolShapeRegularPolygon2Points: public QgsMapToolShapeRegularPolygonAbstract +{ + Q_OBJECT + + public: + QgsMapToolShapeRegularPolygon2Points( QgsMapToolCapture *parentTool ) + : QgsMapToolShapeRegularPolygonAbstract( QgsMapToolShapeRegularPolygon2PointsMetadata::TOOL_ID, parentTool ) + {} + + ~QgsMapToolShapeRegularPolygon2Points() override; + + bool cadCanvasReleaseEvent( QgsMapMouseEvent *e, QgsMapToolCapture::CaptureMode mode ) override; + void cadCanvasMoveEvent( QgsMapMouseEvent *e, QgsMapToolCapture::CaptureMode mode ) override; + +}; + +#endif // QGSMAPTOOLSHAPEREGULARPOLYGON2POINTS_H diff --git a/src/app/qgsmaptooladdregularpolygon.cpp b/src/app/maptools/qgsmaptoolshaperegularpolygonabstract.cpp similarity index 73% rename from src/app/qgsmaptooladdregularpolygon.cpp rename to src/app/maptools/qgsmaptoolshaperegularpolygonabstract.cpp index 7233e0a32ab2..814d3b558ef7 100644 --- a/src/app/qgsmaptooladdregularpolygon.cpp +++ b/src/app/maptools/qgsmaptoolshaperegularpolygonabstract.cpp @@ -1,5 +1,5 @@ /*************************************************************************** - qgsmaptooladdregularpolygon.cpp - map tool for adding regular polygon + qgsmaptoolshaperegularpolygonabstract.cpp - map tool for adding regular polygon --------------------- begin : July 2017 copyright : (C) 2017 @@ -13,22 +13,20 @@ * * ***************************************************************************/ -#include "qgsmaptooladdregularpolygon.h" +#include "qgsmaptoolshaperegularpolygonabstract.h" #include "qgsgeometryrubberband.h" #include "qgsgeometryutils.h" #include "qgsmapcanvas.h" #include "qgspoint.h" #include "qgisapp.h" -#include "qgsstatusbar.h" -#include "qgssnapindicator.h" +#include "qgsmaptoolcapture.h" -QgsMapToolAddRegularPolygon::QgsMapToolAddRegularPolygon( QgsMapToolCapture *parentTool, QgsMapCanvas *canvas, CaptureMode mode ) - : QgsMapToolAddAbstract( parentTool, canvas, mode ) +QgsMapToolShapeRegularPolygonAbstract::QgsMapToolShapeRegularPolygonAbstract(const QString &id, QgsMapToolCapture *parentTool ) + : QgsMapToolShapeAbstract( id, parentTool ) { - mToolName = tr( "Add regular polygon" ); } -void QgsMapToolAddRegularPolygon::createNumberSidesSpinBox() +void QgsMapToolShapeRegularPolygonAbstract::createNumberSidesSpinBox() { deleteNumberSidesSpinBox(); mNumberSidesSpinBox = std::make_unique(); @@ -39,7 +37,7 @@ void QgsMapToolAddRegularPolygon::createNumberSidesSpinBox() QgisApp::instance()->addUserInputWidget( mNumberSidesSpinBox.get() ); } -void QgsMapToolAddRegularPolygon::deleteNumberSidesSpinBox() +void QgsMapToolShapeRegularPolygonAbstract::deleteNumberSidesSpinBox() { if ( mNumberSidesSpinBox ) { @@ -47,7 +45,7 @@ void QgsMapToolAddRegularPolygon::deleteNumberSidesSpinBox() } } -void QgsMapToolAddRegularPolygon::deactivate() +void QgsMapToolShapeRegularPolygonAbstract::addRegularPolygonToParentTool() { if ( !mParentTool || mRegularPolygon.isEmpty() ) { @@ -60,7 +58,7 @@ void QgsMapToolAddRegularPolygon::deactivate() for ( const QgsPoint &point : std::as_const( mPoints ) ) { if ( QgsWkbTypes::hasZ( point.wkbType() ) && - point.z() != defaultZValue() ) + point.z() != mParentTool->defaultZValue() ) { ls->dropZValue(); ls->addZValue( point.z() ); @@ -69,19 +67,16 @@ void QgsMapToolAddRegularPolygon::deactivate() } mParentTool->addCurve( ls.release() ); - clean(); - - QgsMapToolCapture::deactivate(); } -void QgsMapToolAddRegularPolygon::clean() +void QgsMapToolShapeRegularPolygonAbstract::clean() { - QgsMapToolAddAbstract::clean(); - if ( mNumberSidesSpinBox ) { deleteNumberSidesSpinBox(); } mRegularPolygon = QgsRegularPolygon(); + + QgsMapToolShapeAbstract::clean(); } diff --git a/src/app/qgsmaptooladdregularpolygon.h b/src/app/maptools/qgsmaptoolshaperegularpolygonabstract.h similarity index 72% rename from src/app/qgsmaptooladdregularpolygon.h rename to src/app/maptools/qgsmaptoolshaperegularpolygonabstract.h index 258fc5d579cf..1cc9b0b2a182 100644 --- a/src/app/qgsmaptooladdregularpolygon.h +++ b/src/app/maptools/qgsmaptoolshaperegularpolygonabstract.h @@ -1,5 +1,5 @@ /*************************************************************************** - qgsmaptooladdregularpolygon.h - map tool for adding regular polygon + qgsmaptoolshaperegularpolygonabstract.h - map tool for adding regular polygon --------------------- begin : July 2017 copyright : (C) 2017 @@ -13,28 +13,27 @@ * * ***************************************************************************/ -#ifndef QGSMAPTOOLADDREGULARPOLYGON_H -#define QGSMAPTOOLADDREGULARPOLYGON_H +#ifndef QGSMAPTOOLSHAPEREGULARPOLYGONABSTRACT_H +#define QGSMAPTOOLSHAPEREGULARPOLYGONABSTRACT_H -#include "qgsmaptooladdabstract.h" +#include "qgsmaptoolshapeabstract.h" #include "qgsregularpolygon.h" #include "qgsspinbox.h" #include "qgis_app.h" class QSpinBox; -class APP_EXPORT QgsMapToolAddRegularPolygon: public QgsMapToolAddAbstract +class APP_EXPORT QgsMapToolShapeRegularPolygonAbstract: public QgsMapToolShapeAbstract { Q_OBJECT public: - QgsMapToolAddRegularPolygon( QgsMapToolCapture *parentTool, QgsMapCanvas *canvas, CaptureMode mode = CaptureLine ); + QgsMapToolShapeRegularPolygonAbstract(const QString &id, QgsMapToolCapture *parentTool); - void deactivate() override; void clean() override; protected: - explicit QgsMapToolAddRegularPolygon( QgsMapCanvas *canvas ) = delete; //forbidden + void addRegularPolygonToParentTool(); std::unique_ptr mNumberSidesSpinBox; int mNumberSides = 6; @@ -48,4 +47,4 @@ class APP_EXPORT QgsMapToolAddRegularPolygon: public QgsMapToolAddAbstract QgsRegularPolygon mRegularPolygon; }; -#endif // QGSMAPTOOLADDREGULARPOLYGON_H +#endif // QGSMAPTOOLSHAPEREGULARPOLYGONABSTRACT_H diff --git a/src/app/maptools/qgsmaptoolshaperegularpolygoncentercorner.cpp b/src/app/maptools/qgsmaptoolshaperegularpolygoncentercorner.cpp new file mode 100644 index 000000000000..4d2c516aa78b --- /dev/null +++ b/src/app/maptools/qgsmaptoolshaperegularpolygoncentercorner.cpp @@ -0,0 +1,98 @@ +/*************************************************************************** + qgsmaptoolshaperegularpolygoncentercorner.cpp - map tool for adding regular + polygon from center and a corner + --------------------- + begin : July 2017 + copyright : (C) 2017 by Loïc Bartoletti + email : lbartoletti at tuxfamily dot org + *************************************************************************** + * * + * 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 "qgsmaptoolshaperegularpolygoncentercorner.h" +#include "qgsgeometryrubberband.h" +#include "qgsmapcanvas.h" +#include "qgspoint.h" +#include "qgsmapmouseevent.h" +#include "qgsmaptoolcapture.h" +#include "qgsapplication.h" + +const QString QgsMapToolShapeRegularPolygonCenterCornerMetadata::TOOL_ID = QStringLiteral( "regular-polygon-from-center-and-a-corner" ); + +QString QgsMapToolShapeRegularPolygonCenterCornerMetadata::id() const +{ + return QgsMapToolShapeRegularPolygonCenterCornerMetadata::TOOL_ID; +} + +QString QgsMapToolShapeRegularPolygonCenterCornerMetadata::name() const +{ + return QObject::tr( "Regular polygon from center and a corner" ); +} + +QIcon QgsMapToolShapeRegularPolygonCenterCornerMetadata::icon() const +{ + return QgsApplication::getThemeIcon( QStringLiteral( "/mActionRegularPolygonCenterCorner.svg" ) ); +} + +QgsMapToolShapeAbstract::ShapeCategory QgsMapToolShapeRegularPolygonCenterCornerMetadata::category() const +{ + return QgsMapToolShapeAbstract::ShapeCategory::RegularPolygon; +} + +QgsMapToolShapeAbstract *QgsMapToolShapeRegularPolygonCenterCornerMetadata::factory( QgsMapToolCapture *parentTool ) const +{ + return new QgsMapToolShapeRegularPolygonCenterCorner( parentTool ); +} + + +QgsMapToolShapeRegularPolygonCenterCorner::~QgsMapToolShapeRegularPolygonCenterCorner() +{ + deleteNumberSidesSpinBox(); +} + +bool QgsMapToolShapeRegularPolygonCenterCorner::cadCanvasReleaseEvent( QgsMapMouseEvent *e, QgsMapToolCapture::CaptureMode mode ) +{ + const QgsPoint point = mParentTool->mapPoint( *e ); + + if ( e->button() == Qt::LeftButton ) + { + if ( mPoints.empty() ) + mPoints.append( point ); + + if ( !mTempRubberBand ) + { + QgsWkbTypes::GeometryType type = mode == QgsMapToolCapture::CapturePolygon ? QgsWkbTypes::PolygonGeometry : QgsWkbTypes::LineGeometry; + mTempRubberBand = mParentTool->createGeometryRubberBand( type, true ); + mTempRubberBand->show(); + + createNumberSidesSpinBox(); + } + } + else if ( e->button() == Qt::RightButton ) + { + mPoints.append( point ); + addRegularPolygonToParentTool(); + return true; + } + + return false; +} + +void QgsMapToolShapeRegularPolygonCenterCorner::cadCanvasMoveEvent( QgsMapMouseEvent *e, QgsMapToolCapture::CaptureMode mode ) +{ + Q_UNUSED( mode ) + + const QgsPoint point = mParentTool->mapPoint( *e ); + + if ( mTempRubberBand ) + { + const QgsRegularPolygon::ConstructionOption option = QgsRegularPolygon::InscribedCircle; + mRegularPolygon = QgsRegularPolygon( mPoints.at( 0 ), point, mNumberSidesSpinBox->value(), option ); + mTempRubberBand->setGeometry( mRegularPolygon.toPolygon() ); + } +} diff --git a/src/app/maptools/qgsmaptoolshaperegularpolygoncentercorner.h b/src/app/maptools/qgsmaptoolshaperegularpolygoncentercorner.h new file mode 100644 index 000000000000..a170f701913b --- /dev/null +++ b/src/app/maptools/qgsmaptoolshaperegularpolygoncentercorner.h @@ -0,0 +1,54 @@ +/*************************************************************************** + qgsmaptoolshaperegularpolygoncentercorner.h - map tool for adding regular + polygon from center and a corner + --------------------- + begin : July 2017 + copyright : (C) 2017 by Loïc Bartoletti + email : lbartoletti at tuxfamily dot org + *************************************************************************** + * * + * 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 QGSMAPTOOLSHAPEREGULARPOLYGONCENTERCORNER_H +#define QGSMAPTOOLSHAPEREGULARPOLYGONCENTERCORNER_H + +#include "qgsmaptoolshaperegularpolygonabstract.h" +#include "qgis_app.h" +#include "qgsmaptoolshaperegistry.h" + +class APP_EXPORT QgsMapToolShapeRegularPolygonCenterCornerMetadata : public QgsMapToolShapeMetadata +{ + public: + QgsMapToolShapeRegularPolygonCenterCornerMetadata() + : QgsMapToolShapeMetadata() + {} + + static const QString TOOL_ID; + + QString id() const override; + QString name() const override; + QIcon icon() const override; + QgsMapToolShapeAbstract::ShapeCategory category() const override; + QgsMapToolShapeAbstract *factory( QgsMapToolCapture *parentTool ) const override; +}; + +class APP_EXPORT QgsMapToolShapeRegularPolygonCenterCorner: public QgsMapToolShapeRegularPolygonAbstract +{ + Q_OBJECT + + public: + QgsMapToolShapeRegularPolygonCenterCorner( QgsMapToolCapture *parentTool ) + : QgsMapToolShapeRegularPolygonAbstract( QgsMapToolShapeRegularPolygonCenterCornerMetadata::TOOL_ID, parentTool ) + {} + ~QgsMapToolShapeRegularPolygonCenterCorner() override; + + bool cadCanvasReleaseEvent( QgsMapMouseEvent *e, QgsMapToolCapture::CaptureMode mode ) override; + void cadCanvasMoveEvent( QgsMapMouseEvent *e, QgsMapToolCapture::CaptureMode mode ) override; +}; + +#endif // QGSMAPTOOLSHAPEREGULARPOLYGONCENTERCORNER_H diff --git a/src/app/maptools/qgsmaptoolshaperegularpolygoncenterpoint.cpp b/src/app/maptools/qgsmaptoolshaperegularpolygoncenterpoint.cpp new file mode 100644 index 000000000000..301a75a05224 --- /dev/null +++ b/src/app/maptools/qgsmaptoolshaperegularpolygoncenterpoint.cpp @@ -0,0 +1,101 @@ +/*************************************************************************** + qgsmaptoolshaperegularpolygoncenterpoint.cpp - map tool for adding regular + polygon from center and a point + --------------------- + begin : July 2017 + copyright : (C) 2017 by Loïc Bartoletti + email : lbartoletti at tuxfamily dot org + *************************************************************************** + * * + * 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 "qgsmaptoolshaperegularpolygoncenterpoint.h" +#include "qgsgeometryrubberband.h" +#include "qgsmapcanvas.h" +#include "qgspoint.h" +#include "qgsmapmouseevent.h" +#include "qgsmaptoolcapture.h" +#include "qgsapplication.h" + +const QString QgsMapToolShapeRegularPolygonCenterPointMetadata::TOOL_ID = QStringLiteral( "regular-polygon-from-center-point" ); + +QString QgsMapToolShapeRegularPolygonCenterPointMetadata::id() const +{ + return QgsMapToolShapeRegularPolygonCenterPointMetadata::TOOL_ID; +} + +QString QgsMapToolShapeRegularPolygonCenterPointMetadata::name() const +{ + return QObject::tr( "Regular polygon from center and a point" ); +} + +QIcon QgsMapToolShapeRegularPolygonCenterPointMetadata::icon() const +{ + return QgsApplication::getThemeIcon( QStringLiteral( "/mActionRegularPolygonCenterPoint.svg" ) ); +} + +QgsMapToolShapeAbstract::ShapeCategory QgsMapToolShapeRegularPolygonCenterPointMetadata::category() const +{ + return QgsMapToolShapeAbstract::ShapeCategory::RegularPolygon; +} + +QgsMapToolShapeAbstract *QgsMapToolShapeRegularPolygonCenterPointMetadata::factory( QgsMapToolCapture *parentTool ) const +{ + return new QgsMapToolShapeRegularPolygonCenterPoint( parentTool ); +} + +QgsMapToolShapeRegularPolygonCenterPoint::~QgsMapToolShapeRegularPolygonCenterPoint() +{ + deleteNumberSidesSpinBox(); +} + +bool QgsMapToolShapeRegularPolygonCenterPoint::cadCanvasReleaseEvent( QgsMapMouseEvent *e, QgsMapToolCapture::CaptureMode mode ) +{ + + const QgsPoint point = mParentTool->mapPoint( *e ); + + if ( e->button() == Qt::LeftButton ) + { + if ( mPoints.size() < 1 ) + mPoints.append( point ); + + if ( !mPoints.isEmpty() ) + { + if ( !mTempRubberBand ) + { + QgsWkbTypes::GeometryType type = mode == QgsMapToolCapture::CapturePolygon ? QgsWkbTypes::PolygonGeometry : QgsWkbTypes::LineGeometry; + mTempRubberBand = mParentTool->createGeometryRubberBand( type, true ); + mTempRubberBand->show(); + + createNumberSidesSpinBox(); + } + } + } + else if ( e->button() == Qt::RightButton ) + { + mPoints.append( point ); + addRegularPolygonToParentTool(); + return true; + } + + return false; +} + +void QgsMapToolShapeRegularPolygonCenterPoint::cadCanvasMoveEvent( QgsMapMouseEvent *e, QgsMapToolCapture::CaptureMode mode ) +{ + Q_UNUSED( mode ) + + const QgsPoint point = mParentTool->mapPoint( *e ); + + if ( mTempRubberBand ) + { + const QgsRegularPolygon::ConstructionOption option = QgsRegularPolygon::CircumscribedCircle; + mRegularPolygon = QgsRegularPolygon( mPoints.at( 0 ), point, mNumberSidesSpinBox->value(), option ); + mTempRubberBand->setGeometry( mRegularPolygon.toPolygon() ); + } +} diff --git a/src/app/maptools/qgsmaptoolshaperegularpolygoncenterpoint.h b/src/app/maptools/qgsmaptoolshaperegularpolygoncenterpoint.h new file mode 100644 index 000000000000..2bf9e365b2a8 --- /dev/null +++ b/src/app/maptools/qgsmaptoolshaperegularpolygoncenterpoint.h @@ -0,0 +1,54 @@ +/*************************************************************************** + qgsmaptoolshaperegularpolygoncenterpoint.h - map tool for adding regular + polygon from center and a point + --------------------- + begin : July 2017 + copyright : (C) 2017 by Loïc Bartoletti + email : lbartoletti at tuxfamily dot org + *************************************************************************** + * * + * 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 QGSMAPTOOLSHAPEREGULARPOLYGONCENTERPOINT_H +#define QGSMAPTOOLSHAPEREGULARPOLYGONCENTERPOINT_H + +#include "qgsmaptoolshaperegularpolygonabstract.h" +#include "qgis_app.h" +#include "qgsmaptoolshaperegistry.h" + +class APP_EXPORT QgsMapToolShapeRegularPolygonCenterPointMetadata : public QgsMapToolShapeMetadata +{ + public: + QgsMapToolShapeRegularPolygonCenterPointMetadata() + : QgsMapToolShapeMetadata() + {} + + static const QString TOOL_ID; + + QString id() const override; + QString name() const override; + QIcon icon() const override; + QgsMapToolShapeAbstract::ShapeCategory category() const override; + QgsMapToolShapeAbstract *factory( QgsMapToolCapture *parentTool ) const override; +}; + +class APP_EXPORT QgsMapToolShapeRegularPolygonCenterPoint: public QgsMapToolShapeRegularPolygonAbstract +{ + Q_OBJECT + + public: + QgsMapToolShapeRegularPolygonCenterPoint( QgsMapToolCapture *parentTool ) + : QgsMapToolShapeRegularPolygonAbstract( QgsMapToolShapeRegularPolygonCenterPointMetadata::TOOL_ID, parentTool ) + {} + ~QgsMapToolShapeRegularPolygonCenterPoint() override; + + bool cadCanvasReleaseEvent( QgsMapMouseEvent *e, QgsMapToolCapture::CaptureMode mode ) override; + void cadCanvasMoveEvent( QgsMapMouseEvent *e, QgsMapToolCapture::CaptureMode mode ) override; +}; + +#endif // QGSMAPTOOLSHAPEREGULARPOLYGONCENTERPOINT_H diff --git a/src/app/qgisapp.cpp b/src/app/qgisapp.cpp index e8a029cbab0a..3a80a8c206f2 100644 --- a/src/app/qgisapp.cpp +++ b/src/app/qgisapp.cpp @@ -444,6 +444,25 @@ Q_GUI_EXPORT extern int qt_defaultDpiX(); #include "pointcloud/qgspointcloudelevationpropertieswidget.h" #include "pointcloud/qgspointcloudlayerstylewidget.h" +#include "qgsmaptoolsdigitizingtechniquemanager.h" +#include "qgsmaptoolshaperegistry.h" +#include "qgsmaptoolshapecircularstringradius.h" +#include "qgsmaptoolshapecircle2points.h" +#include "qgsmaptoolshapecircle3points.h" +#include "qgsmaptoolshapecircle3tangents.h" +#include "qgsmaptoolshapecircle2tangentspoint.h" +#include "qgsmaptoolshapecirclecenterpoint.h" +#include "qgsmaptoolshapeellipsecenter2points.h" +#include "qgsmaptoolshapeellipsecenterpoint.h" +#include "qgsmaptoolshapeellipseextent.h" +#include "qgsmaptoolshapeellipsefoci.h" +#include "qgsmaptoolshaperectanglecenter.h" +#include "qgsmaptoolshaperectangleextent.h" +#include "qgsmaptoolshaperectangle3points.h" +#include "qgsmaptoolshaperegularpolygon2points.h" +#include "qgsmaptoolshaperegularpolygoncenterpoint.h" +#include "qgsmaptoolshaperegularpolygoncentercorner.h" + #ifdef ENABLE_MODELTEST #include "modeltest.h" #endif @@ -818,7 +837,7 @@ void QgisApp::annotationItemTypeAdded( int id ) mMapCanvas->setMapTool( tool->mapTool() ); if ( qobject_cast< QgsMapToolCapture * >( tool->mapTool() ) ) { - enableDigitizeTechniqueActions( checked, action ); + mDigitizingTechniqueManager->enableDigitizingTechniqueActions( checked, action ); } connect( tool->mapTool(), &QgsMapTool::deactivated, tool->mapTool(), &QObject::deleteLater ); @@ -1172,17 +1191,32 @@ QgisApp::QgisApp( QSplashScreen *splash, bool restorePlugins, bool skipBadLayers functionProfile( &QgisApp::createActions, this, QStringLiteral( "Create actions" ) ); functionProfile( &QgisApp::createActionGroups, this, QStringLiteral( "Create action group" ) ); - // create tools + // create map tools mMapTools = std::make_unique< QgsAppMapTools >( mMapCanvas, mAdvancedDigitizingDockWidget ); + mDigitizingTechniqueManager = new QgsMapToolsDigitizingTechniqueManager( this ); + + QgsGui::mapToolShapeRegistry()->addMapTool( new QgsMapToolShapeCircularStringRadiusMetadata() ); + QgsGui::mapToolShapeRegistry()->addMapTool( new QgsMapToolShapeCircle2PointsMetadata() ); + QgsGui::mapToolShapeRegistry()->addMapTool( new QgsMapToolShapeCircle3PointsMetadata() ); + QgsGui::mapToolShapeRegistry()->addMapTool( new QgsMapToolShapeCircle3TangentsMetadata() ); + QgsGui::mapToolShapeRegistry()->addMapTool( new QgsMapToolShapeCircle2TangentsPointMetadata() ); + QgsGui::mapToolShapeRegistry()->addMapTool( new QgsMapToolShapeCircleCenterPointMetadata() ); + QgsGui::mapToolShapeRegistry()->addMapTool( new QgsMapToolShapeEllipseCenter2PointsMetadata() ); + QgsGui::mapToolShapeRegistry()->addMapTool( new QgsMapToolShapeEllipseCenterPointMetadata() ); + QgsGui::mapToolShapeRegistry()->addMapTool( new QgsMapToolShapeEllipseExtentMetadata() ); + QgsGui::mapToolShapeRegistry()->addMapTool( new QgsMapToolShapeEllipseFociMetadata() ); + QgsGui::mapToolShapeRegistry()->addMapTool( new QgsMapToolShapeRectangleCenterMetadata() ); + QgsGui::mapToolShapeRegistry()->addMapTool( new QgsMapToolShapeRectangleExtentMetadata() ); + QgsGui::mapToolShapeRegistry()->addMapTool( new QgsMapToolShapeRectangle3PointsMetadata( QgsMapToolShapeRectangle3PointsMetadata::CreateMode::Distance ) ); + QgsGui::mapToolShapeRegistry()->addMapTool( new QgsMapToolShapeRectangle3PointsMetadata( QgsMapToolShapeRectangle3PointsMetadata::CreateMode::Projected ) ); + QgsGui::mapToolShapeRegistry()->addMapTool( new QgsMapToolShapeRegularPolygon2PointsMetadata() ); + QgsGui::mapToolShapeRegistry()->addMapTool( new QgsMapToolShapeRegularPolygonCenterPointMetadata() ); + QgsGui::mapToolShapeRegistry()->addMapTool( new QgsMapToolShapeRegularPolygonCenterCornerMetadata() ); + functionProfile( &QgisApp::createToolBars, this, QStringLiteral( "Toolbars" ) ); functionProfile( &QgisApp::createStatusBar, this, QStringLiteral( "Status bar" ) ); functionProfile( &QgisApp::setupCanvasTools, this, QStringLiteral( "Create canvas tools" ) ); - const QList< QgsMapToolCapture * > captureTools = mMapTools->captureTools(); - for ( QgsMapToolCapture *tool : captureTools ) - { - connect( tool->action(), &QAction::toggled, this, [this, tool]( bool checked ) { enableDigitizeTechniqueActions( checked, tool->action() ); } ); - } applyDefaultSettingsToCanvas( mMapCanvas ); @@ -1850,6 +1884,8 @@ QgisApp::QgisApp() mPanelMenu = new QMenu( this ); mProgressBar = new QProgressBar( this ); mStatusBar = new QgsStatusBar( this ); + mMapTools = std::make_unique< QgsAppMapTools >( mMapCanvas, mAdvancedDigitizingDockWidget ); + mDigitizingTechniqueManager = new QgsMapToolsDigitizingTechniqueManager( this ); mBearingNumericFormat.reset( QgsLocalDefaultSettings::bearingFormat() ); // More tests may need more members to be initialized @@ -1873,6 +1909,7 @@ QgisApp::~QgisApp() delete mInternalClipboard; delete mQgisInterface; delete mStyleSheetBuilder; + delete mDigitizingTechniqueManager; if ( QgsMapTool *tool = mMapCanvas->mapTool() ) mMapCanvas->unsetMapTool( tool ); @@ -2712,27 +2749,6 @@ void QgisApp::createActions() connect( mActionCopyLayer, &QAction::triggered, this, &QgisApp::copyLayer ); connect( mActionPasteLayer, &QAction::triggered, this, &QgisApp::pasteLayer ); connect( mActionAddFeature, &QAction::triggered, this, &QgisApp::addFeature ); - connect( mActionCircularStringCurvePoint, &QAction::triggered, this, [ = ] { setMapTool( mMapTools->mapTool( QgsAppMapTools::CircularStringCurvePoint ) ); } ); - connect( mActionCircularStringRadius, &QAction::triggered, this, [ = ] { setMapTool( mMapTools->mapTool( QgsAppMapTools::CircularStringRadius ) ); } ); - connect( mActionCircle2Points, &QAction::triggered, this, [ = ] { setMapTool( mMapTools->mapTool( QgsAppMapTools::Circle2Points ), true ); } ); - connect( mActionCircle3Points, &QAction::triggered, this, [ = ] { setMapTool( mMapTools->mapTool( QgsAppMapTools::Circle3Points ), true ); } ); - connect( mActionCircle3Tangents, &QAction::triggered, this, [ = ] { setMapTool( mMapTools->mapTool( QgsAppMapTools::Circle3Tangents ), true ); } ); - connect( mActionCircle2TangentsPoint, &QAction::triggered, this, [ = ] { setMapTool( mMapTools->mapTool( QgsAppMapTools::Circle2TangentsPoint ), true ); } ); - connect( mActionCircleCenterPoint, &QAction::triggered, this, [ = ] { setMapTool( mMapTools->mapTool( QgsAppMapTools::CircleCenterPoint ), true ); } ); - connect( mActionEllipseCenter2Points, &QAction::triggered, this, [ = ] { setMapTool( mMapTools->mapTool( QgsAppMapTools::EllipseCenter2Points ), true ); } ); - connect( mActionEllipseCenterPoint, &QAction::triggered, this, [ = ] { setMapTool( mMapTools->mapTool( QgsAppMapTools::EllipseCenterPoint ), true ); } ); - connect( mActionEllipseExtent, &QAction::triggered, this, [ = ] { setMapTool( mMapTools->mapTool( QgsAppMapTools::EllipseExtent ), true ); } ); - connect( mActionEllipseFoci, &QAction::triggered, this, [ = ] { setMapTool( mMapTools->mapTool( QgsAppMapTools::EllipseFoci ), true ); } ); - connect( mActionRectangleCenterPoint, &QAction::triggered, this, [ = ] { setMapTool( mMapTools->mapTool( QgsAppMapTools::RectangleCenterPoint ), true ); } ); - connect( mActionRectangleExtent, &QAction::triggered, this, [ = ] { setMapTool( mMapTools->mapTool( QgsAppMapTools::RectangleExtent ), true ); } ); - connect( mActionRectangle3PointsDistance, &QAction::triggered, this, [ = ] { setMapTool( mMapTools->mapTool( QgsAppMapTools::Rectangle3PointsDistance ), true ); } ); - connect( mActionRectangle3PointsProjected, &QAction::triggered, this, [ = ] { setMapTool( mMapTools->mapTool( QgsAppMapTools::Rectangle3PointsProjected ), true ); } ); - connect( mActionRegularPolygon2Points, &QAction::triggered, this, [ = ] { setMapTool( mMapTools->mapTool( QgsAppMapTools::RegularPolygon2Points ), true ); } ); - connect( mActionRegularPolygonCenterPoint, &QAction::triggered, this, [ = ] { setMapTool( mMapTools->mapTool( QgsAppMapTools::RegularPolygonCenterPoint ), true ); } ); - connect( mActionRegularPolygonCenterCorner, &QAction::triggered, this, [ = ] { setMapTool( mMapTools->mapTool( QgsAppMapTools::RegularPolygonCenterCorner ), true ); } ); - connect( mActionDigitizeWithCurve, &QAction::triggered, this, &QgisApp::enableDigitizeWithCurve ); - connect( mActionStreamDigitize, &QAction::triggered, this, &QgisApp::enableStreamDigitizing ); - mActionStreamDigitize->setShortcut( tr( "R", "Keyboard shortcut: toggle stream digitizing" ) ); connect( mActionMoveFeature, &QAction::triggered, this, &QgisApp::moveFeature ); connect( mActionMoveFeatureCopy, &QAction::triggered, this, &QgisApp::moveFeatureCopy ); @@ -3114,24 +3130,6 @@ void QgisApp::createActionGroups() mMapToolGroup->addAction( mActionMeasureAngle ); mMapToolGroup->addAction( mActionMeasureBearing ); mMapToolGroup->addAction( mActionAddFeature ); - mMapToolGroup->addAction( mActionCircularStringCurvePoint ); - mMapToolGroup->addAction( mActionCircularStringRadius ); - mMapToolGroup->addAction( mActionCircle2Points ); - mMapToolGroup->addAction( mActionCircle3Points ); - mMapToolGroup->addAction( mActionCircle3Tangents ); - mMapToolGroup->addAction( mActionCircle2TangentsPoint ); - mMapToolGroup->addAction( mActionCircleCenterPoint ); - mMapToolGroup->addAction( mActionEllipseCenter2Points ); - mMapToolGroup->addAction( mActionEllipseCenterPoint ); - mMapToolGroup->addAction( mActionEllipseExtent ); - mMapToolGroup->addAction( mActionEllipseFoci ); - mMapToolGroup->addAction( mActionRectangleCenterPoint ); - mMapToolGroup->addAction( mActionRectangleExtent ); - mMapToolGroup->addAction( mActionRectangle3PointsDistance ); - mMapToolGroup->addAction( mActionRectangle3PointsProjected ); - mMapToolGroup->addAction( mActionRegularPolygon2Points ); - mMapToolGroup->addAction( mActionRegularPolygonCenterPoint ); - mMapToolGroup->addAction( mActionRegularPolygonCenterCorner ); mMapToolGroup->addAction( mActionMoveFeature ); mMapToolGroup->addAction( mActionMoveFeatureCopy ); mMapToolGroup->addAction( mActionRotateFeature ); @@ -3395,25 +3393,8 @@ void QgisApp::createToolBars() static_cast< void ( QgsDoubleSpinBox::* )( double ) >( &QgsDoubleSpinBox::valueChanged ), this, [ = ]( double v ) { mTracer->setOffset( v ); } ); - mDigitizeModeToolButton = new QToolButton(); - mDigitizeModeToolButton->setPopupMode( QToolButton::MenuButtonPopup ); - QMenu *digitizeMenu = new QMenu( mDigitizeModeToolButton ); - digitizeMenu->addAction( mActionDigitizeWithCurve ); - digitizeMenu->addAction( mActionStreamDigitize ); - digitizeMenu->addSeparator(); - digitizeMenu->addAction( mMapTools->streamDigitizingSettingsAction() ); - mDigitizeModeToolButton->setMenu( digitizeMenu ); + mDigitizingTechniqueManager->setupToolBars(); - switch ( settings.value( QStringLiteral( "UI/digitizeTechnique" ), 0 ).toInt() ) - { - case 0: - mDigitizeModeToolButton->setDefaultAction( mActionDigitizeWithCurve ); - break; - case 1: - mDigitizeModeToolButton->setDefaultAction( mActionStreamDigitize ); - break; - } - mAdvancedDigitizeToolBar->insertWidget( mAdvancedDigitizeToolBar->actions().at( 0 ), mDigitizeModeToolButton ); QList toolbarMenuActions; // Set action names so that they can be used in customization @@ -3660,138 +3641,6 @@ void QgisApp::createToolBars() layout->itemAt( i )->setAlignment( Qt::AlignLeft ); } - //circular string digitize tool button - QToolButton *tbAddCircularString = new QToolButton( mShapeDigitizeToolBar ); - tbAddCircularString->setPopupMode( QToolButton::MenuButtonPopup ); - tbAddCircularString->addAction( mActionCircularStringCurvePoint ); - tbAddCircularString->addAction( mActionCircularStringRadius ); - QAction *defActionCircularString = mActionCircularStringCurvePoint; - switch ( settings.value( QStringLiteral( "UI/defaultCircularString" ), 0 ).toInt() ) - { - case 0: - defActionCircularString = mActionCircularStringCurvePoint; - break; - case 1: - defActionCircularString = mActionCircularStringRadius; - break; - } - tbAddCircularString->setDefaultAction( defActionCircularString ); - QAction *addCircularAction = mShapeDigitizeToolBar->insertWidget( mActionVertexTool, tbAddCircularString ); - addCircularAction->setObjectName( QStringLiteral( "ActionAddCircularString" ) ); - connect( tbAddCircularString, &QToolButton::triggered, this, &QgisApp::toolButtonActionTriggered ); - - //circle digitize tool button - QToolButton *tbAddCircle = new QToolButton( mShapeDigitizeToolBar ); - tbAddCircle->setPopupMode( QToolButton::MenuButtonPopup ); - tbAddCircle->addAction( mActionCircle2Points ); - tbAddCircle->addAction( mActionCircle3Points ); - tbAddCircle->addAction( mActionCircle3Tangents ); - tbAddCircle->addAction( mActionCircle2TangentsPoint ); - tbAddCircle->addAction( mActionCircleCenterPoint ); - QAction *defActionCircle = mActionCircle2Points; - switch ( settings.value( QStringLiteral( "UI/defaultCircle" ), 0 ).toInt() ) - { - case 0: - defActionCircle = mActionCircle2Points; - break; - case 1: - defActionCircle = mActionCircle3Points; - break; - case 2: - defActionCircle = mActionCircle3Tangents; - break; - case 3: - defActionCircle = mActionCircle2TangentsPoint; - break; - case 4: - defActionCircle = mActionCircleCenterPoint; - break; - } - tbAddCircle->setDefaultAction( defActionCircle ); - QAction *addCircleAction = mShapeDigitizeToolBar->insertWidget( mActionVertexTool, tbAddCircle ); - addCircleAction->setObjectName( QStringLiteral( "ActionAddCircle" ) ); - connect( tbAddCircle, &QToolButton::triggered, this, &QgisApp::toolButtonActionTriggered ); - - //ellipse digitize tool button - QToolButton *tbAddEllipse = new QToolButton( mShapeDigitizeToolBar ); - tbAddEllipse->setPopupMode( QToolButton::MenuButtonPopup ); - tbAddEllipse->addAction( mActionEllipseCenter2Points ); - tbAddEllipse->addAction( mActionEllipseCenterPoint ); - tbAddEllipse->addAction( mActionEllipseExtent ); - tbAddEllipse->addAction( mActionEllipseFoci ); - QAction *defActionEllipse = mActionEllipseCenter2Points; - switch ( settings.value( QStringLiteral( "UI/defaultEllipse" ), 0 ).toInt() ) - { - case 0: - defActionEllipse = mActionEllipseCenter2Points; - break; - case 1: - defActionEllipse = mActionEllipseCenterPoint; - break; - case 2: - defActionEllipse = mActionEllipseExtent; - break; - case 3: - defActionEllipse = mActionEllipseFoci; - break; - } - tbAddEllipse->setDefaultAction( defActionEllipse ); - QAction *addEllipseAction = mShapeDigitizeToolBar->insertWidget( mActionVertexTool, tbAddEllipse ); - addEllipseAction->setObjectName( QStringLiteral( "ActionAddEllipse" ) ); - connect( tbAddEllipse, &QToolButton::triggered, this, &QgisApp::toolButtonActionTriggered ); - - //Rectangle digitize tool button - QToolButton *tbAddRectangle = new QToolButton( mShapeDigitizeToolBar ); - tbAddRectangle->setPopupMode( QToolButton::MenuButtonPopup ); - tbAddRectangle->addAction( mActionRectangleCenterPoint ); - tbAddRectangle->addAction( mActionRectangleExtent ); - tbAddRectangle->addAction( mActionRectangle3PointsDistance ); - tbAddRectangle->addAction( mActionRectangle3PointsProjected ); - QAction *defActionRectangle = mActionRectangleCenterPoint; - switch ( settings.value( QStringLiteral( "UI/defaultRectangle" ), 0 ).toInt() ) - { - case 0: - defActionRectangle = mActionRectangleCenterPoint; - break; - case 1: - defActionRectangle = mActionRectangleExtent; - break; - case 2: - defActionRectangle = mActionRectangle3PointsDistance; - break; - case 3: - defActionRectangle = mActionRectangle3PointsProjected; - break; - } - tbAddRectangle->setDefaultAction( defActionRectangle ); - QAction *addRectangleAction = mShapeDigitizeToolBar->insertWidget( mActionVertexTool, tbAddRectangle ); - addRectangleAction->setObjectName( QStringLiteral( "ActionAddRectangle" ) ); - connect( tbAddRectangle, &QToolButton::triggered, this, &QgisApp::toolButtonActionTriggered ); - - //Regular polygon digitize tool button - QToolButton *tbAddRegularPolygon = new QToolButton( mShapeDigitizeToolBar ); - tbAddRegularPolygon->setPopupMode( QToolButton::MenuButtonPopup ); - tbAddRegularPolygon->addAction( mActionRegularPolygon2Points ); - tbAddRegularPolygon->addAction( mActionRegularPolygonCenterPoint ); - tbAddRegularPolygon->addAction( mActionRegularPolygonCenterCorner ); - QAction *defActionRegularPolygon = mActionRegularPolygon2Points; - switch ( settings.value( QStringLiteral( "UI/defaultRegularPolygon" ), 0 ).toInt() ) - { - case 0: - defActionRegularPolygon = mActionRegularPolygon2Points; - break; - case 1: - defActionRegularPolygon = mActionRegularPolygonCenterPoint; - break; - case 2: - defActionRegularPolygon = mActionRegularPolygonCenterCorner; - break; - } - tbAddRegularPolygon->setDefaultAction( defActionRegularPolygon ); - QAction *addRegularPolygonAction = mShapeDigitizeToolBar->insertWidget( mActionVertexTool, tbAddRegularPolygon ); - addRegularPolygonAction->setObjectName( QStringLiteral( "ActionAddRegularPolygon" ) ); - connect( tbAddRegularPolygon, &QToolButton::triggered, this, &QgisApp::toolButtonActionTriggered ); - // Cad toolbar mAdvancedDigitizeToolBar->insertAction( mAdvancedDigitizeToolBar->actions().at( 0 ), mAdvancedDigitizingDockWidget->enableAction() ); @@ -3888,10 +3737,6 @@ void QgisApp::createToolBars() meshForceByLinesToolButton->setMenu( meshForceByLineMenu ); mMeshToolBar->addWidget( meshForceByLinesToolButton ); - digitizeMenu->addAction( mActionStreamDigitize ); - digitizeMenu->addSeparator(); - digitizeMenu->addAction( mMapTools->streamDigitizingSettingsAction() ); - mDigitizeModeToolButton->setMenu( digitizeMenu ); for ( QAction *mapToolAction : editMeshMapTool->mapToolActions() ) mMapToolGroup->addAction( mapToolAction ); @@ -4523,24 +4368,6 @@ void QgisApp::setupCanvasTools() mMapTools->mapTool( QgsAppMapTools::SvgAnnotation )->setAction( mActionSvgAnnotation ); mMapTools->mapTool( QgsAppMapTools::Annotation )->setAction( mActionAnnotation ); mMapTools->mapTool( QgsAppMapTools::AddFeature )->setAction( mActionAddFeature ); - mMapTools->mapTool( QgsAppMapTools::CircularStringCurvePoint )->setAction( mActionCircularStringCurvePoint ); - mMapTools->mapTool( QgsAppMapTools::CircularStringRadius )->setAction( mActionCircularStringRadius ); - mMapTools->mapTool( QgsAppMapTools::Circle2Points )->setAction( mActionCircle2Points ); - mMapTools->mapTool( QgsAppMapTools::Circle3Points )->setAction( mActionCircle3Points ); - mMapTools->mapTool( QgsAppMapTools::Circle3Tangents )->setAction( mActionCircle3Tangents ); - mMapTools->mapTool( QgsAppMapTools::Circle2TangentsPoint )->setAction( mActionCircle2TangentsPoint ); - mMapTools->mapTool( QgsAppMapTools::CircleCenterPoint )->setAction( mActionCircleCenterPoint ); - mMapTools->mapTool( QgsAppMapTools::EllipseCenter2Points )->setAction( mActionEllipseCenter2Points ); - mMapTools->mapTool( QgsAppMapTools::EllipseCenterPoint )->setAction( mActionEllipseCenterPoint ); - mMapTools->mapTool( QgsAppMapTools::EllipseExtent )->setAction( mActionEllipseExtent ); - mMapTools->mapTool( QgsAppMapTools::EllipseFoci )->setAction( mActionEllipseFoci ); - mMapTools->mapTool( QgsAppMapTools::RectangleCenterPoint )->setAction( mActionRectangleCenterPoint ); - mMapTools->mapTool( QgsAppMapTools::RectangleExtent )->setAction( mActionRectangleExtent ); - mMapTools->mapTool( QgsAppMapTools::Rectangle3PointsDistance )->setAction( mActionRectangle3PointsDistance ); - mMapTools->mapTool( QgsAppMapTools::Rectangle3PointsProjected )->setAction( mActionRectangle3PointsProjected ); - mMapTools->mapTool( QgsAppMapTools::RegularPolygon2Points )->setAction( mActionRegularPolygon2Points ); - mMapTools->mapTool( QgsAppMapTools::RegularPolygonCenterPoint )->setAction( mActionRegularPolygonCenterPoint ); - mMapTools->mapTool( QgsAppMapTools::RegularPolygonCenterCorner )->setAction( mActionRegularPolygonCenterCorner ); mMapTools->mapTool( QgsAppMapTools::MoveFeature )->setAction( mActionMoveFeature ); mMapTools->mapTool( QgsAppMapTools::MoveFeatureCopy )->setAction( mActionMoveFeatureCopy ); mMapTools->mapTool( QgsAppMapTools::RotateFeature )->setAction( mActionRotateFeature ); @@ -4582,6 +4409,8 @@ void QgisApp::setupCanvasTools() //ensure that non edit tool is initialized or we will get crashes in some situations mNonEditMapTool = mMapTools->mapTool( QgsAppMapTools::Pan ); + + mDigitizingTechniqueManager->setupCanvasTools(); } void QgisApp::createOverview() @@ -10619,94 +10448,6 @@ void QgisApp::snappingOptions() mSnappingDialogContainer->show(); } -void QgisApp::enableDigitizeWithCurve( bool enable ) -{ - if ( enable && mActionStreamDigitize->isChecked() ) - { - mActionStreamDigitize->setChecked( false ); - enableStreamDigitizing( false ); - } - - if ( enable ) - { - mDigitizeModeToolButton->setDefaultAction( mActionDigitizeWithCurve ); - QgsSettings().setValue( QStringLiteral( "UI/digitizeTechnique" ), 0 ); - } - - const QList< QgsMapToolCapture * > tools = captureTools(); - for ( QgsMapToolCapture *tool : tools ) - { - if ( tool->supportsTechnique( QgsMapToolCapture::CircularString ) ) - tool->setCircularDigitizingEnabled( enable ); - } - QgsSettings settings; - settings.setValue( QStringLiteral( "UI/digitizeWithCurve" ), enable ? 1 : 0 ); -} - -void QgisApp::enableStreamDigitizing( bool enable ) -{ - if ( enable && mActionDigitizeWithCurve->isChecked() ) - { - mActionDigitizeWithCurve->setChecked( false ); - enableDigitizeWithCurve( false ); - } - - if ( enable ) - { - mDigitizeModeToolButton->setDefaultAction( mActionStreamDigitize ); - QgsSettings().setValue( QStringLiteral( "UI/digitizeTechnique" ), 1 ); - } - - const QList< QgsMapToolCapture * > tools = captureTools(); - for ( QgsMapToolCapture *tool : tools ) - { - if ( tool->supportsTechnique( QgsMapToolCapture::Streaming ) ) - tool->setStreamDigitizingEnabled( enable ); - } - QgsSettings settings; - settings.setValue( QStringLiteral( "UI/digitizeWithStream" ), enable ? 1 : 0 ); -} - -void QgisApp::enableDigitizeTechniqueActions( bool enable, QAction *triggeredFromToolAction ) -{ - if ( !mMapTools ) - return; - - QgsSettings settings; - - const QList< QgsMapToolCapture * > tools = captureTools(); - - QSet< QgsMapToolCapture::CaptureTechnique > supportedTechniques; - for ( QgsMapToolCapture *tool : tools ) - { - if ( triggeredFromToolAction == tool->action() || ( !triggeredFromToolAction && mMapCanvas->mapTool() == tool ) ) - { - for ( QgsMapToolCapture::CaptureTechnique technique : { QgsMapToolCapture::CircularString, QgsMapToolCapture::Streaming } ) - { - if ( tool->supportsTechnique( technique ) ) - supportedTechniques.insert( technique ); - } - break; - } - } - - mActionDigitizeWithCurve->setEnabled( enable && supportedTechniques.contains( QgsMapToolCapture::CircularString ) ); - const bool curveIsChecked = settings.value( QStringLiteral( "UI/digitizeWithCurve" ) ).toInt(); - mActionDigitizeWithCurve->setChecked( curveIsChecked && mActionDigitizeWithCurve->isEnabled() ); - - mActionStreamDigitize->setEnabled( enable && supportedTechniques.contains( QgsMapToolCapture::Streaming ) ); - const bool streamIsChecked = settings.value( QStringLiteral( "UI/digitizeWithStream" ) ).toInt(); - mActionStreamDigitize->setChecked( streamIsChecked && mActionStreamDigitize->isEnabled() ); - - for ( QgsMapToolCapture *tool : tools ) - { - if ( tool->supportsTechnique( QgsMapToolCapture::CircularString ) ) - tool->setCircularDigitizingEnabled( mActionDigitizeWithCurve->isChecked() ); - if ( tool->supportsTechnique( QgsMapToolCapture::Streaming ) ) - tool->setStreamDigitizingEnabled( mActionStreamDigitize->isChecked() ); - } -} - void QgisApp::splitFeatures() { mMapCanvas->setMapTool( mMapTools->mapTool( QgsAppMapTools::SplitFeatures ) ); @@ -15573,28 +15314,6 @@ void QgisApp::activateDeactivateLayerRelatedActions( QgsMapLayer *layer ) mActionAddToOverview->setEnabled( false ); mActionFeatureAction->setEnabled( false ); mActionAddFeature->setEnabled( false ); - mActionCircularStringCurvePoint->setEnabled( false ); - mActionCircularStringRadius->setEnabled( false ); - mMenuCircle->setEnabled( false ); - mActionCircle2Points->setEnabled( false ); - mActionCircle3Points->setEnabled( false ); - mActionCircle3Tangents->setEnabled( false ); - mActionCircle2TangentsPoint->setEnabled( false ); - mActionCircleCenterPoint->setEnabled( false ); - mMenuEllipse->setEnabled( false ); - mActionEllipseCenter2Points->setEnabled( false ); - mActionEllipseCenterPoint->setEnabled( false ); - mActionEllipseExtent->setEnabled( false ); - mActionEllipseFoci->setEnabled( false ); - mMenuRectangle->setEnabled( false ); - mActionRectangleCenterPoint->setEnabled( false ); - mActionRectangleExtent->setEnabled( false ); - mActionRectangle3PointsDistance->setEnabled( false ); - mActionRectangle3PointsProjected->setEnabled( false ); - mMenuRegularPolygon->setEnabled( false ); - mActionRegularPolygon2Points->setEnabled( false ); - mActionRegularPolygonCenterPoint->setEnabled( false ); - mActionRegularPolygonCenterCorner->setEnabled( false ); mMenuEditGeometry->setEnabled( false ); mActionMoveFeature->setEnabled( false ); mActionMoveFeatureCopy->setEnabled( false ); @@ -15660,7 +15379,7 @@ void QgisApp::activateDeactivateLayerRelatedActions( QgsMapLayer *layer ) mActionZoomToLayer->setEnabled( false ); enableMeshEditingTools( false ); - enableDigitizeTechniqueActions( false ); + mDigitizingTechniqueManager->enableDigitizingTechniqueActions( false ); return; } @@ -15765,34 +15484,6 @@ void QgisApp::activateDeactivateLayerRelatedActions( QgsMapLayer *layer ) mActionAddFeature->setEnabled( isEditable && canAddFeatures ); - bool enableCircularTools; - bool enableShapeTools; - enableCircularTools = isEditable && ( canAddFeatures || canChangeGeometry ) - && ( vlayer->geometryType() == QgsWkbTypes::LineGeometry || vlayer->geometryType() == QgsWkbTypes::PolygonGeometry ); - enableShapeTools = enableCircularTools; - mActionCircularStringCurvePoint->setEnabled( enableCircularTools ); - mActionCircularStringRadius->setEnabled( enableCircularTools ); - mMenuCircle->setEnabled( enableShapeTools ); - mActionCircle2Points->setEnabled( enableShapeTools ); - mActionCircle3Points->setEnabled( enableShapeTools ); - mActionCircle3Tangents->setEnabled( enableShapeTools ); - mActionCircle2TangentsPoint->setEnabled( enableShapeTools ); - mActionCircleCenterPoint->setEnabled( enableShapeTools ); - mMenuEllipse->setEnabled( enableShapeTools ); - mActionEllipseCenter2Points->setEnabled( enableShapeTools ); - mActionEllipseCenterPoint->setEnabled( enableShapeTools ); - mActionEllipseExtent->setEnabled( enableShapeTools ); - mActionEllipseFoci->setEnabled( enableShapeTools ); - mMenuRectangle->setEnabled( enableShapeTools ); - mActionRectangleCenterPoint->setEnabled( enableShapeTools ); - mActionRectangleExtent->setEnabled( enableShapeTools ); - mActionRectangle3PointsDistance->setEnabled( enableShapeTools ); - mActionRectangle3PointsProjected->setEnabled( enableShapeTools ); - mMenuRegularPolygon->setEnabled( enableShapeTools ); - mActionRegularPolygon2Points->setEnabled( enableShapeTools ); - mActionRegularPolygonCenterPoint->setEnabled( enableShapeTools ); - mActionRegularPolygonCenterCorner->setEnabled( enableShapeTools ); - //does provider allow deleting of features? mActionDeleteSelected->setEnabled( isEditable && canDeleteFeatures && layerHasSelection ); mActionCutFeatures->setEnabled( isEditable && canDeleteFeatures && layerHasSelection ); @@ -15825,7 +15516,7 @@ void QgisApp::activateDeactivateLayerRelatedActions( QgsMapLayer *layer ) mActionVertexTool->setEnabled( isEditable && canChangeGeometry ); mActionVertexToolActiveLayer->setEnabled( isEditable && canChangeGeometry ); - enableDigitizeTechniqueActions( isEditable && canChangeGeometry ); + mDigitizingTechniqueManager->enableDigitizingTechniqueActions( isEditable && canChangeGeometry ); if ( vlayer->geometryType() == QgsWkbTypes::PointGeometry ) { @@ -15987,28 +15678,6 @@ void QgisApp::activateDeactivateLayerRelatedActions( QgsMapLayer *layer ) mActionSaveLayerDefinition->setEnabled( true ); mActionLayerSaveAs->setEnabled( true ); mActionAddFeature->setEnabled( false ); - mActionCircularStringCurvePoint->setEnabled( false ); - mActionCircularStringRadius->setEnabled( false ); - mMenuCircle->setEnabled( false ); - mActionCircle2Points->setEnabled( false ); - mActionCircle3Points->setEnabled( false ); - mActionCircle3Tangents->setEnabled( false ); - mActionCircle2TangentsPoint->setEnabled( false ); - mActionCircleCenterPoint->setEnabled( false ); - mMenuEllipse->setEnabled( false ); - mActionEllipseCenter2Points->setEnabled( false ); - mActionEllipseCenterPoint->setEnabled( false ); - mActionEllipseExtent->setEnabled( false ); - mActionEllipseFoci->setEnabled( false ); - mMenuRectangle->setEnabled( false ); - mActionRectangleCenterPoint->setEnabled( false ); - mActionRectangleExtent->setEnabled( false ); - mActionRectangle3PointsDistance->setEnabled( false ); - mActionRectangle3PointsProjected->setEnabled( false ); - mMenuRegularPolygon->setEnabled( false ); - mActionRegularPolygon2Points->setEnabled( false ); - mActionRegularPolygonCenterPoint->setEnabled( false ); - mActionRegularPolygonCenterCorner->setEnabled( false ); mMenuEditAttributes->setEnabled( false ); mMenuEditGeometry->setEnabled( false ); mActionReverseLine->setEnabled( false ); @@ -16039,7 +15708,7 @@ void QgisApp::activateDeactivateLayerRelatedActions( QgsMapLayer *layer ) mActionDiagramProperties->setEnabled( false ); enableMeshEditingTools( false ); - enableDigitizeTechniqueActions( false ); + mDigitizingTechniqueManager->enableDigitizingTechniqueActions( false ); //NOTE: This check does not really add any protection, as it is called on load not on layer select/activate //If you load a layer with a provider and idenitfy ability then load another without, the tool would be disabled for both @@ -16103,8 +15772,6 @@ void QgisApp::activateDeactivateLayerRelatedActions( QgsMapLayer *layer ) mActionSaveLayerDefinition->setEnabled( true ); mActionLayerSaveAs->setEnabled( false ); mActionAddFeature->setEnabled( false ); - mActionCircularStringCurvePoint->setEnabled( false ); - mActionCircularStringRadius->setEnabled( false ); mActionDeleteSelected->setEnabled( false ); mActionAddRing->setEnabled( false ); mActionFillRing->setEnabled( false ); @@ -16130,7 +15797,7 @@ void QgisApp::activateDeactivateLayerRelatedActions( QgsMapLayer *layer ) mActionLabeling->setEnabled( false ); mActionDiagramProperties->setEnabled( false ); mActionIdentify->setEnabled( true ); - enableDigitizeTechniqueActions( false ); + mDigitizingTechniqueManager->enableDigitizingTechniqueActions( false ); bool canSupportEditing = mlayer->supportsEditing(); bool isEditable = mlayer->isEditable(); @@ -16185,8 +15852,6 @@ void QgisApp::activateDeactivateLayerRelatedActions( QgsMapLayer *layer ) mActionSaveLayerDefinition->setEnabled( true ); mActionLayerSaveAs->setEnabled( false ); mActionAddFeature->setEnabled( false ); - mActionCircularStringCurvePoint->setEnabled( false ); - mActionCircularStringRadius->setEnabled( false ); mActionDeleteSelected->setEnabled( false ); mActionAddRing->setEnabled( false ); mActionFillRing->setEnabled( false ); @@ -16212,7 +15877,7 @@ void QgisApp::activateDeactivateLayerRelatedActions( QgsMapLayer *layer ) mActionLabeling->setEnabled( false ); mActionDiagramProperties->setEnabled( false ); mActionIdentify->setEnabled( true ); - enableDigitizeTechniqueActions( false ); + mDigitizingTechniqueManager->enableDigitizingTechniqueActions( false ); enableMeshEditingTools( false ); break; @@ -16255,8 +15920,6 @@ void QgisApp::activateDeactivateLayerRelatedActions( QgsMapLayer *layer ) mActionSaveLayerDefinition->setEnabled( true ); mActionLayerSaveAs->setEnabled( false ); mActionAddFeature->setEnabled( false ); - mActionCircularStringCurvePoint->setEnabled( false ); - mActionCircularStringRadius->setEnabled( false ); mActionDeleteSelected->setEnabled( false ); mActionAddRing->setEnabled( false ); mActionFillRing->setEnabled( false ); @@ -16282,7 +15945,7 @@ void QgisApp::activateDeactivateLayerRelatedActions( QgsMapLayer *layer ) mActionLabeling->setEnabled( false ); mActionDiagramProperties->setEnabled( false ); mActionIdentify->setEnabled( true ); - enableDigitizeTechniqueActions( false ); + mDigitizingTechniqueManager->enableDigitizingTechniqueActions( false ); enableMeshEditingTools( false ); break; @@ -16326,8 +15989,6 @@ void QgisApp::activateDeactivateLayerRelatedActions( QgsMapLayer *layer ) mActionSaveLayerDefinition->setEnabled( false ); mActionLayerSaveAs->setEnabled( false ); mActionAddFeature->setEnabled( false ); - mActionCircularStringCurvePoint->setEnabled( false ); - mActionCircularStringRadius->setEnabled( false ); mActionDeleteSelected->setEnabled( false ); mActionAddRing->setEnabled( false ); mActionFillRing->setEnabled( false ); @@ -16353,7 +16014,7 @@ void QgisApp::activateDeactivateLayerRelatedActions( QgsMapLayer *layer ) mActionLabeling->setEnabled( false ); mActionDiagramProperties->setEnabled( false ); mActionIdentify->setEnabled( true ); - enableDigitizeTechniqueActions( true ); + mDigitizingTechniqueManager->enableDigitizingTechniqueActions( true ); mActionToggleEditing->setEnabled( false ); mActionToggleEditing->setChecked( true ); // always editable mActionUndo->setEnabled( false ); @@ -17452,42 +17113,6 @@ void QgisApp::toolButtonActionTriggered( QAction *action ) settings.setEnumValue( QStringLiteral( "UI/defaultVertexTool" ), QgsVertexTool::AllLayers ); else if ( action == mActionVertexToolActiveLayer ) settings.setEnumValue( QStringLiteral( "UI/defaultVertexTool" ), QgsVertexTool::ActiveLayer ); - else if ( action == mActionCircularStringCurvePoint ) - settings.setValue( QStringLiteral( "UI/defaultCircularString" ), 0 ); - else if ( action == mActionCircularStringRadius ) - settings.setValue( QStringLiteral( "UI/defaultCircularString" ), 1 ); - else if ( action == mActionCircle2Points ) - settings.setValue( QStringLiteral( "UI/defaultCircle" ), 0 ); - else if ( action == mActionCircle3Points ) - settings.setValue( QStringLiteral( "UI/defaultCircle" ), 1 ); - else if ( action == mActionCircle3Tangents ) - settings.setValue( QStringLiteral( "UI/defaultCircle" ), 2 ); - else if ( action == mActionCircle2TangentsPoint ) - settings.setValue( QStringLiteral( "UI/defaultCircle" ), 3 ); - else if ( action == mActionCircleCenterPoint ) - settings.setValue( QStringLiteral( "UI/defaultCircle" ), 4 ); - else if ( action == mActionEllipseCenter2Points ) - settings.setValue( QStringLiteral( "UI/defaultEllipse" ), 0 ); - else if ( action == mActionEllipseCenterPoint ) - settings.setValue( QStringLiteral( "UI/defaultEllipse" ), 1 ); - else if ( action == mActionEllipseExtent ) - settings.setValue( QStringLiteral( "UI/defaultEllipse" ), 2 ); - else if ( action == mActionEllipseFoci ) - settings.setValue( QStringLiteral( "UI/defaultEllipse" ), 3 ); - else if ( action == mActionRectangleCenterPoint ) - settings.setValue( QStringLiteral( "UI/defaultRectangle" ), 0 ); - else if ( action == mActionRectangleExtent ) - settings.setValue( QStringLiteral( "UI/defaultRectangle" ), 1 ); - else if ( action == mActionRectangle3PointsDistance ) - settings.setValue( QStringLiteral( "UI/defaultRectangle" ), 2 ); - else if ( action == mActionRectangle3PointsProjected ) - settings.setValue( QStringLiteral( "UI/defaultRectangle" ), 3 ); - else if ( action == mActionRegularPolygon2Points ) - settings.setValue( QStringLiteral( "UI/defaultRegularPolygon" ), 0 ); - else if ( action == mActionRegularPolygonCenterPoint ) - settings.setValue( QStringLiteral( "UI/defaultRegularPolygon" ), 1 ); - else if ( action == mActionRegularPolygonCenterCorner ) - settings.setValue( QStringLiteral( "UI/defaultRegularPolygon" ), 2 ); bt->setDefaultAction( action ); } diff --git a/src/app/qgisapp.h b/src/app/qgisapp.h index 4bd6b5a24493..cc67b4a9d51a 100644 --- a/src/app/qgisapp.h +++ b/src/app/qgisapp.h @@ -71,6 +71,7 @@ class QgsMapLayerConfigWidgetFactory; class QgsMapOverviewCanvas; class QgsMapTip; class QgsMapTool; +class QgsMapToolsDigitizingTechniqueManager; class QgsOptions; class QgsPluginLayer; class QgsPluginLayer; @@ -557,24 +558,6 @@ class APP_EXPORT QgisApp : public QMainWindow, private Ui::MainWindow QAction *actionShowBookmarks() { return mActionShowBookmarks; } QAction *actionShowBookmarkManager() { return mActionShowBookmarkManager; } QAction *actionDraw() { return mActionDraw; } - QAction *actionCircle2Points() { return mActionCircle2Points ; } - QAction *actionCircle3Points() { return mActionCircle3Points ; } - QAction *actionCircle3Tangents() { return mActionCircle3Tangents ; } - QAction *actionCircle2TangentsPoint() { return mActionCircle2TangentsPoint ; } - QAction *actionCircleCenterPoint() { return mActionCircleCenterPoint ; } - QAction *actionEllipseCenter2Points() { return mActionEllipseCenter2Points ; } - QAction *actionEllipseCenterPoint() { return mActionEllipseCenterPoint ; } - QAction *actionEllipseExtent() { return mActionEllipseExtent ; } - QAction *actionEllipseFoci() { return mActionEllipseFoci ; } - QAction *actionRectangleCenterPoint() { return mActionRectangleCenterPoint ; } - QAction *actionRectangleExtent() { return mActionRectangleExtent ; } - QAction *actionRectangle3PointsDistance() { return mActionRectangle3PointsDistance ; } - QAction *actionRectangle3PointsProjected() { return mActionRectangle3PointsProjected ; } - QAction *actionRegularPolygon2Points() { return mActionRegularPolygon2Points ; } - QAction *actionRegularPolygonCenterPoint() { return mActionRegularPolygonCenterPoint ; } - QAction *actionRegularPolygonCenterCorner() { return mActionRegularPolygonCenterCorner ; } - - QAction *actionDataSourceManager() { return mActionDataSourceManager; } QAction *actionNewVectorLayer() { return mActionNewVectorLayer; } #ifdef HAVE_SPATIALITE @@ -2038,23 +2021,6 @@ class APP_EXPORT QgisApp : public QMainWindow, private Ui::MainWindow //! Enable or disable event tracing (for debugging) void toggleEventTracing(); - /** - * Enables or disables digitizing with curve for map tool that support this capabilities - * \since QGIS 3.16 - */ - void enableDigitizeWithCurve( bool enable ); - - /** - * Enables or disables stream digitizing - * \since QGIS 3.20 - */ - void enableStreamDigitizing( bool enable ); - - /** - * Enables the action that toggles digitizing with curve - */ - void enableDigitizeTechniqueActions( bool enable, QAction *triggeredFromToolAction = nullptr ); - #ifdef HAVE_GEOREFERENCER void showGeoreferencer(); #endif @@ -2515,6 +2481,7 @@ class APP_EXPORT QgisApp : public QMainWindow, private Ui::MainWindow QAction *mWindowAction = nullptr; #endif + QgsMapToolsDigitizingTechniqueManager *mDigitizingTechniqueManager = nullptr; std::unique_ptr< QgsAppMapTools > mMapTools; QgsMapTool *mNonEditMapTool = nullptr; @@ -2654,8 +2621,6 @@ class APP_EXPORT QgisApp : public QMainWindow, private Ui::MainWindow QgsDockWidget *mDevToolsDock = nullptr; QgsDevToolsPanelWidget *mDevToolsWidget = nullptr; - QToolButton *mDigitizeModeToolButton = nullptr; - //! Persistent tile scale slider QgsTileScaleWidget *mpTileScaleWidget = nullptr; @@ -2824,6 +2789,7 @@ class APP_EXPORT QgisApp : public QMainWindow, private Ui::MainWindow }; int mFreezeCount = 0; friend class QgsCanvasRefreshBlocker; + friend class QgsMapToolsDigitizingTechniqueManager; friend class TestQgisAppPython; friend class TestQgisApp; diff --git a/src/app/qgisappinterface.cpp b/src/app/qgisappinterface.cpp index 440735f1ddc4..d192d6f1c374 100644 --- a/src/app/qgisappinterface.cpp +++ b/src/app/qgisappinterface.cpp @@ -721,22 +721,6 @@ QAction *QgisAppInterface::actionMapTips() { return qgis->actionMapTips(); } QAction *QgisAppInterface::actionNewBookmark() { return qgis->actionNewBookmark(); } QAction *QgisAppInterface::actionShowBookmarks() { return qgis->actionShowBookmarks(); } QAction *QgisAppInterface::actionDraw() { return qgis->actionDraw(); } -QAction *QgisAppInterface::actionCircle2Points() { return qgis->actionCircle2Points();} -QAction *QgisAppInterface::actionCircle3Points() { return qgis->actionCircle3Points();} -QAction *QgisAppInterface::actionCircle3Tangents() { return qgis->actionCircle3Tangents();} -QAction *QgisAppInterface::actionCircle2TangentsPoint() { return qgis->actionCircle2TangentsPoint();} -QAction *QgisAppInterface::actionCircleCenterPoint() { return qgis->actionCircleCenterPoint();} -QAction *QgisAppInterface::actionEllipseCenter2Points() { return qgis->actionEllipseCenter2Points();} -QAction *QgisAppInterface::actionEllipseCenterPoint() { return qgis->actionEllipseCenterPoint();} -QAction *QgisAppInterface::actionEllipseExtent() { return qgis->actionEllipseExtent();} -QAction *QgisAppInterface::actionEllipseFoci() { return qgis->actionEllipseFoci();} -QAction *QgisAppInterface::actionRectangleCenterPoint() { return qgis->actionRectangleCenterPoint();} -QAction *QgisAppInterface::actionRectangleExtent() { return qgis->actionRectangleExtent();} -QAction *QgisAppInterface::actionRectangle3PointsDistance() { return qgis->actionRectangle3PointsDistance();} -QAction *QgisAppInterface::actionRectangle3PointsProjected() { return qgis->actionRectangle3PointsProjected();} -QAction *QgisAppInterface::actionRegularPolygon2Points() { return qgis->actionRegularPolygon2Points();} -QAction *QgisAppInterface::actionRegularPolygonCenterPoint() { return qgis->actionRegularPolygonCenterPoint();} -QAction *QgisAppInterface::actionRegularPolygonCenterCorner() { return qgis->actionRegularPolygonCenterCorner();} //! Layer menu actions QAction *QgisAppInterface::actionNewVectorLayer() { return qgis->actionNewVectorLayer(); } QAction *QgisAppInterface::actionAddOgrLayer() { return qgis->actionAddOgrLayer(); } diff --git a/src/app/qgisappinterface.h b/src/app/qgisappinterface.h index 192f816b9f17..85fcc4f96e70 100644 --- a/src/app/qgisappinterface.h +++ b/src/app/qgisappinterface.h @@ -290,22 +290,6 @@ class APP_EXPORT QgisAppInterface : public QgisInterface QAction *actionQgisHomePage() override; QAction *actionCheckQgisVersion() override; QAction *actionAbout() override; - QAction *actionCircle2Points() override; - QAction *actionCircle3Points() override; - QAction *actionCircle3Tangents() override; - QAction *actionCircle2TangentsPoint() override; - QAction *actionCircleCenterPoint() override; - QAction *actionEllipseCenter2Points() override; - QAction *actionEllipseCenterPoint() override; - QAction *actionEllipseExtent() override; - QAction *actionEllipseFoci() override; - QAction *actionRectangleCenterPoint() override; - QAction *actionRectangleExtent() override; - QAction *actionRectangle3PointsDistance() override; - QAction *actionRectangle3PointsProjected() override; - QAction *actionRegularPolygon2Points() override; - QAction *actionRegularPolygonCenterPoint() override; - QAction *actionRegularPolygonCenterCorner() override; bool openFeatureForm( QgsVectorLayer *l, QgsFeature &f, bool updateFeatureOnly = false, bool showModal = true ) override; QgsAttributeDialog *getFeatureForm( QgsVectorLayer *layer, QgsFeature &feature ) override; diff --git a/src/app/qgsmaptooladdabstract.cpp b/src/app/qgsmaptooladdabstract.cpp deleted file mode 100644 index 99710af2fc23..000000000000 --- a/src/app/qgsmaptooladdabstract.cpp +++ /dev/null @@ -1,119 +0,0 @@ -/*************************************************************************** - qgsmaptooladdabstract.cpp - abstract class for map tools of the 'add' kind - --------------------- - begin : July 2017 - copyright : (C) 2017 - email : lbartoletti at tuxfamily dot org - *************************************************************************** - * * - * 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 "qgsmaptooladdabstract.h" -#include "qgsgeometryrubberband.h" -#include "qgsgeometryutils.h" -#include "qgsmapcanvas.h" -#include "qgspoint.h" -#include "qgisapp.h" -#include "qgssnapindicator.h" - -QgsMapToolAddAbstract::QgsMapToolAddAbstract( QgsMapToolCapture *parentTool, QgsMapCanvas *canvas, CaptureMode mode ) - : QgsMapToolCapture( canvas, QgisApp::instance()->cadDockWidget(), mode ) - , mParentTool( parentTool ) - , mSnapIndicator( std::make_unique< QgsSnapIndicator>( canvas ) ) -{ - QgsMapToolAddAbstract::clean(); - - connect( QgisApp::instance(), &QgisApp::newProject, this, &QgsMapToolAddAbstract::stopCapturing ); - connect( QgisApp::instance(), &QgisApp::projectRead, this, &QgsMapToolAddAbstract::stopCapturing ); -} - -QgsMapToolAddAbstract::~QgsMapToolAddAbstract() -{ - QgsMapToolAddAbstract::clean(); -} - -void QgsMapToolAddAbstract::keyPressEvent( QKeyEvent *e ) -{ - if ( e && e->isAutoRepeat() ) - { - return; - } - - if ( e && e->key() == Qt::Key_Escape ) - { - clean(); - if ( mParentTool ) - mParentTool->keyPressEvent( e ); - } - - if ( e && e->key() == Qt::Key_Backspace ) - { - if ( mPoints.size() == 1 ) - { - - if ( mTempRubberBand ) - { - delete mTempRubberBand; - mTempRubberBand = nullptr; - } - - mPoints.clear(); - } - else if ( mPoints.size() > 1 ) - { - mPoints.removeLast(); - - } - if ( mParentTool ) - mParentTool->keyPressEvent( e ); - } -} - -void QgsMapToolAddAbstract::keyReleaseEvent( QKeyEvent *e ) -{ - if ( e && e->isAutoRepeat() ) - { - return; - } -} - -void QgsMapToolAddAbstract::activate() -{ - clean(); - QgsMapToolCapture::activate(); -} - -void QgsMapToolAddAbstract::clean() -{ - if ( mTempRubberBand ) - { - delete mTempRubberBand; - mTempRubberBand = nullptr; - } - - mPoints.clear(); - - if ( mParentTool ) - { - mParentTool->deleteTempRubberBand(); - } - - QgsVectorLayer *vLayer = static_cast( QgisApp::instance()->activeLayer() ); - if ( vLayer ) - mLayerType = vLayer->geometryType(); -} - -void QgsMapToolAddAbstract::release( QgsMapMouseEvent *e ) -{ - deactivate(); - if ( mParentTool ) - { - mParentTool->canvasReleaseEvent( e ); - } - activate(); -} diff --git a/src/app/qgsmaptooladdabstract.h b/src/app/qgsmaptooladdabstract.h deleted file mode 100644 index a23fffc890aa..000000000000 --- a/src/app/qgsmaptooladdabstract.h +++ /dev/null @@ -1,66 +0,0 @@ -/*************************************************************************** - qgsmaptooladdabstract.h - abstract class for map tools of the 'add' kind - --------------------- - begin : May 2017 - copyright : (C) 2017 - email : lbartoletti at tuxfamily dot org - *************************************************************************** - * * - * 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 QGSMAPTOOLADDABSTRACT_H -#define QGSMAPTOOLADDABSTRACT_H - -#include "qgsmaptoolcapture.h" -#include "qgsellipse.h" -#include "qgssettingsregistrycore.h" -#include "qgis_app.h" - -class QgsGeometryRubberBand; -class QgsSnapIndicator; - -class APP_EXPORT QgsMapToolAddAbstract: public QgsMapToolCapture -{ - Q_OBJECT - public: - QgsMapToolAddAbstract( QgsMapToolCapture *parentTool, QgsMapCanvas *canvas, CaptureMode mode = CaptureLine ); - ~QgsMapToolAddAbstract() override; - - void keyPressEvent( QKeyEvent *e ) override; - void keyReleaseEvent( QKeyEvent *e ) override; - - void deactivate() override = 0; - - void activate() override; - void clean() override; - - protected: - explicit QgsMapToolAddAbstract( QgsMapCanvas *canvas ) = delete; //forbidden - - //! Convenient method to release (activate/deactivate) tools - void release( QgsMapMouseEvent *e ); - - /** - * The parent map tool, e.g. the add feature tool. - * Completed geometry will be added to this tool by calling its toLineString() method. - */ - QPointer mParentTool; - //! Ellipse points (in map coordinates) - QgsPointSequence mPoints; - //! The rubberband to show the geometry currently working on - QgsGeometryRubberBand *mTempRubberBand = nullptr; - - //! Layer type which will be used for rubberband - QgsWkbTypes::GeometryType mLayerType = QgsWkbTypes::LineGeometry; - - //! Snapping indicators - std::unique_ptr mSnapIndicator; - -}; - -#endif // QGSMAPTOOLADDABSTRACT_H diff --git a/src/app/qgsmaptooladdfeature.cpp b/src/app/qgsmaptooladdfeature.cpp index 2fe8ffcf4b33..1ed98d47d4f1 100644 --- a/src/app/qgsmaptooladdfeature.cpp +++ b/src/app/qgsmaptooladdfeature.cpp @@ -61,10 +61,10 @@ bool QgsMapToolAddFeature::addFeature( QgsVectorLayer *vlayer, const QgsFeature return res; } -void QgsMapToolAddFeature::digitized( const QgsFeature &f ) +void QgsMapToolAddFeature::featureDigitized( const QgsFeature &feature ) { QgsVectorLayer *vlayer = currentVectorLayer(); - const bool res = addFeature( vlayer, f, false ); + const bool res = addFeature( vlayer, feature, false ); if ( res ) { @@ -86,7 +86,7 @@ void QgsMapToolAddFeature::digitized( const QgsFeature &f ) //can only add topological points if background layer is editable... if ( vl->geometryType() == QgsWkbTypes::PolygonGeometry && vl->isEditable() ) { - vl->addTopologicalPoints( f.geometry() ); + vl->addTopologicalPoints( feature.geometry() ); } } } @@ -98,10 +98,10 @@ void QgsMapToolAddFeature::digitized( const QgsFeature &f ) { if ( sm.at( i ).layer() ) { - sm.at( i ).layer()->addTopologicalPoints( f.geometry().vertexAt( i ) ); + sm.at( i ).layer()->addTopologicalPoints( feature.geometry().vertexAt( i ) ); } } - vlayer->addTopologicalPoints( f.geometry() ); + vlayer->addTopologicalPoints( feature.geometry() ); } } } diff --git a/src/app/qgsmaptooladdfeature.h b/src/app/qgsmaptooladdfeature.h index c9ffc4640532..7407805c2c38 100644 --- a/src/app/qgsmaptooladdfeature.h +++ b/src/app/qgsmaptooladdfeature.h @@ -24,12 +24,14 @@ class APP_EXPORT QgsMapToolAddFeature : public QgsMapToolDigitizeFeature //! \since QGIS 2.12 QgsMapToolAddFeature( QgsMapCanvas *canvas, CaptureMode mode ); + private slots: + + void featureDigitized( const QgsFeature &feature ) override; + private: bool addFeature( QgsVectorLayer *vlayer, const QgsFeature &f, bool showModal = true ); - void digitized( const QgsFeature &f ) override; - /** * Check if CaptureMode matches layer type. Default is TRUE. * \since QGIS 2.12 diff --git a/src/app/qgsmaptooladdpart.cpp b/src/app/qgsmaptooladdpart.cpp index d5092bf2aa3b..95e2b0f93996 100644 --- a/src/app/qgsmaptooladdpart.cpp +++ b/src/app/qgsmaptooladdpart.cpp @@ -28,7 +28,7 @@ QgsMapToolAddPart::QgsMapToolAddPart( QgsMapCanvas *canvas ) - : QgsMapToolCapture( canvas, QgisApp::instance()->cadDockWidget(), CaptureNone ) + : QgsMapToolCaptureLayerGeometry( canvas, QgisApp::instance()->cadDockWidget(), CaptureNone ) { mToolName = tr( "Add part" ); connect( QgisApp::instance(), &QgisApp::newProject, this, &QgsMapToolAddPart::stopCapturing ); @@ -44,11 +44,12 @@ bool QgsMapToolAddPart::supportsTechnique( QgsMapToolCapture::CaptureTechnique t { switch ( technique ) { - case QgsMapToolCapture::StraightSegments: - case QgsMapToolCapture::Streaming: + case QgsMapToolCapture::CaptureTechnique::StraightSegments: + case QgsMapToolCapture::CaptureTechnique::Streaming: return true; - case QgsMapToolCapture::CircularString: + case QgsMapToolCapture::CaptureTechnique::CircularString: + case QgsMapToolCapture::CaptureTechnique::Shape: return mode() != QgsMapToolCapture::CapturePoint; } return false; @@ -56,7 +57,7 @@ bool QgsMapToolAddPart::supportsTechnique( QgsMapToolCapture::CaptureTechnique t void QgsMapToolAddPart::canvasReleaseEvent( QgsMapMouseEvent *e ) { - if ( checkSelection() ) + if ( getLayerAndCheckSelection() ) { QgsMapToolAdvancedDigitizing::canvasReleaseEvent( e ); } @@ -68,142 +69,45 @@ void QgsMapToolAddPart::canvasReleaseEvent( QgsMapMouseEvent *e ) void QgsMapToolAddPart::cadCanvasReleaseEvent( QgsMapMouseEvent *e ) { - //check if we operate on a vector layer - QgsVectorLayer *vlayer = currentVectorLayer(); - if ( !vlayer ) - { - notifyNotVectorLayer(); + QgsVectorLayer *layer = getLayerAndCheckSelection(); + if ( !layer ) return; - } - if ( !vlayer->isEditable() ) - { - notifyNotEditableLayer(); - return; - } + QgsMapToolCapture::cadCanvasReleaseEvent( e ); +} - if ( !checkSelection() ) - { - stopCapturing(); +void QgsMapToolAddPart::layerPointCaptured( const QgsPoint &point ) +{ + QgsVectorLayer *layer = getLayerAndCheckSelection(); + if ( !layer ) return; - } - - Qgis::GeometryOperationResult errorCode = Qgis::GeometryOperationResult::Success; - switch ( mode() ) - { - case CapturePoint: - { - QgsPoint layerPoint; - const QgsPointXY mapPoint = e->mapPoint(); - - if ( nextPoint( QgsPoint( mapPoint ), layerPoint ) != 0 ) - { - QgsDebugMsg( QStringLiteral( "nextPoint failed" ) ); - return; - } - - vlayer->beginEditCommand( tr( "Part added" ) ); - errorCode = vlayer->addPart( QgsPointSequence() << layerPoint ); - } - break; - - case CaptureLine: - case CapturePolygon: - { - //add point to list and to rubber band - if ( e->button() == Qt::LeftButton ) - { - const int error = addVertex( e->mapPoint(), e->mapPointMatch() ); - if ( error == 2 ) - { - //problem with coordinate transformation - emit messageEmitted( tr( "Coordinate transform error. Cannot transform the point to the layers coordinate system" ), Qgis::MessageLevel::Warning ); - return; - } - - startCapturing(); - return; - } - else if ( e->button() != Qt::RightButton ) - { - deleteTempRubberBand(); - - return; - } - - if ( !isCapturing() ) - return; - - if ( mode() == CapturePolygon ) - { - closePolygon(); - } - - //does compoundcurve contain circular strings? - //does provider support circular strings? - const bool hasCurvedSegments = captureCurve()->hasCurvedSegments(); - const bool providerSupportsCurvedSegments = vlayer->dataProvider()->capabilities() & QgsVectorDataProvider::CircularGeometries; + layer->beginEditCommand( tr( "Part added" ) ); + Qgis::GeometryOperationResult errorCode = layer->addPart( QgsPointSequence() << point ); + finalizeEditCommand( layer, errorCode ); +} - QgsCurve *curveToAdd = nullptr; - if ( hasCurvedSegments && providerSupportsCurvedSegments ) - { - curveToAdd = captureCurve()->clone(); - } - else - { - curveToAdd = captureCurve()->curveToLine(); - } +void QgsMapToolAddPart::layerLineCaptured( const QgsCurve *line ) +{ + QgsVectorLayer *layer = getLayerAndCheckSelection(); + if ( !layer ) + return; + layer->beginEditCommand( tr( "Part added" ) ); + Qgis::GeometryOperationResult errorCode = layer->addPart( line->clone() ); + finalizeEditCommand( layer, errorCode ); +} - vlayer->beginEditCommand( tr( "Part added" ) ); - if ( mode() == CapturePolygon ) - { - //avoid intersections - QgsCurvePolygon *cp = new QgsCurvePolygon(); - cp->setExteriorRing( curveToAdd ); - QgsGeometry *geom = new QgsGeometry( cp ); - - QList avoidIntersectionsLayers; - switch ( QgsProject::instance()->avoidIntersectionsMode() ) - { - case QgsProject::AvoidIntersectionsMode::AvoidIntersectionsCurrentLayer: - avoidIntersectionsLayers.append( vlayer ); - break; - case QgsProject::AvoidIntersectionsMode::AvoidIntersectionsLayers: - avoidIntersectionsLayers = QgsProject::instance()->avoidIntersectionsLayers(); - break; - case QgsProject::AvoidIntersectionsMode::AllowIntersections: - break; - } - if ( !avoidIntersectionsLayers.isEmpty() ) - { - geom->avoidIntersections( avoidIntersectionsLayers ); - } - - const QgsCurvePolygon *cpGeom = qgsgeometry_cast( geom->constGet() ); - if ( !cpGeom ) - { - stopCapturing(); - delete geom; - vlayer->destroyEditCommand(); - return; - } - - errorCode = vlayer->addPart( cpGeom->exteriorRing()->clone() ); - delete geom; - } - else - { - errorCode = vlayer->addPart( curveToAdd ); - } - stopCapturing(); - } - break; - default: - Q_ASSERT( !"invalid capture mode" ); - errorCode = Qgis::GeometryOperationResult::AddPartSelectedGeometryNotFound; - break; - } +void QgsMapToolAddPart::layerPolygonCaptured( const QgsCurvePolygon *polygon ) +{ + QgsVectorLayer *layer = getLayerAndCheckSelection(); + if ( !layer ) + return; + layer->beginEditCommand( tr( "Part added" ) ); + Qgis::GeometryOperationResult errorCode = layer->addPart( polygon->exteriorRing()->clone() ); + finalizeEditCommand( layer, errorCode ); +} +void QgsMapToolAddPart::finalizeEditCommand( QgsVectorLayer *layer, Qgis::GeometryOperationResult errorCode ) +{ QString errorMessage; switch ( errorCode ) { @@ -219,9 +123,9 @@ void QgsMapToolAddPart::cadCanvasReleaseEvent( QgsMapMouseEvent *e ) addTopologicalPoints( pointsZM() ); } - vlayer->endEditCommand(); + layer->endEditCommand(); - vlayer->triggerRepaint(); + layer->triggerRepaint(); return; } @@ -264,27 +168,33 @@ void QgsMapToolAddPart::cadCanvasReleaseEvent( QgsMapMouseEvent *e ) } emit messageEmitted( errorMessage, Qgis::MessageLevel::Warning ); - vlayer->destroyEditCommand(); + layer->destroyEditCommand(); } void QgsMapToolAddPart::activate() { - checkSelection(); + getLayerAndCheckSelection(); QgsMapToolCapture::activate(); } -bool QgsMapToolAddPart::checkSelection() +QgsVectorLayer *QgsMapToolAddPart::getLayerAndCheckSelection() { //check if we operate on a vector layer - QgsVectorLayer *vlayer = currentVectorLayer(); - if ( !vlayer ) + QgsVectorLayer *layer = currentVectorLayer(); + if ( !layer ) { notifyNotVectorLayer(); - return false; + return nullptr; + } + + if ( !layer->isEditable() ) + { + notifyNotEditableLayer(); + return nullptr; } //inform user at the begin of the digitizing action that the island tool only works if exactly one feature is selected - const int nSelectedFeatures = vlayer->selectedFeatureCount(); + const int nSelectedFeatures = layer->selectedFeatureCount(); QString selectionErrorMsg; if ( nSelectedFeatures < 1 ) { @@ -298,10 +208,10 @@ bool QgsMapToolAddPart::checkSelection() { // Only one selected feature // For single-type layers only allow features without geometry - QgsFeatureIterator selectedFeatures = vlayer->getSelectedFeatures(); + QgsFeatureIterator selectedFeatures = layer->getSelectedFeatures(); QgsFeature selectedFeature; selectedFeatures.nextFeature( selectedFeature ); - if ( QgsWkbTypes::isSingleType( vlayer->wkbType() ) && + if ( QgsWkbTypes::isSingleType( layer->wkbType() ) && selectedFeature.geometry().constGet() ) { selectionErrorMsg = tr( "This layer does not support multipart geometries." ); @@ -313,5 +223,9 @@ bool QgsMapToolAddPart::checkSelection() emit messageEmitted( tr( "Could not add part. %1" ).arg( selectionErrorMsg ), Qgis::MessageLevel::Warning ); } - return selectionErrorMsg.isEmpty(); + if ( selectionErrorMsg.isEmpty() ) + return layer; + else + return nullptr; } + diff --git a/src/app/qgsmaptooladdpart.h b/src/app/qgsmaptooladdpart.h index 62122d365502..ecc78dbf4427 100644 --- a/src/app/qgsmaptooladdpart.h +++ b/src/app/qgsmaptooladdpart.h @@ -13,11 +13,13 @@ * * ***************************************************************************/ -#include "qgsmaptoolcapture.h" +#include "qgsmaptoolcapturelayergeometry.h" #include "qgis_app.h" +class QgsCurvePolygon; + //! A map tool that adds new parts to multipart features -class APP_EXPORT QgsMapToolAddPart : public QgsMapToolCapture +class APP_EXPORT QgsMapToolAddPart : public QgsMapToolCaptureLayerGeometry { Q_OBJECT public: @@ -32,6 +34,16 @@ class APP_EXPORT QgsMapToolAddPart : public QgsMapToolCapture void activate() override; private: - //! Check if there is any feature selected and the layer supports adding the part - bool checkSelection(); + + /** + * Check if there is any feature selected and the layer supports adding the part + * Returns a nullptr otherwise + */ + QgsVectorLayer *getLayerAndCheckSelection(); + + void layerPointCaptured( const QgsPoint &point ) override; + void layerLineCaptured( const QgsCurve *line ) override; + void layerPolygonCaptured( const QgsCurvePolygon *polygon ) override; + + void finalizeEditCommand( QgsVectorLayer *layer, Qgis::GeometryOperationResult errorCode ); }; diff --git a/src/app/qgsmaptooladdring.cpp b/src/app/qgsmaptooladdring.cpp index c3b8e3237a1e..96f97ae2731a 100644 --- a/src/app/qgsmaptooladdring.cpp +++ b/src/app/qgsmaptooladdring.cpp @@ -19,7 +19,7 @@ #include "qgslinestring.h" #include "qgsmapcanvas.h" #include "qgsproject.h" -#include "qgsvectordataprovider.h" +#include "qgscurvepolygon.h" #include "qgsvectorlayer.h" #include "qgisapp.h" #include "qgsmapmouseevent.h" @@ -33,13 +33,19 @@ QgsMapToolAddRing::QgsMapToolAddRing( QgsMapCanvas *canvas ) connect( QgisApp::instance(), &QgisApp::projectRead, this, &QgsMapToolAddRing::stopCapturing ); } +QgsMapToolCapture::Capabilities QgsMapToolAddRing::capabilities() const +{ + return QgsMapToolCapture::SupportsCurves | QgsMapToolCapture::ValidateGeometries; +} + bool QgsMapToolAddRing::supportsTechnique( QgsMapToolCapture::CaptureTechnique technique ) const { switch ( technique ) { - case QgsMapToolCapture::StraightSegments: - case QgsMapToolCapture::Streaming: - case QgsMapToolCapture::CircularString: + case QgsMapToolCapture::CaptureTechnique::StraightSegments: + case QgsMapToolCapture::CaptureTechnique::Streaming: + case QgsMapToolCapture::CaptureTechnique::CircularString: + case QgsMapToolCapture::CaptureTechnique::Shape: return true; } return false; @@ -47,107 +53,81 @@ bool QgsMapToolAddRing::supportsTechnique( QgsMapToolCapture::CaptureTechnique t void QgsMapToolAddRing::cadCanvasReleaseEvent( QgsMapMouseEvent *e ) { - emit messageDiscarded(); - //check if we operate on a vector layer - QgsVectorLayer *vlayer = currentVectorLayer(); + getCheckLayer(); + + QgsMapToolCapture::cadCanvasReleaseEvent( e ); +} + +void QgsMapToolAddRing::polygonCaptured( const QgsCurvePolygon *polygon ) +{ + QgsVectorLayer *vlayer = getCheckLayer(); if ( !vlayer ) - { - notifyNotVectorLayer(); return; + + vlayer->beginEditCommand( tr( "Ring added" ) ); + const Qgis::GeometryOperationResult addRingReturnCode = vlayer->addRing( polygon->exteriorRing()->clone() ); + QString errorMessage; + switch ( addRingReturnCode ) + { + case Qgis::GeometryOperationResult::Success: + break; + case Qgis::GeometryOperationResult::InvalidInputGeometryType: + errorMessage = tr( "a problem with geometry type occurred" ); + break; + case Qgis::GeometryOperationResult::AddRingNotClosed: + errorMessage = tr( "the inserted ring is not closed" ); + break; + case Qgis::GeometryOperationResult::AddRingNotValid: + errorMessage = tr( "the inserted ring is not a valid geometry" ); + break; + case Qgis::GeometryOperationResult::AddRingCrossesExistingRings: + errorMessage = tr( "the inserted ring crosses existing rings" ); + break; + case Qgis::GeometryOperationResult::AddRingNotInExistingFeature: + errorMessage = tr( "the inserted ring is not contained in a feature" ); + break; + case Qgis::GeometryOperationResult::SplitCannotSplitPoint: + case Qgis::GeometryOperationResult::InvalidBaseGeometry: + case Qgis::GeometryOperationResult::NothingHappened: + case Qgis::GeometryOperationResult::SelectionIsEmpty: + case Qgis::GeometryOperationResult::SelectionIsGreaterThanOne: + case Qgis::GeometryOperationResult::GeometryEngineError: + case Qgis::GeometryOperationResult::LayerNotEditable: + case Qgis::GeometryOperationResult::AddPartSelectedGeometryNotFound: + case Qgis::GeometryOperationResult::AddPartNotMultiGeometry: + errorMessage = tr( "an unknown error occurred (%1)" ).arg( qgsEnumValueToKey( addRingReturnCode ) ); + break; } - if ( !vlayer->isEditable() ) + if ( addRingReturnCode != Qgis::GeometryOperationResult::Success ) { - notifyNotEditableLayer(); - return; + emit messageEmitted( tr( "Could not add ring: %1." ).arg( errorMessage ), Qgis::MessageLevel::Critical ); + vlayer->destroyEditCommand(); } + else + { + vlayer->endEditCommand(); + } +} - //add point to list and to rubber band - if ( e->button() == Qt::LeftButton ) +QgsVectorLayer *QgsMapToolAddRing::getCheckLayer() +{ + //check if we operate on a vector layer + QgsVectorLayer *layer = currentVectorLayer(); + if ( !layer ) { - const int error = addVertex( e->mapPoint(), e->mapPointMatch() ); - if ( error == 2 ) - { - //problem with coordinate transformation - emit messageEmitted( tr( "Cannot transform the point to the layers coordinate system." ), Qgis::MessageLevel::Warning ); - return; - } - - startCapturing(); + notifyNotVectorLayer(); + return nullptr; } - else if ( e->button() == Qt::RightButton ) + + if ( !layer->isEditable() ) { - if ( !isCapturing() ) - return; - - deleteTempRubberBand(); - - closePolygon(); - - vlayer->beginEditCommand( tr( "Ring added" ) ); - - //does compoundcurve contain circular strings? - //does provider support circular strings? - const bool hasCurvedSegments = captureCurve()->hasCurvedSegments(); - const bool providerSupportsCurvedSegments = vlayer->dataProvider()->capabilities() & QgsVectorDataProvider::CircularGeometries; - - QgsCurve *curveToAdd = nullptr; - if ( hasCurvedSegments && providerSupportsCurvedSegments ) - { - curveToAdd = captureCurve()->clone(); - } - else - { - curveToAdd = captureCurve()->curveToLine(); - } - - const Qgis::GeometryOperationResult addRingReturnCode = vlayer->addRing( curveToAdd ); - QString errorMessage; - switch ( addRingReturnCode ) - { - case Qgis::GeometryOperationResult::Success: - break; - case Qgis::GeometryOperationResult::InvalidInputGeometryType: - errorMessage = tr( "a problem with geometry type occurred" ); - break; - case Qgis::GeometryOperationResult::AddRingNotClosed: - errorMessage = tr( "the inserted ring is not closed" ); - break; - case Qgis::GeometryOperationResult::AddRingNotValid: - errorMessage = tr( "the inserted ring is not a valid geometry" ); - break; - case Qgis::GeometryOperationResult::AddRingCrossesExistingRings: - errorMessage = tr( "the inserted ring crosses existing rings" ); - break; - case Qgis::GeometryOperationResult::AddRingNotInExistingFeature: - errorMessage = tr( "the inserted ring is not contained in a feature" ); - break; - case Qgis::GeometryOperationResult::SplitCannotSplitPoint: - case Qgis::GeometryOperationResult::InvalidBaseGeometry: - case Qgis::GeometryOperationResult::NothingHappened: - case Qgis::GeometryOperationResult::SelectionIsEmpty: - case Qgis::GeometryOperationResult::SelectionIsGreaterThanOne: - case Qgis::GeometryOperationResult::GeometryEngineError: - case Qgis::GeometryOperationResult::LayerNotEditable: - case Qgis::GeometryOperationResult::AddPartSelectedGeometryNotFound: - case Qgis::GeometryOperationResult::AddPartNotMultiGeometry: - errorMessage = tr( "an unknown error occurred (%1)" ).arg( qgsEnumValueToKey( addRingReturnCode ) ); - break; - } - - if ( addRingReturnCode != Qgis::GeometryOperationResult::Success ) - { - emit messageEmitted( tr( "Could not add ring: %1." ).arg( errorMessage ), Qgis::MessageLevel::Critical ); - vlayer->destroyEditCommand(); - } - else - { - vlayer->endEditCommand(); - } - - stopCapturing(); + notifyNotEditableLayer(); + return nullptr; } + + return layer; } diff --git a/src/app/qgsmaptooladdring.h b/src/app/qgsmaptooladdring.h index 7cff202a656a..f9d33ee2ce89 100644 --- a/src/app/qgsmaptooladdring.h +++ b/src/app/qgsmaptooladdring.h @@ -22,6 +22,12 @@ class APP_EXPORT QgsMapToolAddRing: public QgsMapToolCapture Q_OBJECT public: QgsMapToolAddRing( QgsMapCanvas *canvas ); + QgsMapToolCapture::Capabilities capabilities() const override; bool supportsTechnique( CaptureTechnique technique ) const override; void cadCanvasReleaseEvent( QgsMapMouseEvent *e ) override; + + // QgsMapToolCapture interface + private: + QgsVectorLayer *getCheckLayer(); + void polygonCaptured( const QgsCurvePolygon *polygon ) override; }; diff --git a/src/app/qgsmaptoolcircle2points.cpp b/src/app/qgsmaptoolcircle2points.cpp deleted file mode 100644 index 49ad6b75e672..000000000000 --- a/src/app/qgsmaptoolcircle2points.cpp +++ /dev/null @@ -1,75 +0,0 @@ -/*************************************************************************** - qgmaptoolcircle2points.cpp - map tool for adding circle - from 2 points - --------------------- - begin : July 2017 - copyright : (C) 2017 by Loïc Bartoletti - email : lbartoletti at tuxfamily dot org - *************************************************************************** - * * - * 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 "qgsmaptoolcircle2points.h" -#include "qgsgeometryrubberband.h" -#include "qgsmapcanvas.h" -#include "qgspoint.h" -#include "qgsmapmouseevent.h" -#include "qgssnapindicator.h" - - -QgsMapToolCircle2Points::QgsMapToolCircle2Points( QgsMapToolCapture *parentTool, - QgsMapCanvas *canvas, CaptureMode mode ) - : QgsMapToolAddCircle( parentTool, canvas, mode ) -{ - mToolName = tr( "Add circle from 2 points" ); -} - -void QgsMapToolCircle2Points::cadCanvasReleaseEvent( QgsMapMouseEvent *e ) -{ - const QgsPoint point = mapPoint( *e ); - - if ( !currentVectorLayer() ) - { - notifyNotVectorLayer(); - clean(); - stopCapturing(); - e->ignore(); - return; - } - - if ( e->button() == Qt::LeftButton ) - { - if ( mPoints.isEmpty() ) - mPoints.append( point ); - - if ( !mTempRubberBand ) - { - mTempRubberBand = createGeometryRubberBand( mLayerType, true ); - mTempRubberBand->show(); - } - } - else if ( e->button() == Qt::RightButton ) - { - mPoints.append( point ); - - release( e ); - } -} - -void QgsMapToolCircle2Points::cadCanvasMoveEvent( QgsMapMouseEvent *e ) -{ - const QgsPoint point = mapPoint( *e ); - - mSnapIndicator->setMatch( e->mapPointMatch() ); - - if ( mTempRubberBand ) - { - mCircle = QgsCircle::from2Points( mPoints.at( 0 ), point ); - mTempRubberBand->setGeometry( mCircle.toCircularString( true ) ); - } -} diff --git a/src/app/qgsmaptoolcircle2points.h b/src/app/qgsmaptoolcircle2points.h deleted file mode 100644 index cbbe99d0034e..000000000000 --- a/src/app/qgsmaptoolcircle2points.h +++ /dev/null @@ -1,34 +0,0 @@ -/*************************************************************************** - qgmaptoolcircle2points.h - map tool for adding circle - from 2 points - --------------------- - begin : July 2017 - copyright : (C) 2017 by Loïc Bartoletti - email : lbartoletti at tuxfamily dot org - *************************************************************************** - * * - * 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 QGSMAPTOOLCIRCLE2POINTS_H -#define QGSMAPTOOLCIRCLE2POINTS_H - -#include "qgsmaptooladdcircle.h" -#include "qgis_app.h" - -class APP_EXPORT QgsMapToolCircle2Points: public QgsMapToolAddCircle -{ - Q_OBJECT - - public: - QgsMapToolCircle2Points( QgsMapToolCapture *parentTool, QgsMapCanvas *canvas, CaptureMode mode = CaptureLine ); - - void cadCanvasReleaseEvent( QgsMapMouseEvent *e ) override; - void cadCanvasMoveEvent( QgsMapMouseEvent *e ) override; -}; - -#endif // QGSMAPTOOLCIRCLE2POINTS_H diff --git a/src/app/qgsmaptoolcircle3points.cpp b/src/app/qgsmaptoolcircle3points.cpp deleted file mode 100644 index 3ecdb667db7f..000000000000 --- a/src/app/qgsmaptoolcircle3points.cpp +++ /dev/null @@ -1,89 +0,0 @@ -/*************************************************************************** - qgmaptoolcircle3points.h - map tool for adding circle - from 3 points - --------------------- - begin : July 2017 - copyright : (C) 2017 by Loïc Bartoletti - email : lbartoletti at tuxfamily dot org - *************************************************************************** - * * - * 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 "qgsmaptoolcircle3points.h" -#include "qgsgeometryrubberband.h" -#include "qgslinestring.h" -#include "qgsmapcanvas.h" -#include "qgspoint.h" -#include "qgsmapmouseevent.h" -#include "qgssnapindicator.h" - -QgsMapToolCircle3Points::QgsMapToolCircle3Points( QgsMapToolCapture *parentTool, - QgsMapCanvas *canvas, CaptureMode mode ) - : QgsMapToolAddCircle( parentTool, canvas, mode ) -{ - mToolName = tr( "Add circle from 3 points" ); -} - -void QgsMapToolCircle3Points::cadCanvasReleaseEvent( QgsMapMouseEvent *e ) -{ - const QgsPoint point = mapPoint( *e ); - - if ( !currentVectorLayer() ) - { - notifyNotVectorLayer(); - clean(); - stopCapturing(); - e->ignore(); - return; - } - - if ( e->button() == Qt::LeftButton ) - { - if ( mPoints.size() < 2 ) - mPoints.append( point ); - if ( !mPoints.isEmpty() && !mTempRubberBand ) - { - mTempRubberBand = createGeometryRubberBand( mLayerType, true ); - mTempRubberBand->show(); - } - } - else if ( e->button() == Qt::RightButton ) - { - release( e ); - } -} - -void QgsMapToolCircle3Points::cadCanvasMoveEvent( QgsMapMouseEvent *e ) -{ - const QgsPoint point = mapPoint( *e ); - - mSnapIndicator->setMatch( e->mapPointMatch() ); - - if ( mTempRubberBand ) - { - switch ( mPoints.size() ) - { - case 1: - { - std::unique_ptr line( new QgsLineString() ); - line->addVertex( mPoints.at( 0 ) ); - line->addVertex( point ); - mTempRubberBand->setGeometry( line.release() ); - } - break; - case 2: - { - mCircle = QgsCircle::from3Points( mPoints.at( 0 ), mPoints.at( 1 ), point ); - mTempRubberBand->setGeometry( mCircle.toCircularString( true ) ); - } - break; - default: - break; - } - } -} diff --git a/src/app/qgsmaptoolcircle3points.h b/src/app/qgsmaptoolcircle3points.h deleted file mode 100644 index dbe680c069a1..000000000000 --- a/src/app/qgsmaptoolcircle3points.h +++ /dev/null @@ -1,34 +0,0 @@ -/*************************************************************************** - qgmaptoolcircle3points.h - map tool for adding circle - from 3 points - --------------------- - begin : July 2017 - copyright : (C) 2017 by Loïc Bartoletti - email : lbartoletti at tuxfamily dot org - *************************************************************************** - * * - * 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 3 of the License, or * - * (at your option) any later version. * - * * - ***************************************************************************/ - -#ifndef QGSMAPTOOLCIRCLE3POINTS_H -#define QGSMAPTOOLCIRCLE3POINTS_H - -#include "qgsmaptooladdcircle.h" -#include "qgis_app.h" - -class APP_EXPORT QgsMapToolCircle3Points: public QgsMapToolAddCircle -{ - Q_OBJECT - - public: - QgsMapToolCircle3Points( QgsMapToolCapture *parentTool, QgsMapCanvas *canvas, CaptureMode mode = CaptureLine ); - - void cadCanvasReleaseEvent( QgsMapMouseEvent *e ) override; - void cadCanvasMoveEvent( QgsMapMouseEvent *e ) override; -}; - -#endif // QGSMAPTOOLCIRCLE3POINTS_H diff --git a/src/app/qgsmaptoolcircle3tangents.h b/src/app/qgsmaptoolcircle3tangents.h deleted file mode 100644 index 58512b388228..000000000000 --- a/src/app/qgsmaptoolcircle3tangents.h +++ /dev/null @@ -1,38 +0,0 @@ -/*************************************************************************** - qgsmaptoolcircle3tangents.h - map tool for adding circle - from 3 tangents - --------------------- - begin : July 2017 - copyright : (C) 2017 by Loïc Bartoletti - email : lbartoletti at tuxfamily dot org - *************************************************************************** - * * - * 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 3 of the License, or * - * (at your option) any later version. * - * * - ***************************************************************************/ - -#ifndef QGSMAPTOOLCIRCLE3TANGENTS_H -#define QGSMAPTOOLCIRCLE3TANGENTS_H - -#include "qgspointlocator.h" -#include "qgsmaptooladdcircle.h" - -class QgsMapToolCircle3Tangents: public QgsMapToolAddCircle -{ - Q_OBJECT - - public: - QgsMapToolCircle3Tangents( QgsMapToolCapture *parentTool, QgsMapCanvas *canvas, CaptureMode mode = CaptureLine ); - - void cadCanvasReleaseEvent( QgsMapMouseEvent *e ) override; - void cadCanvasMoveEvent( QgsMapMouseEvent *e ) override; - void clean() override; - private: - //! Snapped points on the segments. Useful to determine which circle to choose in case of there are two parallels - QVector mPosPoints; -}; - -#endif // QGSMAPTOOLCIRCLE3TANGENTS_H diff --git a/src/app/qgsmaptoolcirclecenterpoint.cpp b/src/app/qgsmaptoolcirclecenterpoint.cpp deleted file mode 100644 index fb43f56a68ea..000000000000 --- a/src/app/qgsmaptoolcirclecenterpoint.cpp +++ /dev/null @@ -1,76 +0,0 @@ -/*************************************************************************** - qgmaptoolcirclecenterpoint.cpp - map tool for adding circle - from center and a point - --------------------- - begin : July 2017 - copyright : (C) 2017 by Loïc Bartoletti - email : lbartoletti at tuxfamily dot org - *************************************************************************** - * * - * 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 "qgsmaptoolcirclecenterpoint.h" -#include "qgsgeometryrubberband.h" -#include "qgsmapcanvas.h" -#include "qgspoint.h" -#include "qgsmapmouseevent.h" -#include "qgssnapindicator.h" - - -QgsMapToolCircleCenterPoint::QgsMapToolCircleCenterPoint( QgsMapToolCapture *parentTool, - QgsMapCanvas *canvas, CaptureMode mode ) - : QgsMapToolAddCircle( parentTool, canvas, mode ) -{ - mToolName = tr( "Add circle by a center point and another point" ); -} - -void QgsMapToolCircleCenterPoint::cadCanvasReleaseEvent( QgsMapMouseEvent *e ) -{ - const QgsPoint point = mapPoint( *e ); - - if ( !currentVectorLayer() ) - { - notifyNotVectorLayer(); - clean(); - stopCapturing(); - e->ignore(); - return; - } - - if ( e->button() == Qt::LeftButton ) - { - if ( mPoints.empty() ) - mPoints.append( point ); - - if ( !mTempRubberBand ) - { - mTempRubberBand = createGeometryRubberBand( mLayerType, true ); - mTempRubberBand->show(); - } - - } - else if ( e->button() == Qt::RightButton ) - { - mPoints.append( point ); - - release( e ); - } -} - -void QgsMapToolCircleCenterPoint::cadCanvasMoveEvent( QgsMapMouseEvent *e ) -{ - const QgsPoint point = mapPoint( *e ); - - mSnapIndicator->setMatch( e->mapPointMatch() ); - - if ( mTempRubberBand ) - { - mCircle = QgsCircle::fromCenterPoint( mPoints.at( 0 ), point ); - mTempRubberBand->setGeometry( mCircle.toCircularString( true ) ); - } -} diff --git a/src/app/qgsmaptoolcirclecenterpoint.h b/src/app/qgsmaptoolcirclecenterpoint.h deleted file mode 100644 index f60f0f36d622..000000000000 --- a/src/app/qgsmaptoolcirclecenterpoint.h +++ /dev/null @@ -1,34 +0,0 @@ -/*************************************************************************** - qgmaptoolcirclecenterpoint.h - map tool for adding circle - from center and a point - --------------------- - begin : July 2017 - copyright : (C) 2017 by Loïc Bartoletti - email : lbartoletti at tuxfamily dot org - *************************************************************************** - * * - * 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 QGSMAPTOOLCIRCLECENTERPOINT_H -#define QGSMAPTOOLCIRCLECENTERPOINT_H - -#include "qgsmaptooladdcircle.h" -#include "qgis_app.h" - -class APP_EXPORT QgsMapToolCircleCenterPoint: public QgsMapToolAddCircle -{ - Q_OBJECT - - public: - QgsMapToolCircleCenterPoint( QgsMapToolCapture *parentTool, QgsMapCanvas *canvas, CaptureMode mode = CaptureLine ); - - void cadCanvasReleaseEvent( QgsMapMouseEvent *e ) override; - void cadCanvasMoveEvent( QgsMapMouseEvent *e ) override; -}; - -#endif // QGSMAPTOOLCIRCLECENTERPOINT_H diff --git a/src/app/qgsmaptoolcircularstringcurvepoint.cpp b/src/app/qgsmaptoolcircularstringcurvepoint.cpp deleted file mode 100644 index 99b7bf08d6de..000000000000 --- a/src/app/qgsmaptoolcircularstringcurvepoint.cpp +++ /dev/null @@ -1,105 +0,0 @@ -/*************************************************************************** - qgsmaptoolcircularstringcurvepoint.cpp - --------------------- - begin : August 2015 - copyright : (C) 2015 by Marco Hugentobler - email : marco dot hugentobler at sourcepole dot ch - *************************************************************************** - * * - * 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 "qgsmaptoolcircularstringcurvepoint.h" -#include "qgscircularstring.h" -#include "qgscompoundcurve.h" -#include "qgsgeometryrubberband.h" -#include "qgsmapcanvas.h" -#include "qgspoint.h" -#include "qgsmapmouseevent.h" -#include "qgssnapindicator.h" - - -QgsMapToolCircularStringCurvePoint::QgsMapToolCircularStringCurvePoint( QgsMapToolCapture *parentTool, - QgsMapCanvas *canvas, CaptureMode mode ) - : QgsMapToolAddCircularString( parentTool, canvas, mode ) -{ - mToolName = tr( "Add circular string curve point" ); -} - -void QgsMapToolCircularStringCurvePoint::cadCanvasReleaseEvent( QgsMapMouseEvent *e ) -{ - const QgsPoint point = mapPoint( *e ); - - if ( !currentVectorLayer() ) - { - notifyNotVectorLayer(); - clean(); - stopCapturing(); - e->ignore(); - return; - } - - if ( e->button() == Qt::LeftButton ) - { - mPoints.append( point ); - if ( !mCenterPointRubberBand && mShowCenterPointRubberBand ) - { - createCenterPointRubberBand(); - } - - if ( !mPoints.isEmpty() ) - { - if ( !mTempRubberBand ) - { - mTempRubberBand = createGeometryRubberBand( mLayerType, true ); - mTempRubberBand->show(); - } - - QgsCircularString *c = new QgsCircularString(); - QgsPointSequence rubberBandPoints = mPoints.mid( mPoints.size() - 1 - ( mPoints.size() + 1 ) % 2 ); - rubberBandPoints.append( point ); - c->setPoints( rubberBandPoints ); - mTempRubberBand->setGeometry( c ); - } - if ( mPoints.size() > 1 && mPoints.size() % 2 ) - { - if ( !mRubberBand ) - { - mRubberBand = createGeometryRubberBand( mLayerType ); - mRubberBand->show(); - } - - QgsCircularString *c = new QgsCircularString(); - QgsPointSequence rubberBandPoints = mPoints; - rubberBandPoints.append( point ); - c->setPoints( rubberBandPoints ); - mRubberBand->setGeometry( c ); - removeCenterPointRubberBand(); - } - } - else if ( e->button() == Qt::RightButton ) - { - release( e ); - } -} - -void QgsMapToolCircularStringCurvePoint::cadCanvasMoveEvent( QgsMapMouseEvent *e ) -{ - const QgsPoint mapPoint( e->mapPoint() ); - - mSnapIndicator->setMatch( e->mapPointMatch() ); - - if ( mTempRubberBand ) - { - QgsPointSequence mTempPoints = mPoints.mid( mPoints.size() - 1 - ( mPoints.size() + 1 ) % 2 ); - mTempPoints.append( mapPoint ); - std::unique_ptr geom( new QgsCircularString() ); - geom->setPoints( mTempPoints ); - mTempRubberBand->setGeometry( geom.release() ); - - updateCenterPointRubberBand( mapPoint ); - } -} diff --git a/src/app/qgsmaptoolcircularstringcurvepoint.h b/src/app/qgsmaptoolcircularstringcurvepoint.h deleted file mode 100644 index 125af7a7fcda..000000000000 --- a/src/app/qgsmaptoolcircularstringcurvepoint.h +++ /dev/null @@ -1,34 +0,0 @@ -/*************************************************************************** - qgsmaptoolcircularstringcurvepoint.h - map tool for adding circular - strings by start / curve / endpoint - --------------------- - begin : Feb 2015 - copyright : (C) 2015 by Marco Hugentobler - email : marco dot hugentobler at sourcepole dot ch - *************************************************************************** - * * - * 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 QGSMAPTOOLCIRCULARSTRINGCURVEPOINT_H -#define QGSMAPTOOLCIRCULARSTRINGCURVEPOINT_H - -#include "qgsmaptooladdcircularstring.h" -#include "qgis_app.h" - -class APP_EXPORT QgsMapToolCircularStringCurvePoint: public QgsMapToolAddCircularString -{ - Q_OBJECT - - public: - QgsMapToolCircularStringCurvePoint( QgsMapToolCapture *parentTool, QgsMapCanvas *canvas, CaptureMode mode = CaptureLine ); - - void cadCanvasReleaseEvent( QgsMapMouseEvent *e ) override; - void cadCanvasMoveEvent( QgsMapMouseEvent *e ) override; -}; - -#endif // QGSMAPTOOLCIRCULARSTRINGCURVEPOINT_H diff --git a/src/app/qgsmaptoolellipsecenter2points.h b/src/app/qgsmaptoolellipsecenter2points.h deleted file mode 100644 index ec9168424b79..000000000000 --- a/src/app/qgsmaptoolellipsecenter2points.h +++ /dev/null @@ -1,34 +0,0 @@ -/*************************************************************************** - qgsmaptoolellipsecenter2points.h - map tool for adding ellipse - from center and 2 points - --------------------- - begin : July 2017 - copyright : (C) 2017 by Loïc Bartoletti - email : lbartoletti at tuxfamily dot org - *************************************************************************** - * * - * 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 3 of the License, or * - * (at your option) any later version. * - * * - ***************************************************************************/ - -#ifndef QGSMAPTOOLELLIPSECENTER2POINTS_H -#define QGSMAPTOOLELLIPSECENTER2POINTS_H - -#include "qgsmaptooladdellipse.h" -#include "qgis_app.h" - -class APP_EXPORT QgsMapToolEllipseCenter2Points: public QgsMapToolAddEllipse -{ - Q_OBJECT - - public: - QgsMapToolEllipseCenter2Points( QgsMapToolCapture *parentTool, QgsMapCanvas *canvas, CaptureMode mode = CaptureLine ); - - void cadCanvasReleaseEvent( QgsMapMouseEvent *e ) override; - void cadCanvasMoveEvent( QgsMapMouseEvent *e ) override; -}; - -#endif // QGSMAPTOOLELLIPSECENTER2POINTS_H diff --git a/src/app/qgsmaptoolellipsecenterpoint.cpp b/src/app/qgsmaptoolellipsecenterpoint.cpp deleted file mode 100644 index cdb17d75b232..000000000000 --- a/src/app/qgsmaptoolellipsecenterpoint.cpp +++ /dev/null @@ -1,72 +0,0 @@ -/*************************************************************************** - qgmaptoolellipsecenterpoint.cpp - map tool for adding ellipse - from center and a point - --------------------- - begin : July 2017 - copyright : (C) 2017 by Loïc Bartoletti - email : lbartoletti at tuxfamily dot org - *************************************************************************** - * * - * 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 "qgsmaptoolellipsecenterpoint.h" -#include "qgsgeometryrubberband.h" -#include "qgsmapcanvas.h" -#include "qgspoint.h" -#include "qgsmapmouseevent.h" -#include "qgssnapindicator.h" - - -QgsMapToolEllipseCenterPoint::QgsMapToolEllipseCenterPoint( QgsMapToolCapture *parentTool, - QgsMapCanvas *canvas, CaptureMode mode ) - : QgsMapToolAddEllipse( parentTool, canvas, mode ) -{ -} - -void QgsMapToolEllipseCenterPoint::cadCanvasReleaseEvent( QgsMapMouseEvent *e ) -{ - const QgsPoint point = mapPoint( *e ); - - if ( !currentVectorLayer() ) - { - notifyNotVectorLayer(); - clean(); - stopCapturing(); - e->ignore(); - return; - } - - if ( e->button() == Qt::LeftButton ) - { - if ( mPoints.empty() ) - mPoints.append( point ); - - if ( !mTempRubberBand ) - { - mTempRubberBand = createGeometryRubberBand( mLayerType, true ); - mTempRubberBand->show(); - } - } - else if ( e->button() == Qt::RightButton ) - { - release( e ); - } -} - -void QgsMapToolEllipseCenterPoint::cadCanvasMoveEvent( QgsMapMouseEvent *e ) -{ - const QgsPoint point = mapPoint( *e ); - - mSnapIndicator->setMatch( e->mapPointMatch() ); - - if ( mTempRubberBand ) - { - mEllipse = QgsEllipse::fromCenterPoint( mPoints.at( 0 ), point ); - mTempRubberBand->setGeometry( mEllipse.toPolygon( segments() ) ); - } -} diff --git a/src/app/qgsmaptoolellipsecenterpoint.h b/src/app/qgsmaptoolellipsecenterpoint.h deleted file mode 100644 index 17ccc17afd22..000000000000 --- a/src/app/qgsmaptoolellipsecenterpoint.h +++ /dev/null @@ -1,34 +0,0 @@ -/*************************************************************************** - qgmaptoolellipsecenterpoint.h - map tool for adding ellipse - from center and a point - --------------------- - begin : July 2017 - copyright : (C) 2017 by Loïc Bartoletti - email : lbartoletti at tuxfamily dot org - *************************************************************************** - * * - * 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 QGSMAPTOOLELLIPSECENTERPOINT_H -#define QGSMAPTOOLELLIPSECENTERPOINT_H - -#include "qgsmaptooladdellipse.h" -#include "qgis_app.h" - -class APP_EXPORT QgsMapToolEllipseCenterPoint: public QgsMapToolAddEllipse -{ - Q_OBJECT - - public: - QgsMapToolEllipseCenterPoint( QgsMapToolCapture *parentTool, QgsMapCanvas *canvas, CaptureMode mode = CaptureLine ); - - void cadCanvasReleaseEvent( QgsMapMouseEvent *e ) override; - void cadCanvasMoveEvent( QgsMapMouseEvent *e ) override; -}; - -#endif // QGSMAPTOOLELLIPSECENTERPOINT_H diff --git a/src/app/qgsmaptoolellipseextent.h b/src/app/qgsmaptoolellipseextent.h deleted file mode 100644 index df0a40779a3a..000000000000 --- a/src/app/qgsmaptoolellipseextent.h +++ /dev/null @@ -1,34 +0,0 @@ -/*************************************************************************** - qgmaptoolellipseextent.h - map tool for adding ellipse - from extent - --------------------- - begin : July 2017 - copyright : (C) 2017 by Loïc Bartoletti - email : lbartoletti at tuxfamily dot org - *************************************************************************** - * * - * 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 QGSMAPTOOLELLIPSEEXTENT_H -#define QGSMAPTOOLELLIPSEEXTENT_H - -#include "qgsmaptooladdellipse.h" -#include "qgis_app.h" - -class APP_EXPORT QgsMapToolEllipseExtent: public QgsMapToolAddEllipse -{ - Q_OBJECT - - public: - QgsMapToolEllipseExtent( QgsMapToolCapture *parentTool, QgsMapCanvas *canvas, CaptureMode mode = CaptureLine ); - - void cadCanvasReleaseEvent( QgsMapMouseEvent *e ) override; - void cadCanvasMoveEvent( QgsMapMouseEvent *e ) override; -}; - -#endif // QGSMAPTOOLELLIPSEEXTENT_H diff --git a/src/app/qgsmaptoolellipsefoci.h b/src/app/qgsmaptoolellipsefoci.h deleted file mode 100644 index 501081ec1af1..000000000000 --- a/src/app/qgsmaptoolellipsefoci.h +++ /dev/null @@ -1,34 +0,0 @@ -/*************************************************************************** - qgmaptoolellipsefoci.h - map tool for adding ellipse - from foci and a point - --------------------- - begin : July 2017 - copyright : (C) 2017 by Loïc Bartoletti - email : lbartoletti at tuxfamily dot org - *************************************************************************** - * * - * 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 3 of the License, or * - * (at your option) any later version. * - * * - ***************************************************************************/ - -#ifndef QGSMAPTOOLELLIPSEFOCI_H -#define QGSMAPTOOLELLIPSEFOCI_H - -#include "qgsmaptooladdellipse.h" -#include "qgis_app.h" - -class APP_EXPORT QgsMapToolEllipseFoci: public QgsMapToolAddEllipse -{ - Q_OBJECT - - public: - QgsMapToolEllipseFoci( QgsMapToolCapture *parentTool, QgsMapCanvas *canvas, CaptureMode mode = CaptureLine ); - - void cadCanvasReleaseEvent( QgsMapMouseEvent *e ) override; - void cadCanvasMoveEvent( QgsMapMouseEvent *e ) override; -}; - -#endif // QGSMAPTOOLELLIPSEFOCI_H diff --git a/src/app/qgsmaptoolfillring.cpp b/src/app/qgsmaptoolfillring.cpp index 51e62f8e6c3d..434367babaf0 100644 --- a/src/app/qgsmaptoolfillring.cpp +++ b/src/app/qgsmaptoolfillring.cpp @@ -37,9 +37,10 @@ bool QgsMapToolFillRing::supportsTechnique( QgsMapToolCapture::CaptureTechnique { switch ( technique ) { - case QgsMapToolCapture::StraightSegments: - case QgsMapToolCapture::Streaming: - case QgsMapToolCapture::CircularString: + case QgsMapToolCapture::CaptureTechnique::StraightSegments: + case QgsMapToolCapture::CaptureTechnique::Streaming: + case QgsMapToolCapture::CaptureTechnique::CircularString: + case QgsMapToolCapture::CaptureTechnique::Shape: return true; } return false; @@ -47,113 +48,78 @@ bool QgsMapToolFillRing::supportsTechnique( QgsMapToolCapture::CaptureTechnique void QgsMapToolFillRing::cadCanvasReleaseEvent( QgsMapMouseEvent *e ) { - //check if we operate on a vector layer - QgsVectorLayer *vlayer = qobject_cast( mCanvas->currentLayer() ); - + QgsVectorLayer *vlayer = getCheckLayer(); if ( !vlayer ) - { - notifyNotVectorLayer(); return; - } - if ( !vlayer->isEditable() ) - { - notifyNotEditableLayer(); - return; - } - - if ( e->button() == Qt::LeftButton && QApplication::keyboardModifiers() == Qt::ShiftModifier && !isCapturing() ) + if ( e->button() == Qt::LeftButton && QApplication::keyboardModifiers() == Qt::ShiftModifier ) { // left button with shift fills an existing ring + fillRingUnderPoint( e->mapPoint() ); } - else if ( e->button() == Qt::LeftButton ) + else { - // add point to list and to rubber band - - const int error = addVertex( e->mapPoint() ); - if ( error == 2 ) - { - // problem with coordinate transformation - emit messageEmitted( tr( "Cannot transform the point to the layers coordinate system" ), Qgis::MessageLevel::Warning ); - return; - } - - startCapturing(); - return; + QgsMapToolCapture::cadCanvasReleaseEvent( e ); } - else if ( e->button() != Qt::RightButton || !isCapturing() ) - { +} + +void QgsMapToolFillRing::polygonCaptured( const QgsCurvePolygon *polygon ) +{ + QgsVectorLayer *vlayer = getCheckLayer(); + if ( !vlayer ) return; - } - QgsGeometry g; QgsFeatureId fid; - if ( isCapturing() ) - { - deleteTempRubberBand(); - - closePolygon(); - - vlayer->beginEditCommand( tr( "Ring added and filled" ) ); + vlayer->beginEditCommand( tr( "Ring added and filled" ) ); - const QgsPointSequence pointList = pointsZM(); + const Qgis::GeometryOperationResult addRingReturnCode = vlayer->addRing( polygon->exteriorRing()->clone(), &fid ); - const Qgis::GeometryOperationResult addRingReturnCode = vlayer->addRing( pointList, &fid ); - - // AP: this is all dead code: - //todo: open message box to communicate errors - if ( addRingReturnCode != Qgis::GeometryOperationResult::Success ) + // AP: this is all dead code: + //todo: open message box to communicate errors + if ( addRingReturnCode != Qgis::GeometryOperationResult::Success ) + { + QString errorMessage; + if ( addRingReturnCode == Qgis::GeometryOperationResult::InvalidInputGeometryType ) { - QString errorMessage; - if ( addRingReturnCode == Qgis::GeometryOperationResult::InvalidInputGeometryType ) - { - errorMessage = tr( "a problem with geometry type occurred" ); - } - else if ( addRingReturnCode == Qgis::GeometryOperationResult::AddRingNotClosed ) - { - errorMessage = tr( "the inserted Ring is not closed" ); - } - else if ( addRingReturnCode == Qgis::GeometryOperationResult::AddRingNotValid ) - { - errorMessage = tr( "the inserted Ring is not a valid geometry" ); - } - else if ( addRingReturnCode == Qgis::GeometryOperationResult::AddRingCrossesExistingRings ) - { - errorMessage = tr( "the inserted Ring crosses existing rings" ); - } - else if ( addRingReturnCode == Qgis::GeometryOperationResult::AddRingNotInExistingFeature ) - { - errorMessage = tr( "the inserted Ring is not contained in a feature" ); - } - else - { - errorMessage = tr( "an unknown error occurred" ); - } - emit messageEmitted( tr( "could not add ring: %1." ).arg( errorMessage ), Qgis::MessageLevel::Critical ); - vlayer->destroyEditCommand(); - - return; + errorMessage = tr( "a problem with geometry type occurred" ); + } + else if ( addRingReturnCode == Qgis::GeometryOperationResult::AddRingNotClosed ) + { + errorMessage = tr( "the inserted Ring is not closed" ); + } + else if ( addRingReturnCode == Qgis::GeometryOperationResult::AddRingNotValid ) + { + errorMessage = tr( "the inserted Ring is not a valid geometry" ); + } + else if ( addRingReturnCode == Qgis::GeometryOperationResult::AddRingCrossesExistingRings ) + { + errorMessage = tr( "the inserted Ring crosses existing rings" ); } + else if ( addRingReturnCode == Qgis::GeometryOperationResult::AddRingNotInExistingFeature ) + { + errorMessage = tr( "the inserted Ring is not contained in a feature" ); + } + else + { + errorMessage = tr( "an unknown error occurred" ); + } + emit messageEmitted( tr( "could not add ring: %1." ).arg( errorMessage ), Qgis::MessageLevel::Critical ); + vlayer->destroyEditCommand(); - const QgsLineString ext( pointList ); - std::unique_ptr< QgsPolygon > polygon = std::make_unique< QgsPolygon >( ); - polygon->setExteriorRing( ext.clone() ); - g = QgsGeometry( std::move( polygon ) ); + return; } - else - { - vlayer->beginEditCommand( tr( "Ring filled" ) ); - g = ringUnderPoint( e->mapPoint(), fid ); + createFeature( QgsGeometry( polygon->clone() ), fid ); +} - if ( fid == -1 ) - { - emit messageEmitted( tr( "No ring found to fill." ), Qgis::MessageLevel::Critical ); - vlayer->destroyEditCommand(); - return; - } - } + +void QgsMapToolFillRing::createFeature( const QgsGeometry &geometry, QgsFeatureId fid ) +{ + + QgsVectorLayer *vlayer = getCheckLayer(); + if ( !vlayer ) + return; QgsExpressionContext context = vlayer->createExpressionContext(); @@ -163,7 +129,7 @@ void QgsMapToolFillRing::cadCanvasReleaseEvent( QgsMapMouseEvent *e ) if ( fit.nextFeature( f ) ) { //create QgsFeature with wkb representation - QgsFeature ft = QgsVectorLayerUtils::createFeature( vlayer, g, f.attributes().toMap(), &context ); + QgsFeature ft = QgsVectorLayerUtils::createFeature( vlayer, geometry, f.attributes().toMap(), &context ); bool res = false; if ( QApplication::keyboardModifiers() == Qt::ControlModifier ) @@ -190,16 +156,16 @@ void QgsMapToolFillRing::cadCanvasReleaseEvent( QgsMapMouseEvent *e ) vlayer->destroyEditCommand(); } } - - if ( isCapturing() ) - stopCapturing(); } // TODO refactor - shamelessly copied from QgsMapToolDeleteRing::ringUnderPoint -QgsGeometry QgsMapToolFillRing::ringUnderPoint( const QgsPointXY &p, QgsFeatureId &fid ) +void QgsMapToolFillRing::fillRingUnderPoint( const QgsPointXY &p ) { - //check if we operate on a vector layer - QgsVectorLayer *vlayer = qobject_cast( mCanvas->currentLayer() ); + QgsFeatureId fid; + + QgsVectorLayer *vlayer = getCheckLayer(); + if ( !vlayer ) + return; //There is no clean way to find if we are inside the ring of a feature, //so we iterate over all the features visible in the canvas @@ -246,5 +212,33 @@ QgsGeometry QgsMapToolFillRing::ringUnderPoint( const QgsPointXY &p, QgsFeatureI } } } - return ringGeom; + + if ( fid == -1 ) + { + emit messageEmitted( tr( "No ring found to fill." ), Qgis::MessageLevel::Critical ); + vlayer->destroyEditCommand(); + return; + } + + vlayer->beginEditCommand( tr( "Ring filled" ) ); + createFeature( ringGeom, fid ); +} + +QgsVectorLayer *QgsMapToolFillRing::getCheckLayer() +{ + //check if we operate on a vector layer + QgsVectorLayer *layer = currentVectorLayer(); + if ( !layer ) + { + notifyNotVectorLayer(); + return nullptr; + } + + if ( !layer->isEditable() ) + { + notifyNotEditableLayer(); + return nullptr; + } + + return layer; } diff --git a/src/app/qgsmaptoolfillring.h b/src/app/qgsmaptoolfillring.h index f914a8e3939e..a513c93c0b0a 100644 --- a/src/app/qgsmaptoolfillring.h +++ b/src/app/qgsmaptoolfillring.h @@ -30,10 +30,13 @@ class APP_EXPORT QgsMapToolFillRing: public QgsMapToolCapture void cadCanvasReleaseEvent( QgsMapMouseEvent *e ) override; private: + void polygonCaptured( const QgsCurvePolygon *polygon ) override; + void createFeature( const QgsGeometry &geometry, QgsFeatureId fid ); /** * Returns the geometry of the ring under the point p and sets fid to the feature id */ - QgsGeometry ringUnderPoint( const QgsPointXY &p, QgsFeatureId &fid ); + void fillRingUnderPoint( const QgsPointXY &p ); + QgsVectorLayer *getCheckLayer(); }; diff --git a/src/app/qgsmaptoolrectangle3points.cpp b/src/app/qgsmaptoolrectangle3points.cpp deleted file mode 100644 index 504730664caf..000000000000 --- a/src/app/qgsmaptoolrectangle3points.cpp +++ /dev/null @@ -1,124 +0,0 @@ -/*************************************************************************** - qgsmaptoolrectangle3points.cpp - map tool for adding rectangle - from 3 points - --------------------- - begin : September 2017 - copyright : (C) 2017 by Loïc Bartoletti - email : lbartoletti at tuxfamily dot org -*************************************************************************** -* * -* 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 3 of the License, or * -* (at your option) any later version. * -* * -***************************************************************************/ - -#include "qgsmaptoolrectangle3points.h" -#include "qgsgeometryrubberband.h" -#include "qgsgeometryutils.h" -#include "qgslinestring.h" -#include "qgsmapcanvas.h" -#include "qgspoint.h" -#include "qgsmapmouseevent.h" -#include -#include "qgssnapindicator.h" - -QgsMapToolRectangle3Points::QgsMapToolRectangle3Points( QgsMapToolCapture *parentTool, - QgsMapCanvas *canvas, CreateMode createMode, CaptureMode mode ) - : QgsMapToolAddRectangle( parentTool, canvas, mode ), - mCreateMode( createMode ) -{ - mToolName = tr( "Add rectangle from 3 points" ); -} - -void QgsMapToolRectangle3Points::cadCanvasReleaseEvent( QgsMapMouseEvent *e ) -{ - QgsPoint point = mapPoint( *e ); - - if ( !currentVectorLayer() ) - { - notifyNotVectorLayer(); - clean(); - stopCapturing(); - e->ignore(); - return; - } - - if ( e->button() == Qt::LeftButton ) - { - bool is3D = false; - QgsVectorLayer *currentLayer = qobject_cast( mCanvas->currentLayer() ); - if ( currentLayer ) - is3D = QgsWkbTypes::hasZ( currentLayer->wkbType() ); - - if ( is3D && !point.is3D() ) - point.addZValue( defaultZValue() ); - - if ( mPoints.size() < 2 ) - { - mPoints.append( point ); - } - - if ( !mPoints.isEmpty() && !mTempRubberBand ) - { - mTempRubberBand = createGeometryRubberBand( mLayerType, true ); - mTempRubberBand->show(); - } - if ( mPoints.size() == 3 ) - { - delete mTempRubberBand; - mTempRubberBand = createGeometryRubberBand( mLayerType, true ); // recreate rubberband for polygon - } - } - else if ( e->button() == Qt::RightButton ) - { - release( e ); - } -} - -void QgsMapToolRectangle3Points::cadCanvasMoveEvent( QgsMapMouseEvent *e ) -{ - QgsPoint point = mapPoint( *e ); - - mSnapIndicator->setMatch( e->mapPointMatch() ); - - if ( mTempRubberBand ) - { - switch ( mPoints.size() ) - { - case 1: - { - std::unique_ptr line( new QgsLineString() ); - line->addVertex( mPoints.at( 0 ) ); - line->addVertex( point ); - mTempRubberBand->setGeometry( line.release() ); - } - break; - case 2: - { - bool is3D = false; - QgsVectorLayer *currentLayer = qobject_cast( mCanvas->currentLayer() ); - if ( currentLayer ) - is3D = QgsWkbTypes::hasZ( currentLayer->wkbType() ); - - if ( is3D && !point.is3D() ) - point.addZValue( defaultZValue() ); - - switch ( mCreateMode ) - { - case DistanceMode: - mRectangle = QgsQuadrilateral::rectangleFrom3Points( mPoints.at( 0 ), mPoints.at( 1 ), point, QgsQuadrilateral::Distance ); - break; - case ProjectedMode: - mRectangle = QgsQuadrilateral::rectangleFrom3Points( mPoints.at( 0 ), mPoints.at( 1 ), point, QgsQuadrilateral::Projected ); - break; - } - mTempRubberBand->setGeometry( mRectangle.toPolygon( ) ); - } - break; - default: - break; - } - } -} diff --git a/src/app/qgsmaptoolrectangle3points.h b/src/app/qgsmaptoolrectangle3points.h deleted file mode 100644 index 189c1bacef3a..000000000000 --- a/src/app/qgsmaptoolrectangle3points.h +++ /dev/null @@ -1,43 +0,0 @@ -/*************************************************************************** - qgsmaptoolrectangle3points.h - map tool for adding rectangle - from 3 points - --------------------- - begin : September 2017 - copyright : (C) 2017 by Loïc Bartoletti - email : lbartoletti at tuxfamily dot org -*************************************************************************** -* * -* 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 3 of the License, or * -* (at your option) any later version. * -* * -***************************************************************************/ - -#ifndef QGSMAPTOOLRECTANGLE3POINTS_H -#define QGSMAPTOOLRECTANGLE3POINTS_H - -#include "qgsmaptooladdrectangle.h" -#include "qgis_app.h" - -class APP_EXPORT QgsMapToolRectangle3Points: public QgsMapToolAddRectangle -{ - Q_OBJECT - - public: - enum CreateMode - { - DistanceMode, - ProjectedMode, - }; - QgsMapToolRectangle3Points( QgsMapToolCapture *parentTool, QgsMapCanvas *canvas, CreateMode createMode, CaptureMode mode = CaptureLine ); - - void cadCanvasReleaseEvent( QgsMapMouseEvent *e ) override; - void cadCanvasMoveEvent( QgsMapMouseEvent *e ) override; - - private: - CreateMode mCreateMode; - -}; - -#endif // QGSMAPTOOLRECTANGLE3POINTS_H diff --git a/src/app/qgsmaptoolrectanglecenter.h b/src/app/qgsmaptoolrectanglecenter.h deleted file mode 100644 index 61ba72c679d4..000000000000 --- a/src/app/qgsmaptoolrectanglecenter.h +++ /dev/null @@ -1,34 +0,0 @@ -/*************************************************************************** - qgsmaptoolrectanglecenter.h - map tool for adding rectangle - from center and a point - --------------------- - begin : July 2017 - copyright : (C) 2017 by Loïc Bartoletti - email : lbartoletti at tuxfamily dot org - *************************************************************************** - * * - * 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 3 of the License, or * - * (at your option) any later version. * - * * - ***************************************************************************/ - -#ifndef QGSMAPTOOLRECTANGLECENTER_H -#define QGSMAPTOOLRECTANGLECENTER_H - -#include "qgsmaptooladdrectangle.h" -#include "qgis_app.h" - -class APP_EXPORT QgsMapToolRectangleCenter: public QgsMapToolAddRectangle -{ - Q_OBJECT - - public: - QgsMapToolRectangleCenter( QgsMapToolCapture *parentTool, QgsMapCanvas *canvas, CaptureMode mode = CaptureLine ); - - void cadCanvasReleaseEvent( QgsMapMouseEvent *e ) override; - void cadCanvasMoveEvent( QgsMapMouseEvent *e ) override; -}; - -#endif // QGSMAPTOOLRECTANGLECENTER_H diff --git a/src/app/qgsmaptoolrectangleextent.h b/src/app/qgsmaptoolrectangleextent.h deleted file mode 100644 index cd6e559c5446..000000000000 --- a/src/app/qgsmaptoolrectangleextent.h +++ /dev/null @@ -1,34 +0,0 @@ -/*************************************************************************** - qgsmaptoolrectangleextent.h - map tool for adding rectangle - from extent - --------------------- - begin : July 2017 - copyright : (C) 2017 by Loïc Bartoletti - email : lbartoletti at tuxfamily dot org - *************************************************************************** - * * - * 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 3 of the License, or * - * (at your option) any later version. * - * * - ***************************************************************************/ - -#ifndef QGSMAPTOOLRECTANGLEEXTENT_H -#define QGSMAPTOOLRECTANGLEEXTENT_H - -#include "qgsmaptooladdrectangle.h" -#include "qgis_app.h" - -class APP_EXPORT QgsMapToolRectangleExtent: public QgsMapToolAddRectangle -{ - Q_OBJECT - - public: - QgsMapToolRectangleExtent( QgsMapToolCapture *parentTool, QgsMapCanvas *canvas, CaptureMode mode = CaptureLine ); - - void cadCanvasReleaseEvent( QgsMapMouseEvent *e ) override; - void cadCanvasMoveEvent( QgsMapMouseEvent *e ) override; -}; - -#endif // QGSMAPTOOLRECTANGLEEXTENT_H diff --git a/src/app/qgsmaptoolregularpolygon2points.cpp b/src/app/qgsmaptoolregularpolygon2points.cpp deleted file mode 100644 index e1691cca4dcb..000000000000 --- a/src/app/qgsmaptoolregularpolygon2points.cpp +++ /dev/null @@ -1,84 +0,0 @@ -/*************************************************************************** - qgsmaptoolregularpolygon2points.cpp - map tool for adding regular - polygon from 2 points - --------------------- - begin : July 2017 - copyright : (C) 2017 by Loïc Bartoletti - email : lbartoletti at tuxfamily dot org - *************************************************************************** - * * - * 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 "qgsmaptoolregularpolygon2points.h" -#include "qgsgeometryrubberband.h" -#include "qgsmapcanvas.h" -#include "qgspoint.h" -#include "qgsmapmouseevent.h" -#include "qgssnapindicator.h" - -QgsMapToolRegularPolygon2Points::QgsMapToolRegularPolygon2Points( QgsMapToolCapture *parentTool, - QgsMapCanvas *canvas, CaptureMode mode ) - : QgsMapToolAddRegularPolygon( parentTool, canvas, mode ) -{ - mToolName = tr( "Add regular polygon from 2 points" ); -} - -QgsMapToolRegularPolygon2Points::~QgsMapToolRegularPolygon2Points() -{ - if ( mNumberSidesSpinBox ) - { - deleteNumberSidesSpinBox(); - } -} - -void QgsMapToolRegularPolygon2Points::cadCanvasReleaseEvent( QgsMapMouseEvent *e ) -{ - const QgsPoint point = mapPoint( *e ); - - if ( !currentVectorLayer() ) - { - notifyNotVectorLayer(); - clean(); - stopCapturing(); - e->ignore(); - return; - } - - if ( e->button() == Qt::LeftButton ) - { - if ( mPoints.empty() ) - mPoints.append( point ); - - if ( !mTempRubberBand ) - { - mTempRubberBand = createGeometryRubberBand( mLayerType, true ); - mTempRubberBand->show(); - - createNumberSidesSpinBox(); - } - } - else if ( e->button() == Qt::RightButton ) - { - mPoints.append( point ); - - release( e ); - } -} - -void QgsMapToolRegularPolygon2Points::cadCanvasMoveEvent( QgsMapMouseEvent *e ) -{ - const QgsPoint point = mapPoint( *e ); - - mSnapIndicator->setMatch( e->mapPointMatch() ); - - if ( mTempRubberBand ) - { - mRegularPolygon = QgsRegularPolygon( mPoints.at( 0 ), point, mNumberSidesSpinBox->value() ); - mTempRubberBand->setGeometry( mRegularPolygon.toPolygon() ); - } -} diff --git a/src/app/qgsmaptoolregularpolygon2points.h b/src/app/qgsmaptoolregularpolygon2points.h deleted file mode 100644 index e02cc9eac5d7..000000000000 --- a/src/app/qgsmaptoolregularpolygon2points.h +++ /dev/null @@ -1,36 +0,0 @@ -/*************************************************************************** - qgmaptoolregularpolygon2points.h - map tool for adding regular - polygon from 2 points - --------------------- - begin : July 2017 - copyright : (C) 2017 by Loïc Bartoletti - email : lbartoletti at tuxfamily dot org - *************************************************************************** - * * - * 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 QGSMAPTOOLREGULARPOLYGON2POINTS_H -#define QGSMAPTOOLREGULARPOLYGON2POINTS_H - -#include "qgsmaptooladdregularpolygon.h" -#include "qgis_app.h" - -class APP_EXPORT QgsMapToolRegularPolygon2Points: public QgsMapToolAddRegularPolygon -{ - Q_OBJECT - - public: - QgsMapToolRegularPolygon2Points( QgsMapToolCapture *parentTool, QgsMapCanvas *canvas, CaptureMode mode = CaptureLine ); - ~QgsMapToolRegularPolygon2Points() override; - - void cadCanvasReleaseEvent( QgsMapMouseEvent *e ) override; - void cadCanvasMoveEvent( QgsMapMouseEvent *e ) override; - -}; - -#endif // QGSMAPTOOLREGULARPOLYGON2POINTS_H diff --git a/src/app/qgsmaptoolregularpolygoncentercorner.cpp b/src/app/qgsmaptoolregularpolygoncentercorner.cpp deleted file mode 100644 index c9f608fcb2e5..000000000000 --- a/src/app/qgsmaptoolregularpolygoncentercorner.cpp +++ /dev/null @@ -1,83 +0,0 @@ -/*************************************************************************** - qgsmaptoolregularpolygoncentercorner.cpp - map tool for adding regular - polygon from center and a corner - --------------------- - begin : July 2017 - copyright : (C) 2017 by Loïc Bartoletti - email : lbartoletti at tuxfamily dot org - *************************************************************************** - * * - * 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 "qgsmaptoolregularpolygoncentercorner.h" -#include "qgsgeometryrubberband.h" -#include "qgsmapcanvas.h" -#include "qgspoint.h" -#include "qgsmapmouseevent.h" -#include "qgssnapindicator.h" - - -QgsMapToolRegularPolygonCenterCorner::QgsMapToolRegularPolygonCenterCorner( QgsMapToolCapture *parentTool, - QgsMapCanvas *canvas, CaptureMode mode ) - : QgsMapToolAddRegularPolygon( parentTool, canvas, mode ) -{ - mToolName = tr( "Add regular polygon from center and a corner" ); -} - -QgsMapToolRegularPolygonCenterCorner::~QgsMapToolRegularPolygonCenterCorner() -{ - deleteNumberSidesSpinBox(); -} - -void QgsMapToolRegularPolygonCenterCorner::cadCanvasReleaseEvent( QgsMapMouseEvent *e ) -{ - const QgsPoint point = mapPoint( *e ); - - if ( !currentVectorLayer() ) - { - notifyNotVectorLayer(); - clean(); - stopCapturing(); - e->ignore(); - return; - } - - if ( e->button() == Qt::LeftButton ) - { - if ( mPoints.empty() ) - mPoints.append( point ); - - if ( !mTempRubberBand ) - { - mTempRubberBand = createGeometryRubberBand( mLayerType, true ); - mTempRubberBand->show(); - - createNumberSidesSpinBox(); - } - } - else if ( e->button() == Qt::RightButton ) - { - mPoints.append( point ); - - release( e ); - } -} - -void QgsMapToolRegularPolygonCenterCorner::cadCanvasMoveEvent( QgsMapMouseEvent *e ) -{ - const QgsPoint point = mapPoint( *e ); - - mSnapIndicator->setMatch( e->mapPointMatch() ); - - if ( mTempRubberBand ) - { - const QgsRegularPolygon::ConstructionOption option = QgsRegularPolygon::InscribedCircle; - mRegularPolygon = QgsRegularPolygon( mPoints.at( 0 ), point, mNumberSidesSpinBox->value(), option ); - mTempRubberBand->setGeometry( mRegularPolygon.toPolygon() ); - } -} diff --git a/src/app/qgsmaptoolregularpolygoncentercorner.h b/src/app/qgsmaptoolregularpolygoncentercorner.h deleted file mode 100644 index a7bff18b3f00..000000000000 --- a/src/app/qgsmaptoolregularpolygoncentercorner.h +++ /dev/null @@ -1,35 +0,0 @@ -/*************************************************************************** - qgsmaptoolregularpolygoncentercorner.h - map tool for adding regular - polygon from center and a corner - --------------------- - begin : July 2017 - copyright : (C) 2017 by Loïc Bartoletti - email : lbartoletti at tuxfamily dot org - *************************************************************************** - * * - * 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 QGSMAPTOOLREGULARPOLYGONCENTERCORNER_H -#define QGSMAPTOOLREGULARPOLYGONCENTERCORNER_H - -#include "qgsmaptooladdregularpolygon.h" -#include "qgis_app.h" - -class APP_EXPORT QgsMapToolRegularPolygonCenterCorner: public QgsMapToolAddRegularPolygon -{ - Q_OBJECT - - public: - QgsMapToolRegularPolygonCenterCorner( QgsMapToolCapture *parentTool, QgsMapCanvas *canvas, CaptureMode mode = CaptureLine ); - ~QgsMapToolRegularPolygonCenterCorner() override; - - void cadCanvasReleaseEvent( QgsMapMouseEvent *e ) override; - void cadCanvasMoveEvent( QgsMapMouseEvent *e ) override; -}; - -#endif // QGSMAPTOOLREGULARPOLYGONCENTERCORNER_H diff --git a/src/app/qgsmaptoolregularpolygoncenterpoint.cpp b/src/app/qgsmaptoolregularpolygoncenterpoint.cpp deleted file mode 100644 index 871ff6df264c..000000000000 --- a/src/app/qgsmaptoolregularpolygoncenterpoint.cpp +++ /dev/null @@ -1,85 +0,0 @@ -/*************************************************************************** - qgsmaptoolregularpolygoncenterpoint.cpp - map tool for adding regular - polygon from center and a point - --------------------- - begin : July 2017 - copyright : (C) 2017 by Loïc Bartoletti - email : lbartoletti at tuxfamily dot org - *************************************************************************** - * * - * 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 "qgsmaptoolregularpolygoncenterpoint.h" -#include "qgsgeometryrubberband.h" -#include "qgsmapcanvas.h" -#include "qgspoint.h" -#include "qgsmapmouseevent.h" -#include "qgssnapindicator.h" - -QgsMapToolRegularPolygonCenterPoint::QgsMapToolRegularPolygonCenterPoint( QgsMapToolCapture *parentTool, - QgsMapCanvas *canvas, CaptureMode mode ) - : QgsMapToolAddRegularPolygon( parentTool, canvas, mode ) -{ - mToolName = tr( "Add regular polygon from center and a point " ); -} - -QgsMapToolRegularPolygonCenterPoint::~QgsMapToolRegularPolygonCenterPoint() -{ - deleteNumberSidesSpinBox(); -} - -void QgsMapToolRegularPolygonCenterPoint::cadCanvasReleaseEvent( QgsMapMouseEvent *e ) -{ - const QgsPoint point = mapPoint( *e ); - - if ( !currentVectorLayer() ) - { - notifyNotVectorLayer(); - clean(); - stopCapturing(); - e->ignore(); - return; - } - - if ( e->button() == Qt::LeftButton ) - { - if ( mPoints.size() < 1 ) - mPoints.append( point ); - - if ( !mPoints.isEmpty() ) - { - if ( !mTempRubberBand ) - { - mTempRubberBand = createGeometryRubberBand( mLayerType, true ); - mTempRubberBand->show(); - - createNumberSidesSpinBox(); - } - } - } - else if ( e->button() == Qt::RightButton ) - { - mPoints.append( point ); - - release( e ); - } -} - -void QgsMapToolRegularPolygonCenterPoint::cadCanvasMoveEvent( QgsMapMouseEvent *e ) -{ - const QgsPoint point = mapPoint( *e ); - - mSnapIndicator->setMatch( e->mapPointMatch() ); - - if ( mTempRubberBand ) - { - const QgsRegularPolygon::ConstructionOption option = QgsRegularPolygon::CircumscribedCircle; - mRegularPolygon = QgsRegularPolygon( mPoints.at( 0 ), point, mNumberSidesSpinBox->value(), option ); - mTempRubberBand->setGeometry( mRegularPolygon.toPolygon() ); - } -} diff --git a/src/app/qgsmaptoolregularpolygoncenterpoint.h b/src/app/qgsmaptoolregularpolygoncenterpoint.h deleted file mode 100644 index 6af3a1bbb945..000000000000 --- a/src/app/qgsmaptoolregularpolygoncenterpoint.h +++ /dev/null @@ -1,35 +0,0 @@ -/*************************************************************************** - qgsmaptoolregularpolygoncenterpoint.h - map tool for adding regular - polygon from center and a point - --------------------- - begin : July 2017 - copyright : (C) 2017 by Loïc Bartoletti - email : lbartoletti at tuxfamily dot org - *************************************************************************** - * * - * 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 QGSMAPTOOLREGULARPOLYGONCENTERPOINT_H -#define QGSMAPTOOLREGULARPOLYGONCENTERPOINT_H - -#include "qgsmaptooladdregularpolygon.h" -#include "qgis_app.h" - -class APP_EXPORT QgsMapToolRegularPolygonCenterPoint: public QgsMapToolAddRegularPolygon -{ - Q_OBJECT - - public: - QgsMapToolRegularPolygonCenterPoint( QgsMapToolCapture *parentTool, QgsMapCanvas *canvas, CaptureMode mode = CaptureLine ); - ~QgsMapToolRegularPolygonCenterPoint() override; - - void cadCanvasReleaseEvent( QgsMapMouseEvent *e ) override; - void cadCanvasMoveEvent( QgsMapMouseEvent *e ) override; -}; - -#endif // QGSMAPTOOLREGULARPOLYGONCENTERPOINT_H diff --git a/src/app/qgsmaptoolreshape.cpp b/src/app/qgsmaptoolreshape.cpp index 76e522e392cf..0b9b47596e7b 100644 --- a/src/app/qgsmaptoolreshape.cpp +++ b/src/app/qgsmaptoolreshape.cpp @@ -80,10 +80,13 @@ bool QgsMapToolReshape::supportsTechnique( QgsMapToolCapture::CaptureTechnique t { switch ( technique ) { - case QgsMapToolCapture::StraightSegments: - case QgsMapToolCapture::CircularString: - case QgsMapToolCapture::Streaming: + case QgsMapToolCapture::CaptureTechnique::StraightSegments: + case QgsMapToolCapture::CaptureTechnique::CircularString: + case QgsMapToolCapture::CaptureTechnique::Streaming: return true; + + case QgsMapToolCapture::CaptureTechnique::Shape: + return false; } return false; } diff --git a/src/app/qgsmaptoolsplitfeatures.cpp b/src/app/qgsmaptoolsplitfeatures.cpp index f2326cc17116..2e5deb232a14 100644 --- a/src/app/qgsmaptoolsplitfeatures.cpp +++ b/src/app/qgsmaptoolsplitfeatures.cpp @@ -34,10 +34,13 @@ bool QgsMapToolSplitFeatures::supportsTechnique( QgsMapToolCapture::CaptureTechn { switch ( technique ) { - case QgsMapToolCapture::StraightSegments: - case QgsMapToolCapture::CircularString: - case QgsMapToolCapture::Streaming: + case QgsMapToolCapture::CaptureTechnique::StraightSegments: + case QgsMapToolCapture::CaptureTechnique::CircularString: + case QgsMapToolCapture::CaptureTechnique::Streaming: return true; + + case QgsMapToolCapture::CaptureTechnique::Shape: + return false; } return false; } diff --git a/src/app/qgsmaptoolsplitparts.cpp b/src/app/qgsmaptoolsplitparts.cpp index 77b6684c3c75..1b14a5382320 100644 --- a/src/app/qgsmaptoolsplitparts.cpp +++ b/src/app/qgsmaptoolsplitparts.cpp @@ -34,11 +34,14 @@ bool QgsMapToolSplitParts::supportsTechnique( QgsMapToolCapture::CaptureTechniqu { switch ( technique ) { - case QgsMapToolCapture::StraightSegments: - case QgsMapToolCapture::Streaming: + case QgsMapToolCapture::CaptureTechnique::StraightSegments: + case QgsMapToolCapture::CaptureTechnique::Streaming: return true; - case QgsMapToolCapture::CircularString: + case QgsMapToolCapture::CaptureTechnique::CircularString: + return false; + + case QgsMapToolCapture::CaptureTechnique::Shape: return false; } return false; diff --git a/src/app/qgssettingsregistryapp.cpp b/src/app/qgssettingsregistryapp.cpp new file mode 100644 index 000000000000..c26707f22010 --- /dev/null +++ b/src/app/qgssettingsregistryapp.cpp @@ -0,0 +1,38 @@ +/*************************************************************************** + qgssettingsregistryapp.h + ---------------------- + begin : January 2022 + copyright : (C) 2022 by Denis Rouzaud + email : denis@opengis.ch + ***************************************************************************/ + +/*************************************************************************** + * * + * 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 "qgssettingsregistrycore.h" +#include "qgssettingsregistryapp.h" +#include "qgsapplication.h" + +#include "qgsmaptoolsdigitizingtechniquemanager.h" + + +QgsSettingsRegistryApp::QgsSettingsRegistryApp() + : QgsSettingsRegistry() +{ + addSettingsEntry( &QgsMapToolsDigitizingTechniqueManager::settingsDigitizingTechnique ); + addSettingsEntry( &QgsMapToolsDigitizingTechniqueManager::settingMapToolShapeDefaultForShape ); + addSettingsEntry( &QgsMapToolsDigitizingTechniqueManager::settingMapToolShapeCurrent ); + + QgsApplication::settingsRegistryCore()->addSubRegistry( this ); +} + +QgsSettingsRegistryApp::~QgsSettingsRegistryApp() +{ + QgsApplication::settingsRegistryCore()->removeSubRegistry( this ); +} diff --git a/src/app/qgssettingsregistryapp.h b/src/app/qgssettingsregistryapp.h new file mode 100644 index 000000000000..7e7d8ff5aa82 --- /dev/null +++ b/src/app/qgssettingsregistryapp.h @@ -0,0 +1,33 @@ +/*************************************************************************** + qgssettingsregistryapp.cpp + ---------------------- + begin : January 2022 + copyright : (C) 2022 by Denis Rouzaud + email : denis@opengis.ch + ***************************************************************************/ + +/*************************************************************************** + * * + * 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 QGSSETTINGSREGISTRYAPP_H +#define QGSSETTINGSREGISTRYAPP_H + +#include "qgisapp.h" +#include "qgis_sip.h" +#include "qgssettingsregistry.h" + + +class APP_EXPORT QgsSettingsRegistryApp : public QgsSettingsRegistry +{ + public: + QgsSettingsRegistryApp(); + ~QgsSettingsRegistryApp(); +}; + +#endif // QGSSETTINGSREGISTRYAPP_H diff --git a/src/core/geometry/qgsgeometryeditutils.cpp b/src/core/geometry/qgsgeometryeditutils.cpp index c845b430f878..23f76c44c45a 100644 --- a/src/core/geometry/qgsgeometryeditutils.cpp +++ b/src/core/geometry/qgsgeometryeditutils.cpp @@ -141,7 +141,23 @@ Qgis::GeometryOperationResult QgsGeometryEditUtils::addPart( QgsAbstractGeometry || QgsWkbTypes::flatType( part->wkbType() ) == QgsWkbTypes::Triangle || QgsWkbTypes::flatType( part->wkbType() ) == QgsWkbTypes::CurvePolygon ) { - added = geomCollection->addGeometry( part.release() ); + QgsCurvePolygon *curvePolygon = qgsgeometry_cast( part.get() ); + if ( curvePolygon ) + { + if ( QgsWkbTypes::flatType( geom->wkbType() ) == QgsWkbTypes::MultiPolygon && curvePolygon->hasCurvedSegments() ) + { + //need to segmentize part as multipolygon does not support curves + QgsCurvePolygon *polygon = curvePolygon->toPolygon(); + delete curvePolygon; + curvePolygon = polygon; + } + part.release(); + added = geomCollection->addGeometry( curvePolygon ); + } + else + { + added = geomCollection->addGeometry( part.release() ); + } } else if ( QgsWkbTypes::flatType( part->wkbType() ) == QgsWkbTypes::MultiPolygon || QgsWkbTypes::flatType( part->wkbType() ) == QgsWkbTypes::MultiSurface ) @@ -150,8 +166,11 @@ Qgis::GeometryOperationResult QgsGeometryEditUtils::addPart( QgsAbstractGeometry int i; const int n = geomCollection->numGeometries(); - for ( i = 0; i < parts->numGeometries() && geomCollection->addGeometry( parts->geometryN( i )->clone() ); i++ ) - ; + for ( i = 0; i < parts->numGeometries(); i++ ) + { + if ( !geomCollection->addGeometry( parts->geometryN( i )->clone() ) ) + break; + } added = i == parts->numGeometries(); if ( !added ) @@ -166,6 +185,51 @@ Qgis::GeometryOperationResult QgsGeometryEditUtils::addPart( QgsAbstractGeometry return Qgis::GeometryOperationResult::InvalidInputGeometryType; } } + else if ( QgsWkbTypes::flatType( geom->wkbType() ) == QgsWkbTypes::MultiLineString + || QgsWkbTypes::flatType( geom->wkbType() ) == QgsWkbTypes::MultiCurve ) + { + if ( QgsWkbTypes::flatType( part->wkbType() ) == QgsWkbTypes::MultiLineString + || QgsWkbTypes::flatType( part->wkbType() ) == QgsWkbTypes::MultiCurve ) + { + std::unique_ptr parts( qgsgeometry_cast( part.release() ) ); + + int i; + const int n = geomCollection->numGeometries(); + for ( i = 0; i < parts->numGeometries(); i++ ) + { + if ( !geomCollection->addGeometry( parts->geometryN( i )->clone() ) ) + break; + } + + added = i == parts->numGeometries(); + if ( !added ) + { + while ( geomCollection->numGeometries() > n ) + geomCollection->removeGeometry( n ); + return Qgis::GeometryOperationResult::InvalidInputGeometryType; + } + } + else + { + QgsCurve *curve = qgsgeometry_cast( part.get() ); + if ( curve ) + { + if ( QgsWkbTypes::flatType( geom->wkbType() ) == QgsWkbTypes::MultiLineString && curve->hasCurvedSegments() ) + { + //need to segmentize part as multilinestring does not support curves + QgsCurve *line = curve->segmentize(); + delete curve; + curve = line; + } + part.release(); + added = geomCollection->addGeometry( curve ); + } + else + { + added = geomCollection->addGeometry( part.release() ); + } + } + } else { added = geomCollection->addGeometry( part.release() ); diff --git a/src/gui/CMakeLists.txt b/src/gui/CMakeLists.txt index 9c1507538682..b95abccc0a1e 100644 --- a/src/gui/CMakeLists.txt +++ b/src/gui/CMakeLists.txt @@ -288,6 +288,10 @@ set(QGIS_GUI_SRCS locator/qgslocatorwidget.cpp + maptools/qgsmaptoolshapeabstract.cpp + maptools/qgsmaptoolcapturelayergeometry.cpp + maptools/qgsmaptoolshaperegistry.cpp + mesh/qgsmeshlayerproperties.cpp mesh/qgsrenderermeshpropertieswidget.cpp mesh/qgsmeshdatasetgrouptreewidget.cpp @@ -1117,6 +1121,10 @@ set(QGIS_GUI_HDRS locator/qgslocatorwidget.h + maptools/qgsmaptoolshapeabstract.h + maptools/qgsmaptoolcapturelayergeometry.h + maptools/qgsmaptoolshaperegistry.h + mesh/qgsmeshlayerproperties.h mesh/qgsrenderermeshpropertieswidget.h mesh/qgsmeshdatasetgrouptreeview.h @@ -1467,6 +1475,7 @@ target_include_directories(qgis_gui PUBLIC ${CMAKE_SOURCE_DIR}/src/gui/layertree ${CMAKE_SOURCE_DIR}/src/gui/layout ${CMAKE_SOURCE_DIR}/src/gui/locator + ${CMAKE_SOURCE_DIR}/src/gui/maptools ${CMAKE_SOURCE_DIR}/src/gui/mesh ${CMAKE_SOURCE_DIR}/src/gui/numericformats ${CMAKE_SOURCE_DIR}/src/gui/ogr diff --git a/src/gui/annotations/qgscreateannotationitemmaptool_impl.cpp b/src/gui/annotations/qgscreateannotationitemmaptool_impl.cpp index fbb50db14937..08ad972dff44 100644 --- a/src/gui/annotations/qgscreateannotationitemmaptool_impl.cpp +++ b/src/gui/annotations/qgscreateannotationitemmaptool_impl.cpp @@ -38,7 +38,7 @@ QgsMapToolCaptureAnnotationItem::QgsMapToolCaptureAnnotationItem( QgsMapCanvas *canvas, QgsAdvancedDigitizingDockWidget *cadDockWidget, CaptureMode mode ) : QgsMapToolCapture( canvas, cadDockWidget, mode ) { - + mToolName = tr( "Annotation tool" ); } QgsCreateAnnotationItemMapToolHandler *QgsMapToolCaptureAnnotationItem::handler() @@ -63,9 +63,16 @@ QgsMapToolCapture::Capabilities QgsMapToolCaptureAnnotationItem::capabilities() return SupportsCurves; } -bool QgsMapToolCaptureAnnotationItem::supportsTechnique( CaptureTechnique ) const +bool QgsMapToolCaptureAnnotationItem::supportsTechnique( CaptureTechnique technique ) const { - return true; + switch ( technique ) + { + case CaptureTechnique::StraightSegments: + case CaptureTechnique::CircularString: + case CaptureTechnique::Streaming: + case CaptureTechnique::Shape: + return true; + } } @@ -155,49 +162,23 @@ QgsCreateLineItemMapTool::QgsCreateLineItemMapTool( QgsMapCanvas *canvas, QgsAdv mHandler = new QgsCreateAnnotationItemMapToolHandler( canvas, cadDockWidget, this ); } -void QgsCreateLineItemMapTool::cadCanvasReleaseEvent( QgsMapMouseEvent *e ) +void QgsCreateLineItemMapTool::lineCaptured( const QgsCurve *line ) { - //add point to list and to rubber band - if ( e->button() == Qt::LeftButton ) + // do it! + std::unique_ptr< QgsAbstractGeometry > geometry( line->simplifiedTypeRef()->clone() ); + if ( qgsgeometry_cast< QgsCurve * >( geometry.get() ) ) { - const int error = addVertex( e->mapPoint(), e->mapPointMatch() ); - if ( error == 2 ) - { - //problem with coordinate transformation - emit messageEmitted( tr( "Cannot transform the point to the layers coordinate system" ), Qgis::MessageLevel::Warning ); - return; - } - - startCapturing(); - } - else if ( e->button() == Qt::RightButton ) - { - deleteTempRubberBand(); - - //find out bounding box of mCaptureList - if ( size() < 1 ) - { - stopCapturing(); - return; - } - - // do it! - std::unique_ptr< QgsAbstractGeometry > geometry( captureCurve()->simplifiedTypeRef()->clone() ); - if ( qgsgeometry_cast< QgsCurve * >( geometry.get() ) ) - { - std::unique_ptr< QgsAnnotationLineItem > createdItem = std::make_unique< QgsAnnotationLineItem >( qgsgeometry_cast< QgsCurve * >( geometry.release() ) ); - - std::unique_ptr< QgsLineSymbol > lineSymbol = QgsApplication::recentStyleHandler()->recentSymbol< QgsLineSymbol >( QStringLiteral( "line_annotation_item" ) ); - if ( !lineSymbol ) - lineSymbol.reset( qgis::down_cast< QgsLineSymbol * >( QgsSymbol::defaultSymbol( QgsWkbTypes::LineGeometry ) ) ); - createdItem->setSymbol( lineSymbol.release() ); - - // set reference scale to match canvas scale, but don't enable it by default for marker items - createdItem->setSymbologyReferenceScale( canvas()->scale() ); - - mHandler->pushCreatedItem( createdItem.release() ); - } - stopCapturing(); + std::unique_ptr< QgsAnnotationLineItem > createdItem = std::make_unique< QgsAnnotationLineItem >( qgsgeometry_cast< QgsCurve * >( geometry.release() ) ); + + std::unique_ptr< QgsLineSymbol > lineSymbol = QgsApplication::recentStyleHandler()->recentSymbol< QgsLineSymbol >( QStringLiteral( "line_annotation_item" ) ); + if ( !lineSymbol ) + lineSymbol.reset( qgis::down_cast< QgsLineSymbol * >( QgsSymbol::defaultSymbol( QgsWkbTypes::LineGeometry ) ) ); + createdItem->setSymbol( lineSymbol.release() ); + + // set reference scale to match canvas scale, but don't enable it by default for marker items + createdItem->setSymbologyReferenceScale( canvas()->scale() ); + + mHandler->pushCreatedItem( createdItem.release() ); } } @@ -211,52 +192,24 @@ QgsCreatePolygonItemMapTool::QgsCreatePolygonItemMapTool( QgsMapCanvas *canvas, mHandler = new QgsCreateAnnotationItemMapToolHandler( canvas, cadDockWidget, this ); } -void QgsCreatePolygonItemMapTool::cadCanvasReleaseEvent( QgsMapMouseEvent *e ) +void QgsCreatePolygonItemMapTool::polygonCaptured( const QgsCurvePolygon *polygon ) { - //add point to list and to rubber band - if ( e->button() == Qt::LeftButton ) - { - const int error = addVertex( e->mapPoint(), e->mapPointMatch() ); - if ( error == 2 ) - { - //problem with coordinate transformation - emit messageEmitted( tr( "Cannot transform the point to the layers coordinate system" ), Qgis::MessageLevel::Warning ); - return; - } - - startCapturing(); - } - else if ( e->button() == Qt::RightButton ) + std::unique_ptr< QgsAbstractGeometry > geometry( polygon->exteriorRing()->simplifiedTypeRef()->clone() ); + if ( qgsgeometry_cast< QgsCurve * >( geometry.get() ) ) { - deleteTempRubberBand(); - - //find out bounding box of mCaptureList - if ( size() < 1 ) - { - stopCapturing(); - return; - } - - closePolygon(); - - std::unique_ptr< QgsAbstractGeometry > geometry( captureCurve()->simplifiedTypeRef()->clone() ); - if ( qgsgeometry_cast< QgsCurve * >( geometry.get() ) ) - { - std::unique_ptr< QgsCurvePolygon > newPolygon = std::make_unique< QgsCurvePolygon >(); - newPolygon->setExteriorRing( qgsgeometry_cast< QgsCurve * >( geometry.release() ) ); - std::unique_ptr< QgsAnnotationPolygonItem > createdItem = std::make_unique< QgsAnnotationPolygonItem >( newPolygon.release() ); - - std::unique_ptr< QgsFillSymbol > fillSymbol = QgsApplication::recentStyleHandler()->recentSymbol< QgsFillSymbol >( QStringLiteral( "polygon_annotation_item" ) ); - if ( !fillSymbol ) - fillSymbol.reset( qgis::down_cast< QgsFillSymbol * >( QgsSymbol::defaultSymbol( QgsWkbTypes::PolygonGeometry ) ) ); - createdItem->setSymbol( fillSymbol.release() ); - - // set reference scale to match canvas scale, but don't enable it by default for marker items - createdItem->setSymbologyReferenceScale( canvas()->scale() ); - - mHandler->pushCreatedItem( createdItem.release() ); - } - stopCapturing(); + std::unique_ptr< QgsCurvePolygon > newPolygon = std::make_unique< QgsCurvePolygon >(); + newPolygon->setExteriorRing( qgsgeometry_cast< QgsCurve * >( geometry.release() ) ); + std::unique_ptr< QgsAnnotationPolygonItem > createdItem = std::make_unique< QgsAnnotationPolygonItem >( newPolygon.release() ); + + std::unique_ptr< QgsFillSymbol > fillSymbol = QgsApplication::recentStyleHandler()->recentSymbol< QgsFillSymbol >( QStringLiteral( "polygon_annotation_item" ) ); + if ( !fillSymbol ) + fillSymbol.reset( qgis::down_cast< QgsFillSymbol * >( QgsSymbol::defaultSymbol( QgsWkbTypes::PolygonGeometry ) ) ); + createdItem->setSymbol( fillSymbol.release() ); + + // set reference scale to match canvas scale, but don't enable it by default for marker items + createdItem->setSymbologyReferenceScale( canvas()->scale() ); + + mHandler->pushCreatedItem( createdItem.release() ); } } diff --git a/src/gui/annotations/qgscreateannotationitemmaptool_impl.h b/src/gui/annotations/qgscreateannotationitemmaptool_impl.h index 1d9aaa7ba1cd..90848c72b04c 100644 --- a/src/gui/annotations/qgscreateannotationitemmaptool_impl.h +++ b/src/gui/annotations/qgscreateannotationitemmaptool_impl.h @@ -81,8 +81,8 @@ class QgsCreateLineItemMapTool: public QgsMapToolCaptureAnnotationItem QgsCreateLineItemMapTool( QgsMapCanvas *canvas, QgsAdvancedDigitizingDockWidget *cadDockWidget ); - void cadCanvasReleaseEvent( QgsMapMouseEvent *e ) override; - + private slots: + void lineCaptured( const QgsCurve *line ) override; }; class QgsCreatePolygonItemMapTool: public QgsMapToolCaptureAnnotationItem @@ -93,8 +93,8 @@ class QgsCreatePolygonItemMapTool: public QgsMapToolCaptureAnnotationItem QgsCreatePolygonItemMapTool( QgsMapCanvas *canvas, QgsAdvancedDigitizingDockWidget *cadDockWidget ); - void cadCanvasReleaseEvent( QgsMapMouseEvent *e ) override; - + private slots: + void polygonCaptured( const QgsCurvePolygon *polygon ) override; }; ///@endcond PRIVATE diff --git a/src/gui/maptools/qgsmaptoolcapturelayergeometry.cpp b/src/gui/maptools/qgsmaptoolcapturelayergeometry.cpp new file mode 100644 index 000000000000..08471ecba35f --- /dev/null +++ b/src/gui/maptools/qgsmaptoolcapturelayergeometry.cpp @@ -0,0 +1,93 @@ +/*************************************************************************** + qgsmaptoolcapturelayergeometry.cpp - base class for map tools digitizing layer geometries + --------------------- + begin : January 2022 + copyright : (C) Denis Rouzaud + email : denis@opengis.ch + *************************************************************************** + * * + * 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 "qgsmaptoolcapturelayergeometry.h" +#include "qgsproject.h" +#include "qgscurvepolygon.h" +#include "qgscurve.h" + + + + +void QgsMapToolCaptureLayerGeometry::geometryCaptured( const QgsGeometry &geometry ) +{ + QgsVectorLayer *vlayer = qobject_cast( layer() ); + if ( !vlayer ) + return; + + QgsGeometry g( geometry ); + + switch ( mode() ) + { + case QgsMapToolCapture::CaptureNone: + case QgsMapToolCapture::CapturePoint: + break; + case QgsMapToolCapture::CaptureLine: + case QgsMapToolCapture::CapturePolygon: + //does compoundcurve contain circular strings? + //does provider support circular strings? + const bool hasCurvedSegments = captureCurve()->hasCurvedSegments(); + const bool providerSupportsCurvedSegments = vlayer && ( vlayer->dataProvider()->capabilities() & QgsVectorDataProvider::CircularGeometries ); + if ( !hasCurvedSegments || !providerSupportsCurvedSegments ) + g = QgsGeometry( g.constGet()->segmentize() ); + + QList avoidIntersectionsLayers; + switch ( QgsProject::instance()->avoidIntersectionsMode() ) + { + case QgsProject::AvoidIntersectionsMode::AvoidIntersectionsCurrentLayer: + if ( vlayer ) + avoidIntersectionsLayers.append( vlayer ); + break; + case QgsProject::AvoidIntersectionsMode::AvoidIntersectionsLayers: + avoidIntersectionsLayers = QgsProject::instance()->avoidIntersectionsLayers(); + break; + case QgsProject::AvoidIntersectionsMode::AllowIntersections: + break; + } + if ( avoidIntersectionsLayers.size() > 0 ) + { + const int avoidIntersectionsReturn = g.avoidIntersections( avoidIntersectionsLayers ); + if ( avoidIntersectionsReturn == 3 ) + { + emit messageEmitted( tr( "The feature has been added, but at least one geometry intersected is invalid. These geometries must be manually repaired." ), Qgis::MessageLevel::Warning ); + } + if ( g.isEmpty() ) //avoid intersection might have removed the whole geometry + { + emit messageEmitted( tr( "The feature cannot be added because its geometry collapsed due to intersection avoidance" ), Qgis::MessageLevel::Critical ); + stopCapturing(); + return; + } + } + break; + } + + layerGeometryCaptured( g ); + + switch ( mode() ) + { + case QgsMapToolCapture::CaptureNone: + break; + case QgsMapToolCapture::CapturePoint: + layerPointCaptured( *qgsgeometry_cast( g.constGet() ) ); + break; + case QgsMapToolCapture::CaptureLine: + layerLineCaptured( qgsgeometry_cast( g.constGet() ) ); + break; + case QgsMapToolCapture::CapturePolygon: + layerPolygonCaptured( qgsgeometry_cast( g.constGet() ) ); + break; + } +} diff --git a/src/gui/maptools/qgsmaptoolcapturelayergeometry.h b/src/gui/maptools/qgsmaptoolcapturelayergeometry.h new file mode 100644 index 000000000000..f99c31409b42 --- /dev/null +++ b/src/gui/maptools/qgsmaptoolcapturelayergeometry.h @@ -0,0 +1,66 @@ +/*************************************************************************** + qgsmaptoolcapturelayergeometry.h - base class for map tools digitizing layer geometries + --------------------- + begin : January 2022 + copyright : (C) Denis Rouzaud + email : denis@opengis.ch + *************************************************************************** + * * + * 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 QGSMAPTOOLCAPTURELAYERGEOMETRY_H +#define QGSMAPTOOLCAPTURELAYERGEOMETRY_H + +#include "qgsmaptoolcapture.h" + +class QgsAdvancedDigitizingDockWidget; +class QgsMapCanvas; + +/** + * \ingroup gui + * \brief QgsMapToolCaptureLayerGeometry is a base class for map tools digitizing layer geometries + * This map tool subclass automatically handles intersection avoidance with other layers in the active project whenever a geometry is digitized by the user. + * \since QGIS 3.26 + */ +class GUI_EXPORT QgsMapToolCaptureLayerGeometry : public QgsMapToolCapture +{ + public: + //! Constructor + QgsMapToolCaptureLayerGeometry( QgsMapCanvas *canvas, QgsAdvancedDigitizingDockWidget *cadDockWidget, CaptureMode mode ) + : QgsMapToolCapture( canvas, cadDockWidget, mode ) + {} + + private: + void geometryCaptured( const QgsGeometry &geometry ) override; + + /** + * Called when the geometry is captured + * A more specific handler is also called afterwards (layerPointCaptured, layerLineCaptured or layerPolygonCaptured) + */ + virtual void layerGeometryCaptured( const QgsGeometry &geometry ) {Q_UNUSED( geometry )} SIP_FORCE + + /** + * Called when a point is captured + * The generic geometryCaptured() signal will be emitted immediately before this point-specific signal. + */ + virtual void layerPointCaptured( const QgsPoint &point ) {Q_UNUSED( point )} SIP_FORCE + + /** + * Called when a line is captured + * The generic geometryCaptured() signal will be emitted immediately before this line-specific signal. + */ + virtual void layerLineCaptured( const QgsCurve *line ) {Q_UNUSED( line )} SIP_FORCE + + /** + * Called when a polygon is captured + * The generic geometryCaptured() signal will be emitted immediately before this polygon-specific signal. + */ + virtual void layerPolygonCaptured( const QgsCurvePolygon *polygon ) {Q_UNUSED( polygon )} SIP_FORCE +}; + +#endif // QGSMAPTOOLCAPTURELAYERGEOMETRY_H diff --git a/src/gui/maptools/qgsmaptoolshapeabstract.cpp b/src/gui/maptools/qgsmaptoolshapeabstract.cpp new file mode 100644 index 000000000000..4f1c1ad70602 --- /dev/null +++ b/src/gui/maptools/qgsmaptoolshapeabstract.cpp @@ -0,0 +1,54 @@ +/*************************************************************************** + qgsmaptoolshapeabstract.cpp + ---------------------- + begin : January 2022 + copyright : (C) 2022 by Denis Rouzaud + email : denis@opengis.ch + ***************************************************************************/ + +/*************************************************************************** + * * + * 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 "qgsmaptoolshapeabstract.h" +#include "qgsgeometryrubberband.h" + +#include + + +QgsMapToolShapeAbstract::~QgsMapToolShapeAbstract() +{ + clean(); +} + +void QgsMapToolShapeAbstract::keyPressEvent( QKeyEvent *e ) +{ + e->ignore(); +} + +void QgsMapToolShapeAbstract::keyReleaseEvent( QKeyEvent *e ) +{ + e->ignore(); +} + +void QgsMapToolShapeAbstract::clean() +{ + if ( mTempRubberBand ) + { + delete mTempRubberBand; + mTempRubberBand = nullptr; + } + + mPoints.clear(); +} + +void QgsMapToolShapeAbstract::undo() +{ + if ( mPoints.count() > 0 ) + mPoints.removeLast(); +} diff --git a/src/gui/maptools/qgsmaptoolshapeabstract.h b/src/gui/maptools/qgsmaptoolshapeabstract.h new file mode 100644 index 000000000000..8fae2399aecc --- /dev/null +++ b/src/gui/maptools/qgsmaptoolshapeabstract.h @@ -0,0 +1,117 @@ +/*************************************************************************** + qgsmaptoolshapeabstract.h - base class for map tools digitizing shapes + --------------------- + begin : January 2022 + copyright : (C) Denis Rouzaud + email : denis@opengis.ch + *************************************************************************** + * * + * 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 QGSMAPTOOLSHAPEABSTRACT_H +#define QGSMAPTOOLSHAPEABSTRACT_H + +// no bindings for now, not stable yet +#define SIP_NO_FILE + +#include "qgis_gui.h" +#include "qgsabstractgeometry.h" +#include "qgsmaptoolcapture.h" + +#include +#include + +class QgsMapMouseEvent; +class QgsVectorLayer; +class QgsGeometryRubberBand; +class QKeyEvent; + + +/** + * \ingroup gui + * \brief QgsMapToolShapeAbstract is a base class for shape map tools to be used by QgsMapToolCapture. + * \since QGIS 3.26 + */ +class GUI_EXPORT QgsMapToolShapeAbstract + : public QObject +{ + Q_OBJECT + public: + //! List of different shapes + enum class ShapeCategory + { + Curve, //!< Curve + Circle,//!< Circle + Ellipse,//!< Ellipse + Rectangle,//!< Rectangle + RegularPolygon,//!< RegularPolygon (e.g pentagons or hexagons) + }; + Q_ENUM( ShapeCategory ) + + //! Constructor + QgsMapToolShapeAbstract( const QString &id, QgsMapToolCapture *parentTool ) + : mId( id ), mParentTool( parentTool ) + { + Q_ASSERT( !mId.isEmpty() ); + Q_ASSERT( parentTool ); + } + + virtual ~QgsMapToolShapeAbstract(); + + //! Returns the id of the shape tool (equivalent to the one from the metadata) + QString id() const {return mId;} + + /** + * Called for a mouse release event + * Must return TRUE if the digitization has ended and the geometry is correctly set + */ + virtual bool cadCanvasReleaseEvent( QgsMapMouseEvent *e, QgsMapToolCapture::CaptureMode mode ) = 0; + + //! Called for a mouse move event + virtual void cadCanvasMoveEvent( QgsMapMouseEvent *e, QgsMapToolCapture::CaptureMode mode ) = 0; + + /** + * Filters a key press event + * Ignores the event in default implementation + */ + virtual void keyPressEvent( QKeyEvent *e ); + + /** + * Filters a key release event + * Ignores the event in default implementation + */ + virtual void keyReleaseEvent( QKeyEvent *e ); + + //! Activates the map tool with the last captured map point + virtual void activate( QgsMapToolCapture::CaptureMode mode, const QgsPoint &lastCapturedMapPoint ) {Q_UNUSED( mode ); Q_UNUSED( lastCapturedMapPoint )} + + //! Deactivates the map tool + virtual void deactivate() {clean();} + + //! Called to clean the map tool (after canceling the operation or when the digitization has finished) + virtual void clean(); + + //! Called to undo last action (last point added) + virtual void undo(); + + private: + QString mId; + + protected: + QgsMapToolCapture *mParentTool = nullptr; + + //! points (in map coordinates) + QgsPointSequence mPoints; + + QgsGeometryRubberBand *mTempRubberBand = nullptr; + +}; + + + +#endif // QGSMAPTOOLSHAPEABSTRACT_H diff --git a/src/gui/maptools/qgsmaptoolshaperegistry.cpp b/src/gui/maptools/qgsmaptoolshaperegistry.cpp new file mode 100644 index 000000000000..c2a4222ebe2b --- /dev/null +++ b/src/gui/maptools/qgsmaptoolshaperegistry.cpp @@ -0,0 +1,77 @@ +/*************************************************************************** + qgsmaptoolshaperegistry.cpp + ---------------------- + begin : January 2022 + copyright : (C) 2022 by Denis Rouzaud + email : denis@opengis.ch + ***************************************************************************/ + +/*************************************************************************** + * * + * 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 "qgsmaptoolshaperegistry.h" + + +QgsMapToolShapeRegistry::QgsMapToolShapeRegistry() +{ +} + +QgsMapToolShapeRegistry::~QgsMapToolShapeRegistry() +{ + qDeleteAll( mMapTools ); + mMapTools.clear(); +} + +void QgsMapToolShapeRegistry::addMapTool( QgsMapToolShapeMetadata *mapTool ) +{ + if ( !mapTool ) + return; + + if ( mapToolMetadata( mapTool->id() ) ) + return; + + mMapTools.append( mapTool ); +} + +void QgsMapToolShapeRegistry::removeMapTool( const QString &id ) +{ + QList::iterator it = mMapTools.begin(); + while ( it != mMapTools.end() ) + { + if ( ( *it )->id() == id ) + { + delete *it; + it = mMapTools.erase( it ); + } + else + { + ++it; + } + } +} + +QgsMapToolShapeMetadata *QgsMapToolShapeRegistry::mapToolMetadata( const QString &id ) const +{ + for ( QgsMapToolShapeMetadata *md : std::as_const( mMapTools ) ) + { + if ( md->id() == id ) + return md; + } + + return nullptr; +} + +QgsMapToolShapeAbstract *QgsMapToolShapeRegistry::mapTool( const QString &id, QgsMapToolCapture *parentTool ) const +{ + QgsMapToolShapeMetadata *md = mapToolMetadata( id ); + if ( !md ) + return nullptr; + + return md->factory( parentTool ); +} diff --git a/src/gui/maptools/qgsmaptoolshaperegistry.h b/src/gui/maptools/qgsmaptoolshaperegistry.h new file mode 100644 index 000000000000..aa95fe7d49e6 --- /dev/null +++ b/src/gui/maptools/qgsmaptoolshaperegistry.h @@ -0,0 +1,109 @@ +/*************************************************************************** + qgsmaptoolshaperegistry.h + ---------------------- + begin : January 2022 + copyright : (C) 2022 by Denis Rouzaud + email : denis@opengis.ch + ***************************************************************************/ + +/*************************************************************************** + * * + * 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 QGSMAPTOOLSHAPEREGISTRY_H +#define QGSMAPTOOLSHAPEREGISTRY_H + +#define SIP_NO_FILE + +#include "qgsabstractrelationeditorwidget.h" +#include "qgsmaptoolshapeabstract.h" +#include "qgis_gui.h" + +class QgsMapToolShapeMetadata; +class QgsMapToolCapture; + +/** + * \ingroup gui + * \brief Keeps track of the registered shape map tools + * \since QGIS 3.26 + */ +class GUI_EXPORT QgsMapToolShapeRegistry +{ + Q_GADGET + public: + + /** + * Constructor + */ + QgsMapToolShapeRegistry(); + + ~QgsMapToolShapeRegistry(); + + /** + * Adds a new shape map tool + */ + void addMapTool( QgsMapToolShapeMetadata *mapTool SIP_TRANSFER ); + + /** + * Removes a registered map tool at the given \a id + * The tool will be deleted. + */ + void removeMapTool( const QString &id ); + + //! Returns the list of map tools + QList mapToolMetadatas() const {return mMapTools;} + + //! Returns the map tool metadata for the given \a id + QgsMapToolShapeMetadata *mapToolMetadata( const QString &id ) const; + + /** + * Constructs the map tool at the given \a id for the given \a parentTool + * Caller takes ownership of the returned tool. + */ + QgsMapToolShapeAbstract *mapTool( const QString &id, QgsMapToolCapture *parentTool ) const SIP_FACTORY; + + private: + + QList mMapTools; + +}; + +/** + * \ingroup gui + * \brief QgsMapToolShapeMetadata is a base class for shape map tools metadata to be used in QgsMapToolShapeRegistry + * \since QGIS 3.26 + */ +class GUI_EXPORT QgsMapToolShapeMetadata +{ + public: + //! Constructor + QgsMapToolShapeMetadata() = default; + + virtual ~QgsMapToolShapeMetadata() = default; + + //! Unique ID for the shape map tool + virtual QString id() const = 0; + + //! Translated readable name + virtual QString name() const = 0; + + //! Icon to be displayed in the toolbar + virtual QIcon icon() const = 0; + + //! Returns the shape category of the tool + virtual QgsMapToolShapeAbstract::ShapeCategory category() const = 0; + + /** + * Creates the shape map tool for the given \a parentTool + * Caller takes ownership of the returned object. + */ + virtual QgsMapToolShapeAbstract *factory( QgsMapToolCapture *parentlTool ) const SIP_FACTORY = 0; +}; + + +#endif // QGSMAPTOOLSHAPEREGISTRY_H diff --git a/src/gui/qgisinterface.h b/src/gui/qgisinterface.h index 26ecc0808cdb..b9a739b02f97 100644 --- a/src/gui/qgisinterface.h +++ b/src/gui/qgisinterface.h @@ -610,38 +610,102 @@ class GUI_EXPORT QgisInterface : public QObject virtual QAction *actionAbout() = 0; // Shape digitize actions - //! Returns the native add circle from 2 points action. Call trigger() on it to set the map tool. - virtual QAction *actionCircle2Points() = 0; - //! Returns the native add circle from 3 points action. Call trigger() on it to set the map tool. - virtual QAction *actionCircle3Points() = 0; - //! Returns the native add circle from 3 tangents action. Call trigger() on it to set the map tool. - virtual QAction *actionCircle3Tangents() = 0; - //! Returns the native add circle from 2 tangents and a point action. Call trigger() on it to set the map tool. - virtual QAction *actionCircle2TangentsPoint() = 0; - //! Returns the native add circle from center action. Call trigger() on it to set the map tool. - virtual QAction *actionCircleCenterPoint() = 0; - //! Returns the native add ellipse from center and 2 points action. Call trigger() on it to set the map tool. - virtual QAction *actionEllipseCenter2Points() = 0; - //! Returns the native add ellipse from center and a point action. Call trigger() on it to set the map tool. - virtual QAction *actionEllipseCenterPoint() = 0; - //! Returns the native add ellipse from an extent action. Call trigger() on it to set the map tool. - virtual QAction *actionEllipseExtent() = 0; - //! Returns the native add ellipse from foci action. Call trigger() on it to set the map tool. - virtual QAction *actionEllipseFoci() = 0; - //! Returns the native add rectangle from center and a point action. Call trigger() on it to set the map tool. - virtual QAction *actionRectangleCenterPoint() = 0; - //! Returns the native add rectangle from extent action. Call trigger() on it to set the map tool. - virtual QAction *actionRectangleExtent() = 0; - //! Returns the native add rectangle from 3 points (distance from 2nd and 3rd points) action. Call trigger() on it to set the map tool. - virtual QAction *actionRectangle3PointsDistance() = 0; - //! Returns the native add rectangle from 3 points (distance from projected 3rd point on segment p1 and p2) action. Call trigger() on it to set the map tool. - virtual QAction *actionRectangle3PointsProjected() = 0; - //! Returns the native add regular polygon from 2 points action. Call trigger() on it to set the map tool. - virtual QAction *actionRegularPolygon2Points() = 0; - //! Returns the native add regular polygon from center and a point action. Call trigger() on it to set the map tool. - virtual QAction *actionRegularPolygonCenterPoint() = 0; - //! Returns the native add regular polygon from center and a corner action. Call trigger() on it to set the map tool. - virtual QAction *actionRegularPolygonCenterCorner() = 0; + + /** + * Returns the native add circle from 2 points action. Call trigger() on it to set the map tool. + * \deprecated since QGIS 3.26 shape digitizing is now part of the add feature tool. To enable the shape tool, use QgsMapToolCapture::setCurrentCaptureTechnique() and then QgsMapToolCapture::setCurrentShapeMapTool(). + */ + Q_DECL_DEPRECATED virtual QAction *actionCircle2Points() SIP_DEPRECATED {return actionAddFeature();} + + /** + * Returns the native add circle from 3 points action. Call trigger() on it to set the map tool. + * \deprecated since QGIS 3.26 shape digitizing is now part of the add feature tool. To enable the shape tool, use QgsMapToolCapture::setCurrentCaptureTechnique() and then QgsMapToolCapture::setCurrentShapeMapTool(). + */ + Q_DECL_DEPRECATED virtual QAction *actionCircle3Points() SIP_DEPRECATED {return actionAddFeature();} + + /** + * Returns the native add circle from 3 tangents action. Call trigger() on it to set the map tool. + * \deprecated since QGIS 3.26 shape digitizing is now part of the add feature tool. To enable the shape tool, use QgsMapToolCapture::setCurrentCaptureTechnique() and then QgsMapToolCapture::setCurrentShapeMapTool(). + */ + Q_DECL_DEPRECATED virtual QAction *actionCircle3Tangents() SIP_DEPRECATED {return actionAddFeature();} + + /** + * Returns the native add circle from 2 tangents and a point action. Call trigger() on it to set the map tool. + * \deprecated since QGIS 3.26 shape digitizing is now part of the add feature tool. To enable the shape tool, use QgsMapToolCapture::setCurrentCaptureTechnique() and then QgsMapToolCapture::setCurrentShapeMapTool(). + */ + Q_DECL_DEPRECATED virtual QAction *actionCircle2TangentsPoint() SIP_DEPRECATED {return actionAddFeature();} + + /** + * Returns the native add circle from center action. Call trigger() on it to set the map tool. + * \deprecated since QGIS 3.26 shape digitizing is now part of the add feature tool. To enable the shape tool, use QgsMapToolCapture::setCurrentCaptureTechnique() and then QgsMapToolCapture::setCurrentShapeMapTool(). + */ + Q_DECL_DEPRECATED virtual QAction *actionCircleCenterPoint() SIP_DEPRECATED {return actionAddFeature();} + + /** + * Returns the native add ellipse from center and 2 points action. Call trigger() on it to set the map tool. + * \deprecated since QGIS 3.26 shape digitizing is now part of the add feature tool. To enable the shape tool, use QgsMapToolCapture::setCurrentCaptureTechnique() and then QgsMapToolCapture::setCurrentShapeMapTool(). + */ + Q_DECL_DEPRECATED virtual QAction *actionEllipseCenter2Points() SIP_DEPRECATED {return actionAddFeature();} + + /** + * Returns the native add ellipse from center and a point action. Call trigger() on it to set the map tool. + * \deprecated since QGIS 3.26 shape digitizing is now part of the add feature tool. To enable the shape tool, use QgsMapToolCapture::setCurrentCaptureTechnique() and then QgsMapToolCapture::setCurrentShapeMapTool(). + */ + Q_DECL_DEPRECATED virtual QAction *actionEllipseCenterPoint() SIP_DEPRECATED {return actionAddFeature();} + + /** + * Returns the native add ellipse from an extent action. Call trigger() on it to set the map tool. + * \deprecated since QGIS 3.26 shape digitizing is now part of the add feature tool. To enable the shape tool, use QgsMapToolCapture::setCurrentCaptureTechnique() and then QgsMapToolCapture::setCurrentShapeMapTool(). + */ + Q_DECL_DEPRECATED virtual QAction *actionEllipseExtent() SIP_DEPRECATED {return actionAddFeature();} + + /** + * Returns the native add ellipse from foci action. Call trigger() on it to set the map tool. + * \deprecated since QGIS 3.26 shape digitizing is now part of the add feature tool. To enable the shape tool, use QgsMapToolCapture::setCurrentCaptureTechnique() and then QgsMapToolCapture::setCurrentShapeMapTool(). + */ + Q_DECL_DEPRECATED virtual QAction *actionEllipseFoci() SIP_DEPRECATED {return actionAddFeature();} + + /** + * Returns the native add rectangle from center and a point action. Call trigger() on it to set the map tool. + * \deprecated since QGIS 3.26 shape digitizing is now part of the add feature tool. To enable the shape tool, use QgsMapToolCapture::setCurrentCaptureTechnique() and then QgsMapToolCapture::setCurrentShapeMapTool(). + */ + Q_DECL_DEPRECATED virtual QAction *actionRectangleCenterPoint() SIP_DEPRECATED {return actionAddFeature();} + + /** + * Returns the native add rectangle from extent action. Call trigger() on it to set the map tool. + * \deprecated since QGIS 3.26 shape digitizing is now part of the add feature tool. To enable the shape tool, use QgsMapToolCapture::setCurrentCaptureTechnique() and then QgsMapToolCapture::setCurrentShapeMapTool(). + */ + Q_DECL_DEPRECATED virtual QAction *actionRectangleExtent() SIP_DEPRECATED {return actionAddFeature();} + + /** + * Returns the native add rectangle from 3 points (distance from 2nd and 3rd points) action. Call trigger() on it to set the map tool. + * \deprecated since QGIS 3.26 shape digitizing is now part of the add feature tool. To enable the shape tool, use QgsMapToolCapture::setCurrentCaptureTechnique() and then QgsMapToolCapture::setCurrentShapeMapTool(). + */ + Q_DECL_DEPRECATED virtual QAction *actionRectangle3PointsDistance() SIP_DEPRECATED {return actionAddFeature();} + + /** + * Returns the native add rectangle from 3 points (distance from projected 3rd point on segment p1 and p2) action. Call trigger() on it to set the map tool. + * \deprecated since QGIS 3.26 shape digitizing is now part of the add feature tool. To enable the shape tool, use QgsMapToolCapture::setCurrentCaptureTechnique() and then QgsMapToolCapture::setCurrentShapeMapTool(). + */ + Q_DECL_DEPRECATED virtual QAction *actionRectangle3PointsProjected() SIP_DEPRECATED {return actionAddFeature();} + + /** + * Returns the native add regular polygon from 2 points action. Call trigger() on it to set the map tool. + * \deprecated since QGIS 3.26 shape digitizing is now part of the add feature tool. To enable the shape tool, use QgsMapToolCapture::setCurrentCaptureTechnique() and then QgsMapToolCapture::setCurrentShapeMapTool(). + */ + Q_DECL_DEPRECATED virtual QAction *actionRegularPolygon2Points() SIP_DEPRECATED {return actionAddFeature();} + + /** + * Returns the native add regular polygon from center and a point action. Call trigger() on it to set the map tool. + * \deprecated since QGIS 3.26 shape digitizing is now part of the add feature tool. To enable the shape tool, use QgsMapToolCapture::setCurrentCaptureTechnique() and then QgsMapToolCapture::setCurrentShapeMapTool(). + */ + Q_DECL_DEPRECATED virtual QAction *actionRegularPolygonCenterPoint() SIP_DEPRECATED {return actionAddFeature();} + + /** + * Returns the native add regular polygon from center and a corner action. Call trigger() on it to set the map tool. + * \deprecated since QGIS 3.26 shape digitizing is now part of the add feature tool. To enable the shape tool, use QgsMapToolCapture::setCurrentCaptureTechnique() and then QgsMapToolCapture::setCurrentShapeMapTool(). + */ + Q_DECL_DEPRECATED virtual QAction *actionRegularPolygonCenterCorner() SIP_DEPRECATED {return actionAddFeature();} /** * Access the vector layer tools instance. diff --git a/src/gui/qgsgui.cpp b/src/gui/qgsgui.cpp index ffa987000198..0076d75a38b3 100644 --- a/src/gui/qgsgui.cpp +++ b/src/gui/qgsgui.cpp @@ -62,6 +62,7 @@ #include "qgssubsetstringeditorproviderregistry.h" #include "qgsprovidersourcewidgetproviderregistry.h" #include "qgsrelationwidgetregistry.h" +#include "qgsmaptoolshaperegistry.h" #include "qgssettingsregistrygui.h" #include "qgshistoryproviderregistry.h" @@ -91,6 +92,11 @@ QgsRelationWidgetRegistry *QgsGui::relationWidgetRegistry() return instance()->mRelationEditorRegistry; } +QgsMapToolShapeRegistry *QgsGui::mapToolShapeRegistry() +{ + return instance()->mShapeMapToolRegistry; +} + QgsSourceSelectProviderRegistry *QgsGui::sourceSelectProviderRegistry() { return instance()->mSourceSelectProviderRegistry; @@ -223,6 +229,7 @@ QgsGui::~QgsGui() delete mCodeEditorColorSchemeRegistry; delete mSubsetStringEditorProviderRegistry; delete mProviderSourceWidgetProviderRegistry; + delete mShapeMapToolRegistry; delete mRelationEditorRegistry; delete mSettingsRegistryGui; } @@ -294,6 +301,7 @@ QgsGui::QgsGui() mEditorWidgetRegistry = new QgsEditorWidgetRegistry(); mRelationEditorRegistry = new QgsRelationWidgetRegistry(); + mShapeMapToolRegistry = new QgsMapToolShapeRegistry(); mShortcutsManager = new QgsShortcutsManager(); mLayerTreeEmbeddedWidgetRegistry = new QgsLayerTreeEmbeddedWidgetRegistry(); mMapLayerActionRegistry = new QgsMapLayerActionRegistry(); diff --git a/src/gui/qgsgui.h b/src/gui/qgsgui.h index 7d7971cc2b3a..b6294b0dcf98 100644 --- a/src/gui/qgsgui.h +++ b/src/gui/qgsgui.h @@ -45,6 +45,7 @@ class QgsMessageBar; class QgsSubsetStringEditorProviderRegistry; class QgsProviderSourceWidgetProviderRegistry; class QgsRelationWidgetRegistry; +class QgsMapToolShapeRegistry; class QgsHistoryProviderRegistry; /** @@ -191,6 +192,12 @@ class GUI_EXPORT QgsGui : public QObject */ static QgsRelationWidgetRegistry *relationWidgetRegistry() SIP_KEEPREFERENCE; + /** + * Returns the registry of shape map tools + * \note Not available in Python bindings + * \since QGIS 3.26 + */ + static QgsMapToolShapeRegistry *mapToolShapeRegistry() SIP_SKIP; /** * Returns the global history provider registry, used for tracking history providers. @@ -304,6 +311,7 @@ class GUI_EXPORT QgsGui : public QObject QgsSubsetStringEditorProviderRegistry *mSubsetStringEditorProviderRegistry = nullptr; QgsProviderSourceWidgetProviderRegistry *mProviderSourceWidgetProviderRegistry = nullptr; QgsRelationWidgetRegistry *mRelationEditorRegistry = nullptr; + QgsMapToolShapeRegistry *mShapeMapToolRegistry = nullptr; QgsHistoryProviderRegistry *mHistoryProviderRegistry = nullptr; std::unique_ptr< QgsWindowManagerInterface > mWindowManager; diff --git a/src/gui/qgsmaptool.h b/src/gui/qgsmaptool.h index d96c0c80399a..b10f4b56abd5 100644 --- a/src/gui/qgsmaptool.h +++ b/src/gui/qgsmaptool.h @@ -261,6 +261,9 @@ class GUI_EXPORT QgsMapTool : public QObject */ virtual bool populateContextMenuWithEvent( QMenu *menu, QgsMapMouseEvent *event ); + //! Transforms a \a point from screen coordinates to map coordinates. + QgsPointXY toMapCoordinates( QPoint point ); + signals: //! emit a message void messageEmitted( const QString &message, Qgis::MessageLevel = Qgis::MessageLevel::Info ); @@ -283,9 +286,6 @@ class GUI_EXPORT QgsMapTool : public QObject //! Constructor takes a map canvas as a parameter. QgsMapTool( QgsMapCanvas *canvas SIP_TRANSFERTHIS ); - //! Transforms a \a point from screen coordinates to map coordinates. - QgsPointXY toMapCoordinates( QPoint point ); - /** * Transforms a \a point from map coordinates to \a layer coordinates. * \note This method is available in the Python bindings as toLayerCoordinatesV2. diff --git a/src/gui/qgsmaptoolcapture.cpp b/src/gui/qgsmaptoolcapture.cpp index 8fea78be5f98..9beac21619c5 100644 --- a/src/gui/qgsmaptoolcapture.cpp +++ b/src/gui/qgsmaptoolcapture.cpp @@ -33,6 +33,9 @@ #include "qgsadvanceddigitizingdockwidget.h" #include "qgsproject.h" #include "qgsmaptoolcapturerubberband.h" +#include "qgsmaptoolshapeabstract.h" +#include "qgsmaptoolshaperegistry.h" +#include "qgsgui.h" #include #include @@ -93,7 +96,15 @@ QgsMapToolCapture::Capabilities QgsMapToolCapture::capabilities() const bool QgsMapToolCapture::supportsTechnique( QgsMapToolCapture::CaptureTechnique technique ) const { - return technique == StraightSegments; + switch ( technique ) + { + case CaptureTechnique::StraightSegments: + return true; + case CaptureTechnique::CircularString: + case CaptureTechnique::Streaming: + case CaptureTechnique::Shape: + return false; + } } void QgsMapToolCapture::activate() @@ -103,6 +114,9 @@ void QgsMapToolCapture::activate() mCanvas->snappingUtils()->addExtraSnapLayer( mExtraSnapLayer ); QgsMapToolAdvancedDigitizing::activate(); + + if ( mCurrentCaptureTechnique == Shape && mCurrentShapeMapTool ) + mCurrentShapeMapTool->activate( mCaptureMode, mCaptureLastPoint ); } void QgsMapToolCapture::deactivate() @@ -113,6 +127,10 @@ void QgsMapToolCapture::deactivate() mSnapIndicator->setMatch( QgsPointLocator::Match() ); mCanvas->snappingUtils()->removeExtraSnapLayer( mExtraSnapLayer ); + + if ( mCurrentCaptureTechnique == Shape && mCurrentShapeMapTool ) + mCurrentShapeMapTool->deactivate(); + QgsMapToolAdvancedDigitizing::deactivate(); } @@ -278,7 +296,7 @@ bool QgsMapToolCapture::tracingAddVertex( const QgsPointXY &point ) mSnappingMatches.append( QgsPointLocator::Match() ); int pointBefore = mCaptureCurve.numPoints(); - mCaptureCurve.addCurve( new QgsLineString( layerPoints ) ); + addCurve( new QgsLineString( layerPoints ) ); resetRubberBand(); @@ -345,93 +363,178 @@ QgsRubberBand *QgsMapToolCapture::takeRubberBand() void QgsMapToolCapture::setCircularDigitizingEnabled( bool enable ) { - mDigitizingType = enable ? QgsWkbTypes::CircularString : QgsWkbTypes::LineString; - if ( mTempRubberBand ) - mTempRubberBand->setStringType( mDigitizingType ); + if ( enable ) + setCurrentCaptureTechnique( CaptureTechnique::CircularString ); + else + setCurrentCaptureTechnique( CaptureTechnique::StraightSegments ); } void QgsMapToolCapture::setStreamDigitizingEnabled( bool enable ) { - mStreamingEnabled = enable; - mStartNewCurve = true; if ( enable ) + setCurrentCaptureTechnique( CaptureTechnique::Streaming ); + else + setCurrentCaptureTechnique( CaptureTechnique::StraightSegments ); +} + +void QgsMapToolCapture::setCurrentCaptureTechnique( CaptureTechnique technique ) +{ + if ( mCurrentCaptureTechnique == technique ) + return; + + mStartNewCurve = true; + + if ( mCurrentCaptureTechnique == CaptureTechnique::Shape && mCurrentShapeMapTool ) + { + mCurrentShapeMapTool->deactivate(); + clean(); + } + + switch ( technique ) + { + case QgsMapToolCapture::CaptureTechnique::StraightSegments: + mLineDigitizingType = QgsWkbTypes::LineString; + break; + case QgsMapToolCapture::CaptureTechnique::CircularString: + mLineDigitizingType = QgsWkbTypes::CircularString; + break; + case QgsMapToolCapture::CaptureTechnique::Streaming: + mLineDigitizingType = QgsWkbTypes::LineString; + mStreamingToleranceInPixels = QgsSettingsRegistryCore::settingsDigitizingStreamTolerance.value(); + break; + case QgsMapToolCapture::CaptureTechnique::Shape: + mLineDigitizingType = QgsWkbTypes::LineString; + break; + + } + + if ( mTempRubberBand ) + mTempRubberBand->setStringType( mLineDigitizingType ); + + mCurrentCaptureTechnique = technique; + + if ( technique == CaptureTechnique::Shape && mCurrentShapeMapTool && isActive() ) + { + clean(); + mCurrentShapeMapTool->activate( mCaptureMode, mCaptureLastPoint ); + } +} + +void QgsMapToolCapture::setCurrentShapeMapTool( const QgsMapToolShapeMetadata *shapeMapToolMetadata ) +{ + if ( mCurrentShapeMapTool ) + { + if ( shapeMapToolMetadata && mCurrentShapeMapTool->id() == shapeMapToolMetadata->id() ) + return; + if ( mCurrentCaptureTechnique == CaptureTechnique::Shape ) + mCurrentShapeMapTool->deactivate(); + mCurrentShapeMapTool->deleteLater(); + } + + mCurrentShapeMapTool = shapeMapToolMetadata ? shapeMapToolMetadata->factory( this ) : nullptr; + + if ( mCurrentCaptureTechnique == CaptureTechnique::Shape && isActive() ) { - mStreamingToleranceInPixels = QgsSettingsRegistryCore::settingsDigitizingStreamTolerance.value(); + clean(); + mCurrentShapeMapTool->activate( mCaptureMode, mCaptureLastPoint ); } } void QgsMapToolCapture::cadCanvasMoveEvent( QgsMapMouseEvent *e ) { QgsMapToolAdvancedDigitizing::cadCanvasMoveEvent( e ); + const QgsPointXY point = e->mapPoint(); mSnapIndicator->setMatch( e->mapPointMatch() ); - const QgsPoint mapPoint = QgsPoint( point ); - - if ( mCaptureMode != CapturePoint && mTempRubberBand && mCapturing ) + if ( mCurrentCaptureTechnique == Shape ) { - bool hasTrace = false; - - if ( mStreamingEnabled ) + if ( !mCurrentShapeMapTool ) + { + emit messageEmitted( tr( "Cannot capture a shape without a shape tool defined" ), Qgis::MessageLevel::Warning ); + } + else { - if ( !mCaptureCurve.isEmpty() ) + if ( !mTempRubberBand ) { - const QgsPoint prevPoint = mCaptureCurve.curveAt( mCaptureCurve.nCurves() - 1 )->endPoint(); - if ( QgsPointXY( toCanvasCoordinates( toMapCoordinates( layer(), prevPoint ) ) ).distance( toCanvasCoordinates( point ) ) < mStreamingToleranceInPixels ) - return; + mTempRubberBand.reset( createCurveRubberBand() ); + mTempRubberBand->setStringType( mLineDigitizingType ); + mTempRubberBand->setRubberBandGeometryType( mCaptureMode == CapturePolygon ? QgsWkbTypes::PolygonGeometry : QgsWkbTypes::LineGeometry ); } - mAllowAddingStreamingPoints = true; - addVertex( mapPoint ); - mAllowAddingStreamingPoints = false; + mCurrentShapeMapTool->cadCanvasMoveEvent( e, mCaptureMode ); + return; } - else if ( tracingEnabled() && mCaptureCurve.numPoints() != 0 ) + } + else + { + const QgsPoint mapPoint = QgsPoint( point ); + + if ( mCaptureMode != CapturePoint && mTempRubberBand && mCapturing ) { - // Store the intermediate point for circular string to retrieve after tracing mouse move if - // the digitizing type is circular and the temp rubber band is effectivly circular and if this point is existing - // Store an empty point if the digitizing type is linear ot the point is not existing (curve not complete) - if ( mDigitizingType == QgsWkbTypes::CircularString && - mTempRubberBand->stringType() == QgsWkbTypes::CircularString && - mTempRubberBand->curveIsComplete() ) - mCircularItermediatePoint = mTempRubberBand->pointFromEnd( 1 ); - else if ( mDigitizingType == QgsWkbTypes::LineString || - !mTempRubberBand->curveIsComplete() ) - mCircularItermediatePoint = QgsPoint(); - - hasTrace = tracingMouseMove( e ); - - if ( !hasTrace ) + bool hasTrace = false; + + if ( mCurrentCaptureTechnique == CaptureTechnique::Streaming ) { - // Restore the temp rubber band - mTempRubberBand->reset( mCaptureMode == CapturePolygon ? QgsWkbTypes::PolygonGeometry : QgsWkbTypes::LineGeometry, mDigitizingType, mCaptureFirstPoint ); - mTempRubberBand->addPoint( mCaptureLastPoint ); - if ( !mCircularItermediatePoint.isEmpty() ) + if ( !mCaptureCurve.isEmpty() ) { - mTempRubberBand->movePoint( mCircularItermediatePoint ); - mTempRubberBand->addPoint( mCircularItermediatePoint ); + const QgsPoint prevPoint = mCaptureCurve.curveAt( mCaptureCurve.nCurves() - 1 )->endPoint(); + if ( QgsPointXY( toCanvasCoordinates( toMapCoordinates( layer(), prevPoint ) ) ).distance( toCanvasCoordinates( point ) ) < mStreamingToleranceInPixels ) + return; } - } - } - if ( !mStreamingEnabled && !hasTrace ) - { - if ( mCaptureCurve.numPoints() > 0 ) + mAllowAddingStreamingPoints = true; + addVertex( mapPoint ); + mAllowAddingStreamingPoints = false; + } + else if ( tracingEnabled() && mCaptureCurve.numPoints() != 0 ) { - const QgsPoint mapPt = mCaptureLastPoint; - - if ( mTempRubberBand ) + // Store the intermediate point for circular string to retrieve after tracing mouse move if + // the digitizing type is circular and the temp rubber band is effectivly circular and if this point is existing + // Store an empty point if the digitizing type is linear ot the point is not existing (curve not complete) + if ( mLineDigitizingType == QgsWkbTypes::CircularString && + mTempRubberBand->stringType() == QgsWkbTypes::CircularString && + mTempRubberBand->curveIsComplete() ) + mCircularItermediatePoint = mTempRubberBand->pointFromEnd( 1 ); + else if ( mLineDigitizingType == QgsWkbTypes::LineString || + !mTempRubberBand->curveIsComplete() ) + mCircularItermediatePoint = QgsPoint(); + + hasTrace = tracingMouseMove( e ); + + if ( !hasTrace ) { - mTempRubberBand->movePoint( mapPoint ); - mTempRubberBand->movePoint( 0, mapPt ); + // Restore the temp rubber band + mTempRubberBand->reset( mCaptureMode == CapturePolygon ? QgsWkbTypes::PolygonGeometry : QgsWkbTypes::LineGeometry, mLineDigitizingType, mCaptureFirstPoint ); + mTempRubberBand->addPoint( mCaptureLastPoint ); + if ( !mCircularItermediatePoint.isEmpty() ) + { + mTempRubberBand->movePoint( mCircularItermediatePoint ); + mTempRubberBand->addPoint( mCircularItermediatePoint ); + } } + } + + if ( mCurrentCaptureTechnique != CaptureTechnique::Streaming && !hasTrace ) + { + if ( mCaptureCurve.numPoints() > 0 ) + { + const QgsPoint mapPt = mCaptureLastPoint; + + if ( mTempRubberBand ) + { + mTempRubberBand->movePoint( mapPoint ); + mTempRubberBand->movePoint( 0, mapPt ); + } - // fix existing rubber band after tracing - the last point may have been moved if using offset - if ( mRubberBand->numberOfVertices() ) - mRubberBand->movePoint( mapPt ); + // fix existing rubber band after tracing - the last point may have been moved if using offset + if ( mRubberBand->numberOfVertices() ) + mRubberBand->movePoint( mapPt ); + } + else if ( mTempRubberBand ) + mTempRubberBand->movePoint( mapPoint ); } - else if ( mTempRubberBand ) - mTempRubberBand->movePoint( mapPoint ); } } } // mouseMoveEvent @@ -555,7 +658,7 @@ int QgsMapToolCapture::addVertex( const QgsPointXY &point, const QgsPointLocator return 2; } - if ( mCapturing && mStreamingEnabled && !mAllowAddingStreamingPoints ) + if ( mCapturing && mCurrentCaptureTechnique == CaptureTechnique::Streaming && !mAllowAddingStreamingPoints ) return 0; QgsPoint layerPoint; @@ -591,8 +694,8 @@ int QgsMapToolCapture::addVertex( const QgsPointXY &point, const QgsPointLocator if ( !mTempRubberBand ) { mTempRubberBand.reset( createCurveRubberBand() ); - mTempRubberBand->setStringType( mDigitizingType ); - mTempRubberBand->reset( mCaptureMode == CapturePolygon ? QgsWkbTypes::PolygonGeometry : QgsWkbTypes::LineGeometry, mDigitizingType, mapPoint ); + mTempRubberBand->setStringType( mLineDigitizingType ); + mTempRubberBand->reset( mCaptureMode == CapturePolygon ? QgsWkbTypes::PolygonGeometry : QgsWkbTypes::LineGeometry, mLineDigitizingType, mapPoint ); } bool traceCreated = false; @@ -630,7 +733,7 @@ int QgsMapToolCapture::addVertex( const QgsPointXY &point, const QgsPointLocator } } mCaptureLastPoint = mapPoint; - mTempRubberBand->reset( mCaptureMode == CapturePolygon ? QgsWkbTypes::PolygonGeometry : QgsWkbTypes::LineGeometry, mDigitizingType, mCaptureFirstPoint ); + mTempRubberBand->reset( mCaptureMode == CapturePolygon ? QgsWkbTypes::PolygonGeometry : QgsWkbTypes::LineGeometry, mLineDigitizingType, mCaptureFirstPoint ); } else if ( mTempRubberBand->pointsCount() == 0 ) { @@ -650,7 +753,7 @@ int QgsMapToolCapture::addVertex( const QgsPointXY &point, const QgsPointLocator } else { - mTempRubberBand->reset( mCaptureMode == CapturePolygon ? QgsWkbTypes::PolygonGeometry : QgsWkbTypes::LineGeometry, mDigitizingType, mCaptureFirstPoint ); + mTempRubberBand->reset( mCaptureMode == CapturePolygon ? QgsWkbTypes::PolygonGeometry : QgsWkbTypes::LineGeometry, mLineDigitizingType, mCaptureFirstPoint ); mTempRubberBand->addPoint( mCaptureLastPoint ); } } @@ -675,7 +778,7 @@ int QgsMapToolCapture::addCurve( QgsCurve *c ) if ( mTempRubberBand ) { - mTempRubberBand->reset( mCaptureMode == CapturePolygon ? QgsWkbTypes::PolygonGeometry : QgsWkbTypes::LineGeometry, mDigitizingType, mCaptureFirstPoint ); + mTempRubberBand->reset( mCaptureMode == CapturePolygon ? QgsWkbTypes::PolygonGeometry : QgsWkbTypes::LineGeometry, mLineDigitizingType, mCaptureFirstPoint ); const QgsPoint endPt = c->endPoint(); mTempRubberBand->addPoint( endPt ); //add last point of c } @@ -778,7 +881,7 @@ void QgsMapToolCapture::undo( bool isAutoRepeat ) resetRubberBand(); - mTempRubberBand->reset( mCaptureMode == CapturePolygon ? QgsWkbTypes::PolygonGeometry : QgsWkbTypes::LineGeometry, mDigitizingType, mCaptureFirstPoint ); + mTempRubberBand->reset( mCaptureMode == CapturePolygon ? QgsWkbTypes::PolygonGeometry : QgsWkbTypes::LineGeometry, mLineDigitizingType, mCaptureFirstPoint ); if ( mCaptureCurve.numPoints() > 0 ) { @@ -795,15 +898,42 @@ void QgsMapToolCapture::undo( bool isAutoRepeat ) void QgsMapToolCapture::keyPressEvent( QKeyEvent *e ) { + if ( mCurrentCaptureTechnique == Shape && mCurrentShapeMapTool ) + { + mCurrentShapeMapTool->keyPressEvent( e ); + if ( e->isAccepted() ) + return; + } + + // this is backwards, but we can't change now without breaking api because + // forever QgsMapTools have had to explicitly mark events as ignored in order to + // indicate that they've consumed the event and that the default behavior should not + // be applied..! + // see QgsMapCanvas::keyPressEvent + e->accept(); + if ( e->key() == Qt::Key_Backspace || e->key() == Qt::Key_Delete ) { - undo( e->isAutoRepeat() ); + if ( mCurrentCaptureTechnique == Shape && mCurrentShapeMapTool ) + { + if ( !e->isAutoRepeat() ) + { + mCurrentShapeMapTool->undo(); + } + } + else + { + undo( e->isAutoRepeat() ); + } // Override default shortcut management in MapCanvas e->ignore(); } else if ( e->key() == Qt::Key_Escape ) { + if ( mCurrentShapeMapTool ) + mCurrentShapeMapTool->clean(); + stopCapturing(); // Override default shortcut management in MapCanvas @@ -852,6 +982,9 @@ void QgsMapToolCapture::deleteTempRubberBand() void QgsMapToolCapture::clean() { stopCapturing(); + if ( mCurrentCaptureTechnique == Shape && mCurrentShapeMapTool ) + mCurrentShapeMapTool->clean(); + clearCurve(); } @@ -1073,3 +1206,159 @@ void QgsMapToolCapture::updateExtraSnapLayer() } } + +void QgsMapToolCapture::cadCanvasReleaseEvent( QgsMapMouseEvent *e ) +{ + // POINT CAPTURING + if ( mode() == CapturePoint ) + { + if ( e->button() != Qt::LeftButton ) + return; + + QgsPoint savePoint; //point in layer coordinates + bool isMatchPointZ = false; + bool isMatchPointM = false; + try + { + QgsPoint fetchPoint; + int res = fetchLayerPoint( e->mapPointMatch(), fetchPoint ); + isMatchPointZ = QgsWkbTypes::hasZ( fetchPoint.wkbType() ); + isMatchPointM = QgsWkbTypes::hasM( fetchPoint.wkbType() ); + + if ( res == 0 ) + { + QgsWkbTypes::Type geomType = QgsWkbTypes::Type::Point; + if ( isMatchPointM && isMatchPointZ ) + { + geomType = QgsWkbTypes::Type::PointZM; + } + else if ( isMatchPointM ) + { + geomType = QgsWkbTypes::Type::PointM; + } + else if ( isMatchPointZ ) + { + geomType = QgsWkbTypes::Type::PointZ; + } + savePoint = QgsPoint( geomType, fetchPoint.x(), fetchPoint.y(), fetchPoint.z(), fetchPoint.m() ); + } + else + { + QgsPointXY point = mCanvas->mapSettings().mapToLayerCoordinates( layer(), e->mapPoint() ); + + savePoint = QgsPoint( point.x(), point.y(), fetchPoint.z(), fetchPoint.m() ); + } + } + catch ( QgsCsException &cse ) + { + Q_UNUSED( cse ) + emit messageEmitted( tr( "Cannot transform the point to the layer's coordinate system" ), Qgis::MessageLevel::Warning ); + return; + } + + QgsGeometry g( std::make_unique( savePoint ) ); + + // The snapping result needs to be added so it's available in the @snapping_results variable of default value etc. expression contexts + addVertex( e->mapPoint(), e->mapPointMatch() ); + + geometryCaptured( g ); + pointCaptured( savePoint ); + + stopCapturing(); + + // we are done with digitizing for now so instruct advanced digitizing dock to reset its CAD points + cadDockWidget()->clearPoints(); + } + + // LINE AND POLYGON CAPTURING + else if ( mode() == CaptureLine || mode() == CapturePolygon ) + { + bool digitizingFinished = false; + + if ( mCurrentCaptureTechnique == Shape ) + { + if ( !mCurrentShapeMapTool ) + { + emit messageEmitted( tr( "Cannot capture a shape without a shape tool defined" ), Qgis::MessageLevel::Warning ); + return; + } + else + { + if ( !mTempRubberBand ) + { + mTempRubberBand.reset( createCurveRubberBand() ); + mTempRubberBand->setStringType( mLineDigitizingType ); + mTempRubberBand->setRubberBandGeometryType( mCaptureMode == CapturePolygon ? QgsWkbTypes::PolygonGeometry : QgsWkbTypes::LineGeometry ); + } + + digitizingFinished = mCurrentShapeMapTool->cadCanvasReleaseEvent( e, mCaptureMode ); + if ( digitizingFinished ) + mCurrentShapeMapTool->clean(); + } + } + else // i.e. not shape + { + //add point to list and to rubber band + if ( e->button() == Qt::LeftButton ) + { + const int error = addVertex( e->mapPoint(), e->mapPointMatch() ); + if ( error == 2 ) + { + //problem with coordinate transformation + emit messageEmitted( tr( "Cannot transform the point to the layers coordinate system" ), Qgis::MessageLevel::Warning ); + return; + } + + startCapturing(); + } + else if ( e->button() == Qt::RightButton ) + { + // End of string + deleteTempRubberBand(); + + //lines: bail out if there are not at least two vertices + if ( mode() == CaptureLine && size() < 2 ) + { + stopCapturing(); + return; + } + + //polygons: bail out if there are not at least two vertices + if ( mode() == CapturePolygon && size() < 3 ) + { + stopCapturing(); + return; + } + + if ( mode() == CapturePolygon || e->modifiers() == Qt::ShiftModifier ) + { + closePolygon(); + } + + digitizingFinished = true; + } + } + + if ( digitizingFinished ) + { + QgsGeometry g; + QgsCurve *curveToAdd = captureCurve()->clone(); + + if ( mode() == CaptureLine ) + { + geometryCaptured( QgsGeometry( curveToAdd ) ); + lineCaptured( curveToAdd ); + } + else + { + QgsCurvePolygon *poly = new QgsCurvePolygon(); + poly->setExteriorRing( curveToAdd ); + g = QgsGeometry( poly ); + geometryCaptured( g ); + polygonCaptured( poly ); + } + + stopCapturing(); + } + } +} diff --git a/src/gui/qgsmaptoolcapture.h b/src/gui/qgsmaptoolcapture.h index 8457ec4c848a..c76db299c43b 100644 --- a/src/gui/qgsmaptoolcapture.h +++ b/src/gui/qgsmaptoolcapture.h @@ -34,11 +34,17 @@ class QgsVertexMarker; class QgsMapLayer; class QgsGeometryValidator; class QgsMapToolCaptureRubberBand; +class QgsCurvePolygon; +class QgsMapToolShapeAbstract; +class QgsMapToolShapeMetadata; /** * \ingroup gui - * \class QgsMapToolCapture + * QgsMapToolCapture is a base class capable of capturing point, lines and polygons. + * The tool supports different techniques: straight segments, curves, streaming and shapes + * Once the the geometry is captured the virtual private handler geometryCaptured is called + * as well as a more specific handler (pointCaptured, lineCaptured or polygonCaptured) */ class GUI_EXPORT QgsMapToolCapture : public QgsMapToolAdvancedDigitizing { @@ -65,7 +71,9 @@ class GUI_EXPORT QgsMapToolCapture : public QgsMapToolAdvancedDigitizing StraightSegments, //!< Default capture mode - capture occurs with straight line segments CircularString, //!< Capture in circular strings Streaming, //!< Streaming points digitizing mode (points are automatically added as the mouse cursor moves). Since QGIS 3.20. + Shape, //!< Digitize shapes. Since QGIS 3.26. }; + Q_ENUM( CaptureTechnique ) //! Specific capabilities of the tool enum Capability @@ -94,6 +102,19 @@ class GUI_EXPORT QgsMapToolCapture : public QgsMapToolAdvancedDigitizing */ virtual bool supportsTechnique( CaptureTechnique technique ) const; + /** + * Sets the current capture if it is supported by the map tool + * \since QGIS 3.26 + */ + void setCurrentCaptureTechnique( CaptureTechnique technique ); + + /** + * Sets the current shape tool + * \see QgsMapToolShapeRegistry + * \since QGIS 3.26 + */ + void setCurrentShapeMapTool( const QgsMapToolShapeMetadata *shapeMapToolMetadata ) SIP_SKIP; + void activate() override; void deactivate() override; @@ -129,6 +150,7 @@ class GUI_EXPORT QgsMapToolCapture : public QgsMapToolAdvancedDigitizing QList snappingMatches() const; void cadCanvasMoveEvent( QgsMapMouseEvent *e ) override; + void cadCanvasReleaseEvent( QgsMapMouseEvent *e ) override; /** * Intercept key events like Esc or Del to delete the last point @@ -152,15 +174,47 @@ class GUI_EXPORT QgsMapToolCapture : public QgsMapToolAdvancedDigitizing */ QgsRubberBand *takeRubberBand() SIP_FACTORY; + /** + * Creates a QgsPoint with ZM support if necessary (according to the + * WkbType of the current layer). If the point is snapped, then the Z + * value is derived from the snapped point. + * + * \param e A mouse event + * + * \returns a point with ZM support if necessary + * + * \since QGIS 3.0 + */ + QgsPoint mapPoint( const QgsMapMouseEvent &e ) const; + + /** + * Creates a QgsPoint with ZM support if necessary (according to the + * WkbType of the current layer). + * + * \param point A point in 2D + * + * \returns a point with ZM support if necessary + * + * \since QGIS 3.0 + */ + QgsPoint mapPoint( const QgsPointXY &point ) const; + + // TODO QGIS 4.0 returns an enum instead of a magic constant + public slots: - //! Enable the digitizing with curve - void setCircularDigitizingEnabled( bool enable ); + + /** + * Enable the digitizing with curve + * \deprecated since QGIS 3.26 use setCurrentCaptureTechnique() instead + */ + Q_DECL_DEPRECATED void setCircularDigitizingEnabled( bool enable ) SIP_DEPRECATED; /** * Toggles the stream digitizing mode. * \since QGIS 3.20 + * \deprecated since QGIS 3.26 use setCurrentCaptureTechnique() instead */ - void setStreamDigitizingEnabled( bool enable ); + Q_DECL_DEPRECATED void setStreamDigitizingEnabled( bool enable ) SIP_DEPRECATED; private slots: void addError( const QgsGeometry::Error &error ); @@ -207,33 +261,6 @@ class GUI_EXPORT QgsMapToolCapture : public QgsMapToolAdvancedDigitizing */ int fetchLayerPoint( const QgsPointLocator::Match &match, QgsPoint &layerPoint ); - /** - * Creates a QgsPoint with ZM support if necessary (according to the - * WkbType of the current layer). If the point is snapped, then the Z - * value is took from the snapped point. - * - * \param e A mouse event - * - * \returns a point with ZM support if necessary - * - * \since QGIS 3.0 - */ - QgsPoint mapPoint( const QgsMapMouseEvent &e ) const; - - /** - * Creates a QgsPoint with ZM support if necessary (according to the - * WkbType of the current layer). - * - * \param point A point in 2D - * - * \returns a point with ZM support if necessary - * - * \since QGIS 3.0 - */ - QgsPoint mapPoint( const QgsPointXY &point ) const; - - // TODO QGIS 4.0 returns an enum instead of a magic constant - /** * Adds a point to the rubber band (in map coordinates) and to the capture list (in layer coordinates) * \returns 0 in case of success, 2 if coordinate transformation failed @@ -320,6 +347,35 @@ class GUI_EXPORT QgsMapToolCapture : public QgsMapToolAdvancedDigitizing void stopCapturing(); private: + + /** + * Called when the geometry is captured + * A more specific handler is also called afterwards (pointCaptured, lineCaptured or polygonCaptured) + * \since QGIS 3.26 + */ + virtual void geometryCaptured( const QgsGeometry &geometry ) {Q_UNUSED( geometry )} SIP_FORCE + + /** + * Called when a point is captured + * geometryCaptured is called just before + * \since QGIS 3.26 + */ + virtual void pointCaptured( const QgsPoint &point ) {Q_UNUSED( point )} SIP_FORCE + + /** + * Called when a line is captured + * geometryCaptured is called just before + * \since QGIS 3.26 + */ + virtual void lineCaptured( const QgsCurve *line ) {Q_UNUSED( line )} SIP_FORCE + + /** + * Called when a polygon is captured + * geometryCaptured is called just before + * \since QGIS 3.26 + */ + virtual void polygonCaptured( const QgsCurvePolygon *polygon ) {Q_UNUSED( polygon )} SIP_FORCE + //! whether tracing has been requested by the user bool tracingEnabled(); //! first point that will be used as a start of the trace @@ -335,7 +391,6 @@ class GUI_EXPORT QgsMapToolCapture : public QgsMapToolAdvancedDigitizing //! Reset the void resetRubberBand(); - private: //! The capture mode in which this tool operates CaptureMode mCaptureMode; @@ -382,9 +437,12 @@ class GUI_EXPORT QgsMapToolCapture : public QgsMapToolAdvancedDigitizing QgsPointXY mTracingStartPoint; //! Used to store the state of digitizing type (linear or circular) - QgsWkbTypes::Type mDigitizingType = QgsWkbTypes::LineString; + QgsWkbTypes::Type mLineDigitizingType = QgsWkbTypes::LineString; + + CaptureTechnique mCurrentCaptureTechnique = CaptureTechnique::StraightSegments; + + QgsMapToolShapeAbstract *mCurrentShapeMapTool = nullptr; - bool mStreamingEnabled = false; bool mAllowAddingStreamingPoints = false; int mStreamingToleranceInPixels = 1; @@ -394,6 +452,7 @@ class GUI_EXPORT QgsMapToolCapture : public QgsMapToolAdvancedDigitizing friend class TestQgsMapToolCapture; + }; Q_DECLARE_OPERATORS_FOR_FLAGS( QgsMapToolCapture::Capabilities ) diff --git a/src/gui/qgsmaptooldigitizefeature.cpp b/src/gui/qgsmaptooldigitizefeature.cpp index de0f38384051..5fd4c9f6c473 100644 --- a/src/gui/qgsmaptooldigitizefeature.cpp +++ b/src/gui/qgsmaptooldigitizefeature.cpp @@ -15,27 +15,29 @@ ***************************************************************************/ #include "qgsmaptooldigitizefeature.h" + #include "qgsadvanceddigitizingdockwidget.h" #include "qgsapplication.h" #include "qgsattributedialog.h" -#include "qgsexception.h" #include "qgscurvepolygon.h" +#include "qgsexception.h" #include "qgsfields.h" #include "qgsgeometry.h" #include "qgslinestring.h" -#include "qgsmultipoint.h" +#include "qgslogger.h" #include "qgsmapcanvas.h" #include "qgsmapmouseevent.h" +#include "qgsmultipoint.h" #include "qgspolygon.h" #include "qgsproject.h" +#include "qgssettingsregistrycore.h" #include "qgsvectordataprovider.h" #include "qgsvectorlayer.h" -#include "qgslogger.h" #include QgsMapToolDigitizeFeature::QgsMapToolDigitizeFeature( QgsMapCanvas *canvas, QgsAdvancedDigitizingDockWidget *cadDockWidget, CaptureMode mode ) - : QgsMapToolCapture( canvas, cadDockWidget, mode ) + : QgsMapToolCaptureLayerGeometry( canvas, cadDockWidget, mode ) , mCheckGeometryType( true ) { mToolName = tr( "Digitize feature" ); @@ -52,18 +54,52 @@ bool QgsMapToolDigitizeFeature::supportsTechnique( QgsMapToolCapture::CaptureTec { switch ( technique ) { - case QgsMapToolCapture::StraightSegments: + case QgsMapToolCapture::CaptureTechnique::StraightSegments: return true; - case QgsMapToolCapture::CircularString: - case QgsMapToolCapture::Streaming: + case QgsMapToolCapture::CaptureTechnique::CircularString: + case QgsMapToolCapture::CaptureTechnique::Streaming: + case QgsMapToolCapture::CaptureTechnique::Shape: return mode() != QgsMapToolCapture::CapturePoint; } return false; } -void QgsMapToolDigitizeFeature::digitized( const QgsFeature &f ) +void QgsMapToolDigitizeFeature::layerGeometryCaptured( const QgsGeometry &geometry ) { + QgsVectorLayer *vlayer = qobject_cast( mLayer ); + if ( !vlayer ) + vlayer = currentVectorLayer(); + + if ( !vlayer ) + return; + + const QgsWkbTypes::Type layerWKBType = vlayer->wkbType(); + + QgsGeometry layerGeometry; + + if ( mCheckGeometryType ) + { + double defaultZ = QgsSettingsRegistryCore::settingsDigitizingDefaultZValue.value(); + double defaultM = QgsSettingsRegistryCore::settingsDigitizingDefaultMValue.value(); + QVector layerGeometries = geometry.coerceToType( layerWKBType, defaultZ, defaultM ); + if ( layerGeometries.count() > 0 ) + layerGeometry = layerGeometries.at( 0 ); + + if ( layerGeometry.wkbType() != layerWKBType && layerGeometry.wkbType() != QgsWkbTypes::linearType( layerWKBType ) ) + { + emit messageEmitted( tr( "The digitized geometry type (%1) does not correspond to the layer geometry type (%2)." ).arg( QgsWkbTypes::displayString( layerGeometry.wkbType() ) ).arg( QgsWkbTypes::displayString( layerWKBType ) ), Qgis::MessageLevel::Warning ); + return; + } + } + else + { + layerGeometry = geometry; + } + QgsFeature f( vlayer->fields(), 0 ); + f.setGeometry( layerGeometry ); + f.setValid( true ); emit digitizingCompleted( f ); + featureDigitized( f ); } void QgsMapToolDigitizeFeature::activate() @@ -74,8 +110,7 @@ void QgsMapToolDigitizeFeature::activate() if ( vlayer && vlayer->geometryType() == QgsWkbTypes::NullGeometry ) { - const QgsFeature f; - digitized( f ); + layerGeometryCaptured( QgsGeometry() ); return; } @@ -87,12 +122,12 @@ void QgsMapToolDigitizeFeature::activate() mCanvas->setCurrentLayer( mLayer ); } - QgsMapToolCapture::activate(); + QgsMapToolCaptureLayerGeometry::activate(); } void QgsMapToolDigitizeFeature::deactivate() { - QgsMapToolCapture::deactivate(); + QgsMapToolCaptureLayerGeometry::deactivate(); if ( mCurrentLayer ) //set the layer back to the one remembered @@ -124,8 +159,6 @@ void QgsMapToolDigitizeFeature::cadCanvasReleaseEvent( QgsMapMouseEvent *e ) return; } - const QgsWkbTypes::Type layerWKBType = vlayer->wkbType(); - QgsVectorDataProvider *provider = vlayer->dataProvider(); if ( !( provider->capabilities() & QgsVectorDataProvider::AddFeatures ) ) @@ -140,223 +173,32 @@ void QgsMapToolDigitizeFeature::cadCanvasReleaseEvent( QgsMapMouseEvent *e ) return; } - // POINT CAPTURING - if ( mode() == CapturePoint ) + //check we only use this tool for point/multipoint layers + if ( mode() == CapturePoint && vlayer->geometryType() != QgsWkbTypes::PointGeometry && mCheckGeometryType ) { - if ( e->button() != Qt::LeftButton ) - return; - - //check we only use this tool for point/multipoint layers - if ( vlayer->geometryType() != QgsWkbTypes::PointGeometry && mCheckGeometryType ) - { - emit messageEmitted( tr( "Wrong editing tool, cannot apply the 'capture point' tool on this vector layer" ), Qgis::MessageLevel::Warning ); - return; - } - - QgsPoint savePoint; //point in layer coordinates - bool isMatchPointZ = false; - bool isMatchPointM = false; - try - { - QgsPoint fetchPoint; - int res; - res = fetchLayerPoint( e->mapPointMatch(), fetchPoint ); - isMatchPointZ = QgsWkbTypes::hasZ( fetchPoint.wkbType() ); - isMatchPointM = QgsWkbTypes::hasM( fetchPoint.wkbType() ); - - if ( res == 0 ) - { - savePoint = QgsPoint( QgsWkbTypes::singleType( layerWKBType ), fetchPoint.x(), fetchPoint.y(), fetchPoint.z(), fetchPoint.m() ); - } - else - { - const QgsPointXY layerPoint = toLayerCoordinates( vlayer, e->mapPoint() ); - savePoint = QgsPoint( QgsWkbTypes::singleType( layerWKBType ), layerPoint.x(), layerPoint.y(), fetchPoint.z(), fetchPoint.m() ); - } - } - catch ( QgsCsException &cse ) - { - Q_UNUSED( cse ) - emit messageEmitted( tr( "Cannot transform the point to the layers coordinate system" ), Qgis::MessageLevel::Warning ); - return; - } - - //only do the rest for provider with feature addition support - //note that for the grass provider, this will return false since - //grass provider has its own mechanism of feature addition - if ( provider->capabilities() & QgsVectorDataProvider::AddFeatures ) - { - QgsFeature f( vlayer->fields() ); - - QgsGeometry g; - const QgsPoint result( QgsWkbTypes::singleType( layerWKBType ), savePoint.x(), savePoint.y(), isMatchPointZ ? savePoint.z() : defaultZValue(), isMatchPointM ? savePoint.m() : defaultMValue() ); - if ( mCheckGeometryType == false ) - { - // if layer supports more types (mCheckGeometryType is false) - g = QgsGeometry( std::make_unique( savePoint ) ); - } - else - { - if ( !QgsWkbTypes::isMultiType( layerWKBType ) ) - { - g = QgsGeometry( std::make_unique( result ) ); - } - else - { - QgsMultiPoint *mp = new QgsMultiPoint(); - mp->addGeometry( new QgsPoint( result ) ); - g.set( mp ); - } - } - - f.setGeometry( g ); - f.setValid( true ); - - // The snapping result needs to be added so it's available in the @snapping_results variable of default value etc. expression contexts - addVertex( e->mapPoint(), e->mapPointMatch() ); - - digitized( f ); - - stopCapturing(); - - // we are done with digitizing for now so instruct advanced digitizing dock to reset its CAD points - cadDockWidget()->clearPoints(); - } + emit messageEmitted( tr( "Wrong editing tool, cannot apply the 'capture point' tool on this vector layer" ), Qgis::MessageLevel::Warning ); + return; } - // LINE AND POLYGON CAPTURING - else if ( mode() == CaptureLine || mode() == CapturePolygon ) + //check we only use the line tool for line/multiline layers + if ( mode() == CaptureLine && vlayer->geometryType() != QgsWkbTypes::LineGeometry && mCheckGeometryType ) { - //check we only use the line tool for line/multiline layers - if ( mode() == CaptureLine && vlayer->geometryType() != QgsWkbTypes::LineGeometry && mCheckGeometryType ) - { - emit messageEmitted( tr( "Wrong editing tool, cannot apply the 'capture line' tool on this vector layer" ), Qgis::MessageLevel::Warning ); - return; - } - - //check we only use the polygon tool for polygon/multipolygon layers - if ( mode() == CapturePolygon && vlayer->geometryType() != QgsWkbTypes::PolygonGeometry && mCheckGeometryType ) - { - emit messageEmitted( tr( "Wrong editing tool, cannot apply the 'capture polygon' tool on this vector layer" ), Qgis::MessageLevel::Warning ); - return; - } + emit messageEmitted( tr( "Wrong editing tool, cannot apply the 'capture line' tool on this vector layer" ), Qgis::MessageLevel::Warning ); + return; + } - //add point to list and to rubber band - if ( e->button() == Qt::LeftButton ) - { - const int error = addVertex( e->mapPoint(), e->mapPointMatch() ); - if ( error == 2 ) - { - //problem with coordinate transformation - emit messageEmitted( tr( "Cannot transform the point to the layers coordinate system" ), Qgis::MessageLevel::Warning ); - return; - } - - startCapturing(); - } - else if ( e->button() == Qt::RightButton ) - { - // End of string - deleteTempRubberBand(); - - //lines: bail out if there are not at least two vertices - if ( mode() == CaptureLine && size() < 2 ) - { - stopCapturing(); - return; - } - - //polygons: bail out if there are not at least two vertices - if ( mode() == CapturePolygon && size() < 3 ) - { - stopCapturing(); - return; - } - - if ( mode() == CapturePolygon || e->modifiers() == Qt::ShiftModifier ) - { - closePolygon(); - } - - //create QgsFeature with wkb representation - std::unique_ptr< QgsFeature > f( new QgsFeature( vlayer->fields(), 0 ) ); - - //does compoundcurve contain circular strings? - //does provider support circular strings? - const bool hasCurvedSegments = captureCurve()->hasCurvedSegments(); - const bool providerSupportsCurvedSegments = vlayer->dataProvider()->capabilities() & QgsVectorDataProvider::CircularGeometries; - - QList snappingMatchesList; - QgsCurve *curveToAdd = nullptr; - if ( hasCurvedSegments && providerSupportsCurvedSegments ) - { - curveToAdd = captureCurve()->clone(); - } - else - { - curveToAdd = captureCurve()->curveToLine(); - snappingMatchesList = snappingMatches(); - } - - if ( mode() == CaptureLine ) - { - const QgsGeometry g( curveToAdd ); - f->setGeometry( g ); - } - else - { - QgsCurvePolygon *poly = nullptr; - if ( hasCurvedSegments && providerSupportsCurvedSegments ) - { - poly = new QgsCurvePolygon(); - } - else - { - poly = new QgsPolygon(); - } - poly->setExteriorRing( curveToAdd ); - const QgsGeometry g( poly ); - f->setGeometry( g ); - - QList avoidIntersectionsLayers; - switch ( QgsProject::instance()->avoidIntersectionsMode() ) - { - case QgsProject::AvoidIntersectionsMode::AvoidIntersectionsCurrentLayer: - avoidIntersectionsLayers.append( vlayer ); - break; - case QgsProject::AvoidIntersectionsMode::AvoidIntersectionsLayers: - avoidIntersectionsLayers = QgsProject::instance()->avoidIntersectionsLayers(); - break; - case QgsProject::AvoidIntersectionsMode::AllowIntersections: - break; - } - if ( avoidIntersectionsLayers.size() > 0 ) - { - QgsGeometry featGeom = f->geometry(); - const int avoidIntersectionsReturn = featGeom.avoidIntersections( avoidIntersectionsLayers ); - f->setGeometry( featGeom ); - if ( avoidIntersectionsReturn == 3 ) - { - emit messageEmitted( tr( "The feature has been added, but at least one geometry intersected is invalid. These geometries must be manually repaired." ), Qgis::MessageLevel::Warning ); - } - if ( f->geometry().isEmpty() ) //avoid intersection might have removed the whole geometry - { - emit messageEmitted( tr( "The feature cannot be added because its geometry collapsed due to intersection avoidance" ), Qgis::MessageLevel::Critical ); - stopCapturing(); - return; - } - } - } - f->setValid( true ); - - digitized( *f ); - - stopCapturing(); - } + //check we only use the polygon tool for polygon/multipolygon layers + if ( mode() == CapturePolygon && vlayer->geometryType() != QgsWkbTypes::PolygonGeometry && mCheckGeometryType ) + { + emit messageEmitted( tr( "Wrong editing tool, cannot apply the 'capture polygon' tool on this vector layer" ), Qgis::MessageLevel::Warning ); + return; } + + QgsMapToolCaptureLayerGeometry::cadCanvasReleaseEvent( e ); } void QgsMapToolDigitizeFeature::setLayer( QgsMapLayer *vl ) { mLayer = vl; } + diff --git a/src/gui/qgsmaptooldigitizefeature.h b/src/gui/qgsmaptooldigitizefeature.h index 5c4c0d7be6cf..cc0fd43af5b3 100644 --- a/src/gui/qgsmaptooldigitizefeature.h +++ b/src/gui/qgsmaptooldigitizefeature.h @@ -16,7 +16,7 @@ #ifndef QGSMAPTOOLDIGITIZEFEATURE_H #define QGSMAPTOOLDIGITIZEFEATURE_H -#include "qgsmaptoolcapture.h" +#include "qgsmaptoolcapturelayergeometry.h" #include "qgis_gui.h" class QgsFeature; @@ -28,7 +28,7 @@ class QgsFeature; * A signal will then be emitted. * \since QGIS 3.10 */ -class GUI_EXPORT QgsMapToolDigitizeFeature : public QgsMapToolCapture +class GUI_EXPORT QgsMapToolDigitizeFeature : public QgsMapToolCaptureLayerGeometry { Q_OBJECT @@ -68,7 +68,7 @@ class GUI_EXPORT QgsMapToolDigitizeFeature : public QgsMapToolCapture * Emitted whenever the digitizing has been ended without digitizing * any feature */ - void digitizingFinished( ); + void digitizingFinished(); protected: @@ -83,14 +83,21 @@ class GUI_EXPORT QgsMapToolDigitizeFeature : public QgsMapToolCapture * \since QGIS 3.0 */ void setCheckGeometryType( bool checkGeometryType ); + // TODO QGIS 4: remove if GRASS plugin is dropped private: /** * Called when the feature has been digitized. - * \param f the new created feature + * \param geometry the digitized geometry */ - virtual void digitized( const QgsFeature &f ); + void layerGeometryCaptured( const QgsGeometry &geometry ) override FINAL; + + /** + * Called when the feature has been digitized + * \since QGIS 3.26 + */ + virtual void featureDigitized( const QgsFeature &feature ) {Q_UNUSED( feature )} SIP_FORCE /** * individual layer per digitizing session diff --git a/src/gui/qgsmaptooledit.h b/src/gui/qgsmaptooledit.h index 7e3808ae7b35..fbbd492a6e30 100644 --- a/src/gui/qgsmaptooledit.h +++ b/src/gui/qgsmaptooledit.h @@ -52,6 +52,15 @@ class GUI_EXPORT QgsMapToolEdit: public QgsMapTool */ double defaultMValue() const; + /** + * Creates a geometry rubber band with the color/line width from + * the QGIS settings. The caller takes ownership of the + * returned object + * \param geometryType + * \param alternativeBand if TRUE, rubber band will be set with more transparency and a dash pattern. default is FALSE. + */ + QgsGeometryRubberBand *createGeometryRubberBand( QgsWkbTypes::GeometryType geometryType = QgsWkbTypes::LineGeometry, bool alternativeBand = false ) const SIP_FACTORY; + private slots: //! Vector layers' editingStopped SIGNAL will eventually trigger a clean void connectLayers( const QList &layers ); @@ -80,8 +89,6 @@ class GUI_EXPORT QgsMapToolEdit: public QgsMapTool */ QgsRubberBand *createRubberBand( QgsWkbTypes::GeometryType geometryType = QgsWkbTypes::LineGeometry, bool alternativeBand = false ) SIP_FACTORY; - QgsGeometryRubberBand *createGeometryRubberBand( QgsWkbTypes::GeometryType geometryType = QgsWkbTypes::LineGeometry, bool alternativeBand = false ) const SIP_FACTORY; - //! Returns the current vector layer of the map canvas or 0 QgsVectorLayer *currentVectorLayer(); diff --git a/src/ui/qgisapp.ui b/src/ui/qgisapp.ui index 531f6f3fdfd8..7bb470aa6d2f 100644 --- a/src/ui/qgisapp.ui +++ b/src/ui/qgisapp.ui @@ -333,42 +333,6 @@ - - - Add Circle - - - - - - - - - - Add Ellipse - - - - - - - - - Add Rectangle - - - - - - - - - Add Regular Polygon - - - - - Add Annotation @@ -419,12 +383,6 @@ - - - - - - @@ -2891,36 +2849,6 @@ Shift+click to snap rotation to 45 degree steps. Align Rasters… - - - true - - - - :/images/themes/default/mActionCircularStringCurvePoint.svg:/images/themes/default/mActionCircularStringCurvePoint.svg - - - Add Circular String - - - Add Circular String - - - - - true - - - - :/images/themes/default/mActionCircularStringRadius.svg:/images/themes/default/mActionCircularStringRadius.svg - - - Add Circular String by Radius - - - Add Circular String by Radius - - Report an Issue @@ -3031,231 +2959,6 @@ Shift+click to snap rotation to 45 degree steps. Ctrl+L - - - true - - - - :/images/themes/default/mActionCircle2Points.svg:/images/themes/default/mActionCircle2Points.svg - - - Add Circle from &2 Points - - - Add Circle from 2 Points - - - - - true - - - - :/images/themes/default/mActionCircle3Points.svg:/images/themes/default/mActionCircle3Points.svg - - - Add Circle from &3 Points - - - Add Circle from 3 Points - - - - - true - - - - :/images/themes/default/mActionCircleCenterPoint.svg:/images/themes/default/mActionCircleCenterPoint.svg - - - &Add Circle by a Center Point and Another Point - - - Add Circle by a Center Point and Another Point - - - - - true - - - - :/images/themes/default/mActionEllipseCenter2Points.svg:/images/themes/default/mActionEllipseCenter2Points.svg - - - &Add Ellipse from Center and 2 Points - - - Add Ellipse from Center and 2 Points - - - - - true - - - - :/images/themes/default/mActionEllipseCenterPoint.svg:/images/themes/default/mActionEllipseCenterPoint.svg - - - Add Ellipse from &Center and a Point - - - Add Ellipse from center and a point - - - - - true - - - - :/images/themes/default/mActionEllipseExtent.svg:/images/themes/default/mActionEllipseExtent.svg - - - Add Ellipse from &Extent - - - Add Ellipse from Extent - - - - - true - - - - :/images/themes/default/mActionEllipseFoci.svg:/images/themes/default/mActionEllipseFoci.svg - - - Add Ellipse from &Foci - - - Add Ellipse from Foci - - - - - true - - - - :/images/themes/default/mActionRectangleExtent.svg:/images/themes/default/mActionRectangleExtent.svg - - - &Add Rectangle from Extent - - - Add Rectangle from Extent - - - - - true - - - - :/images/themes/default/mActionRectangleCenter.svg:/images/themes/default/mActionRectangleCenter.svg - - - Add &Rectangle from Center and a Point - - - Add Rectangle from Center and a Point - - - - - true - - - - :/images/themes/default/mActionRegularPolygonCenterPoint.svg:/images/themes/default/mActionRegularPolygonCenterPoint.svg - - - &Add Regular Polygon from Center and a Point - - - Add Regular Polygon from Center and a Point - - - - - true - - - - :/images/themes/default/mActionRegularPolygon2Points.svg:/images/themes/default/mActionRegularPolygon2Points.svg - - - Add &Regular Polygon from 2 Points - - - Add Regular Polygon from 2 Points - - - - - true - - - - :/images/themes/default/mActionCircle3Tangents.svg:/images/themes/default/mActionCircle3Tangents.svg - - - Add &Circle from 3 Tangents - - - Add Circle from 3 Tangents - - - - - true - - - - :/images/themes/default/mActionRectangle3PointsDistance.svg:/images/themes/default/mActionRectangle3PointsDistance.svg - - - Add Rectangle &from 3 Points (Distance from 2nd and 3rd point) - - - Add Rectangle from 3 Points (Distance from 2nd and 3rd Point) - - - - - true - - - - :/images/themes/default/mActionCircle2TangentsPoint.svg:/images/themes/default/mActionCircle2TangentsPoint.svg - - - Add Circle &from 2 Tangents and a Point - - - Add Circle from 2 Tangents and a Point - - - - - true - - - - :/images/themes/default/mActionRegularPolygonCenterCorner.svg:/images/themes/default/mActionRegularPolygonCenterCorner.svg - - - Add Regular &Polygon from Center and a Corner - - - Add Regular Polygon from Center and a Corner - - @@ -3354,21 +3057,6 @@ Ctrl+click/drag to remove vertices from selection. Shift+R to enable range selection. - - - true - - - - :/images/themes/default/mActionRectangle3PointsProjected.svg:/images/themes/default/mActionRectangle3PointsProjected.svg - - - Add Rectangle &from 3 Points (Distance from projected point on segment p1 and p2) - - - Add Rectangle from 3 Points (Distance from Projected Point on Segment p1 and p2) - - @@ -3629,6 +3317,30 @@ Shows placeholders for labels which could not be placed, e.g. due to overlaps wi Manage 3D Map Views + + + true + + + + :/images/themes/default/mActionDigitizeWithSegment.svg:/images/themes/default/mActionDigitizeWithSegment.svg + + + Digitize with Segment + + + + + true + + + + :/images/themes/default/mActionDigitizeShape.svg:/images/themes/default/mActionDigitizeShape.svg + + + Digitize Shape + + diff --git a/tests/src/app/maptooladdfeatureline/testqgsmaptooladdfeatureline.cpp b/tests/src/app/maptooladdfeatureline/testqgsmaptooladdfeatureline.cpp index e1d23b14d9ab..addbc80cc656 100644 --- a/tests/src/app/maptooladdfeatureline/testqgsmaptooladdfeatureline.cpp +++ b/tests/src/app/maptooladdfeatureline/testqgsmaptooladdfeatureline.cpp @@ -118,7 +118,7 @@ void TestQgsMapToolAddFeatureLine::initTestCase() mCanvas->setDestinationCrs( QgsCoordinateReferenceSystem( QStringLiteral( "EPSG:27700" ) ) ); // make testing layers - mLayerLine = new QgsVectorLayer( QStringLiteral( "LineString?crs=EPSG:27700" ), QStringLiteral( "layer line" ), QStringLiteral( "memory" ) ); + mLayerLine = new QgsVectorLayer( QStringLiteral( "CompoundCurve?crs=EPSG:27700" ), QStringLiteral( "layer line" ), QStringLiteral( "memory" ) ); QVERIFY( mLayerLine->isValid() ); QgsProject::instance()->addMapLayers( QList() << mLayerLine ); @@ -136,7 +136,7 @@ void TestQgsMapToolAddFeatureLine::initTestCase() QCOMPARE( mLayerLine->undoStack()->index(), 1 ); // make testing layers for tracing curves - mLayerLineCurved = new QgsVectorLayer( QStringLiteral( "LineString?crs=EPSG:27700" ), QStringLiteral( "curved layer line" ), QStringLiteral( "memory" ) ); + mLayerLineCurved = new QgsVectorLayer( QStringLiteral( "CompoundCurve?crs=EPSG:27700" ), QStringLiteral( "curved layer line" ), QStringLiteral( "memory" ) ); QVERIFY( mLayerLineCurved->isValid() ); QgsProject::instance()->addMapLayers( QList() << mLayerLineCurved ); @@ -152,7 +152,7 @@ void TestQgsMapToolAddFeatureLine::initTestCase() QCOMPARE( mLayerLineCurved->undoStack()->index(), 1 ); // make testing layers for tracing curves with offset - mLayerLineCurvedOffset = new QgsVectorLayer( QStringLiteral( "LineString?crs=EPSG:27700" ), QStringLiteral( "curved layer line" ), QStringLiteral( "memory" ) ); + mLayerLineCurvedOffset = new QgsVectorLayer( QStringLiteral( "CompoundCurve?crs=EPSG:27700" ), QStringLiteral( "curved layer line" ), QStringLiteral( "memory" ) ); QVERIFY( mLayerLineCurvedOffset->isValid() ); QgsProject::instance()->addMapLayers( QList() << mLayerLineCurvedOffset ); @@ -255,12 +255,12 @@ void TestQgsMapToolAddFeatureLine::testNoTracing() QgsFeatureId newFid = utils.newFeatureId( oldFids ); QCOMPARE( mLayerLine->undoStack()->index(), 2 ); - QCOMPARE( mLayerLine->getFeature( newFid ).geometry(), QgsGeometry::fromWkt( "LINESTRING(1 1, 3 2)" ) ); + QCOMPARE( mLayerLine->getFeature( newFid ).geometry(), QgsGeometry::fromWkt( "LineString ((1 1, 3 2))" ) ); mLayerLine->undoStack()->undo(); QCOMPARE( mLayerLine->undoStack()->index(), 1 ); - mCaptureTool->setCircularDigitizingEnabled( true ); + mCaptureTool->setCurrentCaptureTechnique( QgsMapToolCapture::CaptureTechnique::CircularString ); utils.mouseClick( 1, 1, Qt::LeftButton ); utils.mouseClick( 3, 2, Qt::LeftButton ); @@ -276,7 +276,7 @@ void TestQgsMapToolAddFeatureLine::testNoTracing() utils.mouseMove( 5, 5 ); utils.mouseClick( 4, 2, Qt::LeftButton ); - mCaptureTool->setCircularDigitizingEnabled( false ); + mCaptureTool->setCurrentCaptureTechnique( QgsMapToolCapture::CaptureTechnique::StraightSegments ); utils.mouseMove( 5, 5 ); utils.mouseClick( 4, 3, Qt::LeftButton ); @@ -292,7 +292,7 @@ void TestQgsMapToolAddFeatureLine::testNoTracing() mLayerLine->undoStack()->undo(); QCOMPARE( mLayerLine->undoStack()->index(), 1 ); - mCaptureTool->setCircularDigitizingEnabled( false ); + mCaptureTool->setCurrentCaptureTechnique( QgsMapToolCapture::CaptureTechnique::StraightSegments ); } void TestQgsMapToolAddFeatureLine::testTracing() @@ -302,17 +302,22 @@ void TestQgsMapToolAddFeatureLine::testTracing() // tracing enabled - same clicks - now following line mEnableTracingAction->setChecked( true ); + mCaptureTool->setCurrentCaptureTechnique( QgsMapToolCapture::CaptureTechnique::StraightSegments ); const QSet oldFids = utils.existingFeatureIds(); utils.mouseClick( 1, 1, Qt::LeftButton ); utils.mouseClick( 3, 2, Qt::LeftButton ); + + // be sure it doesn't create an extra curve + QCOMPARE( mCaptureTool->captureCurve()->asWkt( 2 ), QStringLiteral( "CompoundCurve ((1 1, 2 1, 3 2))" ) ); + utils.mouseClick( 3, 2, Qt::RightButton ); const QgsFeatureId newFid = utils.newFeatureId( oldFids ); QCOMPARE( mLayerLine->undoStack()->index(), 2 ); - QCOMPARE( mLayerLine->getFeature( newFid ).geometry(), QgsGeometry::fromWkt( "LINESTRING(1 1, 2 1, 3 2)" ) ); + QCOMPARE( mLayerLine->getFeature( newFid ).geometry(), QgsGeometry::fromWkt( "LineString(1 1, 2 1, 3 2)" ) ); mLayerLine->undoStack()->undo(); @@ -330,7 +335,7 @@ void TestQgsMapToolAddFeatureLine::testTracing() const QgsFeatureId newFid2 = utils.newFeatureId( oldFids ); QCOMPARE( mLayerLine->undoStack()->index(), 2 ); - QCOMPARE( mLayerLine->getFeature( newFid2 ).geometry(), QgsGeometry::fromWkt( "LINESTRING(0 2, 1 1, 2 1, 3 2, 4 1)" ) ); + QCOMPARE( mLayerLine->getFeature( newFid2 ).geometry(), QgsGeometry::fromWkt( "LineString(0 2, 1 1, 2 1, 3 2, 4 1)" ) ); mLayerLine->undoStack()->undo(); @@ -627,7 +632,7 @@ void TestQgsMapToolAddFeatureLine::testLineString() const QgsFeatureId newFid = utils.newFeatureId( oldFids ); - const QString wkt = "LineString (5 6.5, 6.25 6.5, 6.75 6.5, 7.25 6.5, 7.5 6.5)"; + const QString wkt = "LineString(5 6.5, 6.25 6.5, 6.75 6.5, 7.25 6.5, 7.5 6.5)"; QCOMPARE( mLayerLine->getFeature( newFid ).geometry(), QgsGeometry::fromWkt( wkt ) ); mLayerLine->undoStack()->undo(); @@ -648,10 +653,10 @@ void TestQgsMapToolAddFeatureLine::testCompoundCurve() oldFids = utils.existingFeatureIds(); utils.mouseClick( 5, 6.5, Qt::LeftButton ); utils.mouseClick( 6.25, 6.5, Qt::LeftButton ); - mCaptureTool->setCircularDigitizingEnabled( true ); + mCaptureTool->setCurrentCaptureTechnique( QgsMapToolCapture::CaptureTechnique::CircularString ); utils.mouseClick( 6.75, 6.5, Qt::LeftButton ); utils.mouseClick( 7.25, 6.5, Qt::LeftButton ); - mCaptureTool->setCircularDigitizingEnabled( false ); + mCaptureTool->setCurrentCaptureTechnique( QgsMapToolCapture::CaptureTechnique::StraightSegments ); utils.mouseClick( 7.5, 6.5, Qt::LeftButton ); utils.mouseClick( 7.5, 6.0, Qt::LeftButton ); utils.mouseClick( 7.7, 6.0, Qt::LeftButton ); @@ -683,11 +688,13 @@ void TestQgsMapToolAddFeatureLine::testStream() mCanvas->snappingUtils()->setConfig( cfg ); oldFids = utils.existingFeatureIds(); + + mCaptureTool->setCurrentCaptureTechnique( QgsMapToolCapture::CaptureTechnique::StraightSegments ); utils.mouseClick( 5, 6.5, Qt::LeftButton ); utils.mouseClick( 6.25, 6.5, Qt::LeftButton ); utils.mouseClick( 6.75, 6.5, Qt::LeftButton ); - mCaptureTool->setStreamDigitizingEnabled( true ); + mCaptureTool->setCurrentCaptureTechnique( QgsMapToolCapture::CaptureTechnique::Streaming ); utils.mouseMove( 7.0, 6.6 ); utils.mouseMove( 7.1, 6.7 ); utils.mouseMove( 7.2, 6.6 ); @@ -695,9 +702,9 @@ void TestQgsMapToolAddFeatureLine::testStream() utils.mouseMove( 7.5, 6.9 ); utils.mouseMove( 7.6, 6.3 ); utils.mouseClick( 7.75, 6.5, Qt::LeftButton ); - mCaptureTool->setStreamDigitizingEnabled( false ); + mCaptureTool->setCurrentCaptureTechnique( QgsMapToolCapture::CaptureTechnique::StraightSegments ); utils.mouseClick( 7.5, 5.0, Qt::LeftButton ); - mCaptureTool->setStreamDigitizingEnabled( true ); + mCaptureTool->setCurrentCaptureTechnique( QgsMapToolCapture::CaptureTechnique::Streaming ); utils.mouseMove( 7.4, 5.0 ); utils.mouseMove( 7.3, 5.1 ); utils.mouseMove( 7.2, 5.0 ); @@ -706,7 +713,7 @@ void TestQgsMapToolAddFeatureLine::testStream() // check capture curve initially -- the streamed sections MUST become their own curve in the geometry, and not be compined with the straight line segments! QCOMPARE( mCaptureTool->captureCurve()->asWkt( 2 ), QStringLiteral( "CompoundCurve ((5 6.5, 6.25 6.5, 6.75 6.5),(6.75 6.5, 7 6.59, 7.09 6.7, 7.2 6.59, 7.3 6.5, 7.5 6.91, 7.59 6.3),(7.59 6.3, 7.5 5),(7.5 5, 7.41 5, 7.3 5.09, 7.2 5, 7.09 4.91))" ) ); utils.mouseClick( 7.0, 5.0, Qt::RightButton ); - mCaptureTool->setStreamDigitizingEnabled( false ); + mCaptureTool->setCurrentCaptureTechnique( QgsMapToolCapture::CaptureTechnique::StraightSegments ); const QgsFeatureId newFid = utils.newFeatureId( oldFids ); @@ -734,7 +741,7 @@ void TestQgsMapToolAddFeatureLine::testUndo() utils.mouseClick( 6.25, 6.5, Qt::LeftButton ); utils.mouseClick( 6.75, 6.5, Qt::LeftButton ); - mCaptureTool->setStreamDigitizingEnabled( true ); + mCaptureTool->setCurrentCaptureTechnique( QgsMapToolCapture::CaptureTechnique::Streaming ); utils.mouseMove( 7.0, 6.6 ); utils.mouseMove( 7.1, 6.7 ); utils.mouseMove( 7.2, 6.6 ); @@ -742,9 +749,9 @@ void TestQgsMapToolAddFeatureLine::testUndo() utils.mouseMove( 7.5, 6.9 ); utils.mouseMove( 7.6, 6.3 ); utils.mouseClick( 7.75, 6.5, Qt::LeftButton ); - mCaptureTool->setStreamDigitizingEnabled( false ); + mCaptureTool->setCurrentCaptureTechnique( QgsMapToolCapture::CaptureTechnique::StraightSegments ); utils.mouseClick( 7.5, 5.0, Qt::LeftButton ); - mCaptureTool->setStreamDigitizingEnabled( true ); + mCaptureTool->setCurrentCaptureTechnique( QgsMapToolCapture::CaptureTechnique::Streaming ); utils.mouseMove( 7.4, 5.0 ); utils.mouseMove( 7.3, 5.1 ); utils.mouseMove( 7.2, 5.0 ); @@ -798,7 +805,7 @@ void TestQgsMapToolAddFeatureLine::testUndo() utils.keyClick( Qt::Key_Backspace, Qt::KeyboardModifiers(), true ); utils.mouseClick( 7.0, 5.0, Qt::RightButton ); - mCaptureTool->setStreamDigitizingEnabled( false ); + mCaptureTool->setCurrentCaptureTechnique( QgsMapToolCapture::CaptureTechnique::StraightSegments ); } void TestQgsMapToolAddFeatureLine::testStreamTolerance() @@ -822,7 +829,7 @@ void TestQgsMapToolAddFeatureLine::testStreamTolerance() utils.mouseClick( 6.25, 6.5, Qt::LeftButton ); utils.mouseClick( 6.75, 6.5, Qt::LeftButton ); - mCaptureTool->setStreamDigitizingEnabled( true ); + mCaptureTool->setCurrentCaptureTechnique( QgsMapToolCapture::CaptureTechnique::Streaming ); utils.mouseMove( 7.0, 6.6 ); utils.mouseMove( 7.1, 6.7 ); utils.mouseMove( 7.2, 6.6 ); @@ -830,9 +837,9 @@ void TestQgsMapToolAddFeatureLine::testStreamTolerance() utils.mouseMove( 7.5, 6.9 ); utils.mouseMove( 7.6, 6.3 ); utils.mouseClick( 7.75, 6.5, Qt::LeftButton ); - mCaptureTool->setStreamDigitizingEnabled( false ); + mCaptureTool->setCurrentCaptureTechnique( QgsMapToolCapture::CaptureTechnique::StraightSegments ); utils.mouseClick( 7.5, 5.0, Qt::LeftButton ); - mCaptureTool->setStreamDigitizingEnabled( true ); + mCaptureTool->setCurrentCaptureTechnique( QgsMapToolCapture::CaptureTechnique::Streaming ); utils.mouseMove( 7.4, 5.0 ); utils.mouseMove( 7.3, 5.1 ); utils.mouseMove( 7.2, 5.0 ); @@ -841,11 +848,11 @@ void TestQgsMapToolAddFeatureLine::testStreamTolerance() // check capture curve initially -- the streamed sections MUST become their own curve in the geometry, and not be compined with the straight line segments! QCOMPARE( mCaptureTool->captureCurve()->asWkt( 2 ), QStringLiteral( "CompoundCurve ((5 6.5, 6.25 6.5, 6.75 6.5),(6.75 6.5, 7 6.59, 7.2 6.59, 7.5 6.91, 7.59 6.3),(7.59 6.3, 7.5 5),(7.5 5, 7.3 5.09, 7.09 4.91))" ) ); utils.mouseClick( 7.0, 5.0, Qt::RightButton ); - mCaptureTool->setStreamDigitizingEnabled( false ); + mCaptureTool->setCurrentCaptureTechnique( QgsMapToolCapture::CaptureTechnique::StraightSegments ); const QgsFeatureId newFid = utils.newFeatureId( oldFids ); - const QString wkt = "LineString (5 6.5, 6.25 6.5, 6.75 6.5, 7 6.59375, 7.203125 6.59375, 7.5 6.90625, 7.59375 6.296875, 7.5 5, 7.296875 5.09375, 7.09375 4.90625)"; + const QString wkt = "LineString(5 6.5, 6.25 6.5, 6.75 6.5, 7 6.59375, 7.203125 6.59375, 7.5 6.90625, 7.59375 6.296875, 7.5 5, 7.296875 5.09375, 7.09375 4.90625)"; QCOMPARE( mLayerLine->getFeature( newFid ).geometry(), QgsGeometry::fromWkt( wkt ) ); mLayerLine->undoStack()->undo(); diff --git a/tests/src/app/maptooladdfeatureline/testqgsmaptooladdfeaturelinem.cpp b/tests/src/app/maptooladdfeatureline/testqgsmaptooladdfeaturelinem.cpp index 6b06cbca41db..e9e9823c7c24 100644 --- a/tests/src/app/maptooladdfeatureline/testqgsmaptooladdfeaturelinem.cpp +++ b/tests/src/app/maptooladdfeatureline/testqgsmaptooladdfeaturelinem.cpp @@ -244,10 +244,10 @@ void TestQgsMapToolAddFeatureLineM::testTopologicalEditingM() utils.mouseClick( 8, 6.5, Qt::RightButton ); const QgsFeatureId newFid = utils.newFeatureId( oldFids ); - QString wkt = "LineStringM (6 6.5 333, 6.25 6.5 333, 6.75 6.5 333, 7.25 6.5 333, 7.5 6.5 333)"; + QString wkt = "MultiLineStringM((6 6.5 333, 6.25 6.5 333, 6.75 6.5 333, 7.25 6.5 333, 7.5 6.5 333))"; QCOMPARE( mLayerTopoM->getFeature( newFid ).geometry(), QgsGeometry::fromWkt( wkt ) ); wkt = "MultiLineStringM ((7.25 6 0, 7.25 6.5 333, 7.25 7 0, 7.5 7 0, 7.5 6.5 333, 7.5 6 0, 7.25 6 0),(6 6 0, 6 6.5 333, 6 7 10, 7 7 0, 7 6 0, 6 6 0),(6.25 6.25 0, 6.75 6.25 0, 6.75 6.5 333, 6.75 6.75 0, 6.25 6.75 0, 6.25 6.5 333, 6.25 6.25 0))"; - QCOMPARE( mLayerTopoM->getFeature( qgis::setToList( oldFids ).last() ).geometry(), QgsGeometry::fromWkt( wkt ) ); + QCOMPARE( mLayerTopoM->getFeature( qgis::setToList( oldFids ).constLast() ).geometry(), QgsGeometry::fromWkt( wkt ) ); mLayerLine->undoStack()->undo(); diff --git a/tests/src/app/maptooladdfeatureline/testqgsmaptooladdfeaturelinez.cpp b/tests/src/app/maptooladdfeatureline/testqgsmaptooladdfeaturelinez.cpp index ae38de2e4bd2..0f5f301473d8 100644 --- a/tests/src/app/maptooladdfeatureline/testqgsmaptooladdfeaturelinez.cpp +++ b/tests/src/app/maptooladdfeatureline/testqgsmaptooladdfeaturelinez.cpp @@ -245,10 +245,10 @@ void TestQgsMapToolAddFeatureLineZ::testTopologicalEditingZ() utils.mouseClick( 8, 6.5, Qt::RightButton ); const QgsFeatureId newFid = utils.newFeatureId( oldFids ); - QString wkt = "LineStringZ (6 6.5 333, 6.25 6.5 333, 6.75 6.5 333, 7.25 6.5 333, 7.5 6.5 333)"; + QString wkt = "MultiLineStringZ ((6 6.5 333, 6.25 6.5 333, 6.75 6.5 333, 7.25 6.5 333, 7.5 6.5 333))"; QCOMPARE( mLayerTopoZ->getFeature( newFid ).geometry(), QgsGeometry::fromWkt( wkt ) ); wkt = "MultiLineStringZ ((7.25 6 0, 7.25 6.5 333, 7.25 7 0, 7.5 7 0, 7.5 6.5 333, 7.5 6 0, 7.25 6 0),(6 6 0, 6 6.5 333, 6 7 10, 7 7 0, 7 6 0, 6 6 0),(6.25 6.25 0, 6.75 6.25 0, 6.75 6.5 333, 6.75 6.75 0, 6.25 6.75 0, 6.25 6.5 333, 6.25 6.25 0))"; - QCOMPARE( mLayerTopoZ->getFeature( qgis::setToList( oldFids ).last() ).geometry(), QgsGeometry::fromWkt( wkt ) ); + QCOMPARE( mLayerTopoZ->getFeature( qgis::setToList( oldFids ).constLast() ).geometry(), QgsGeometry::fromWkt( wkt ) ); mLayerLine->undoStack()->undo(); diff --git a/tests/src/app/testqgsmaptoolcircle.cpp b/tests/src/app/testqgsmaptoolcircle.cpp index f7fa02a66a4b..008793fc4498 100644 --- a/tests/src/app/testqgsmaptoolcircle.cpp +++ b/tests/src/app/testqgsmaptoolcircle.cpp @@ -27,9 +27,9 @@ #include "qgsmaptooladdfeature.h" #include "testqgsmaptoolutils.h" -#include "qgsmaptoolcircle2points.h" -#include "qgsmaptoolcircle3points.h" -#include "qgsmaptoolcirclecenterpoint.h" +#include "qgsmaptoolshapecircle2points.h" +#include "qgsmaptoolshapecircle3points.h" +#include "qgsmaptoolshapecirclecenterpoint.h" class TestQgsMapToolCircle : public QObject @@ -47,8 +47,10 @@ class TestQgsMapToolCircle : public QObject void testCircle(); private: + void resetMapTool( QgsMapToolShapeMetadata *metadata ); + QgisApp *mQgisApp = nullptr; - QgsMapToolCapture *mParentTool = nullptr; + QgsMapToolCapture *mMapTool = nullptr; QgsMapCanvas *mCanvas = nullptr; std::map> mVectorLayerMap = {}; @@ -96,19 +98,19 @@ void TestQgsMapToolCircle::initTestCase() // make testing layers QList layerList; - mVectorLayerMap["XY"] = std::make_unique( QStringLiteral( "LineString?crs=EPSG:27700" ), QStringLiteral( "layer line " ), QStringLiteral( "memory" ) ); + mVectorLayerMap["XY"] = std::make_unique( QStringLiteral( "CompoundCurve?crs=EPSG:27700" ), QStringLiteral( "layer line " ), QStringLiteral( "memory" ) ); QVERIFY( mVectorLayerMap["XY"]->isValid() ); layerList << mVectorLayerMap["XY"].get(); - mVectorLayerMap["XYZ"] = std::make_unique( QStringLiteral( "LineStringZ?crs=EPSG:27700" ), QStringLiteral( "layer line Z" ), QStringLiteral( "memory" ) ); + mVectorLayerMap["XYZ"] = std::make_unique( QStringLiteral( "CompoundCurveZ?crs=EPSG:27700" ), QStringLiteral( "layer line Z" ), QStringLiteral( "memory" ) ); QVERIFY( mVectorLayerMap["XYZ"]->isValid() ); layerList << mVectorLayerMap["XYZ"].get(); - mVectorLayerMap["XYM"] = std::make_unique( QStringLiteral( "LineStringM?crs=EPSG:27700" ), QStringLiteral( "layer line M" ), QStringLiteral( "memory" ) ); + mVectorLayerMap["XYM"] = std::make_unique( QStringLiteral( "CompoundCurveM?crs=EPSG:27700" ), QStringLiteral( "layer line M" ), QStringLiteral( "memory" ) ); QVERIFY( mVectorLayerMap["XYM"]->isValid() ); layerList << mVectorLayerMap["XYM"].get(); - mVectorLayerMap["XYZM"] = std::make_unique( QStringLiteral( "LineStringZM?crs=EPSG:27700" ), QStringLiteral( "layer line ZM" ), QStringLiteral( "memory" ) ); + mVectorLayerMap["XYZM"] = std::make_unique( QStringLiteral( "CompoundCurveZM?crs=EPSG:27700" ), QStringLiteral( "layer line ZM" ), QStringLiteral( "memory" ) ); QVERIFY( mVectorLayerMap["XYZM"]->isValid() ); layerList << mVectorLayerMap["XYZM"].get(); @@ -116,7 +118,9 @@ void TestQgsMapToolCircle::initTestCase() QgsProject::instance()->addMapLayers( layerList ); mCanvas->setLayers( layerList ); - mParentTool = new QgsMapToolAddFeature( mCanvas, QgsMapToolCapture::CaptureLine ); + mMapTool = new QgsMapToolAddFeature( mCanvas, QgsMapToolCapture::CaptureLine ); + mMapTool->setCurrentCaptureTechnique( QgsMapToolCapture::Shape ); + mCanvas->setMapTool( mMapTool ); initAttributs(); } @@ -168,21 +172,27 @@ void TestQgsMapToolCircle::initAttributs() void TestQgsMapToolCircle::cleanupTestCase() { - - for ( QString coordinate : mCoordinateList ) + for ( const QString &coordinate : std::as_const( mCoordinateList ) ) { mVectorLayerMap[coordinate].reset(); } + delete mMapTool; QgsApplication::exitQgis(); } +void TestQgsMapToolCircle::resetMapTool( QgsMapToolShapeMetadata *metadata ) +{ + mMapTool->clean(); + mMapTool->setCurrentCaptureTechnique( QgsMapToolCapture::CaptureTechnique::Shape ); + mMapTool->setCurrentShapeMapTool( metadata ) ; +} QgsFeatureId TestQgsMapToolCircle::drawCircleFrom2Points() { - QgsMapToolCircle2Points mapTool( mParentTool, mCanvas ); - mCanvas->setMapTool( &mapTool ); + QgsMapToolShapeCircle2PointsMetadata md; + resetMapTool( &md ); - TestQgsMapToolAdvancedDigitizingUtils utils( &mapTool ); + TestQgsMapToolAdvancedDigitizingUtils utils( mMapTool ); utils.mouseClick( 0, 0, Qt::LeftButton ); utils.mouseMove( 0, 2 ); utils.mouseClick( 0, 2, Qt::RightButton ); @@ -192,10 +202,10 @@ QgsFeatureId TestQgsMapToolCircle::drawCircleFrom2Points() QgsFeatureId TestQgsMapToolCircle::drawCircleFrom2PointsWithDeletedVertex() { - QgsMapToolCircle2Points mapTool( mParentTool, mCanvas ); - mCanvas->setMapTool( &mapTool ); + QgsMapToolShapeCircle2PointsMetadata md; + resetMapTool( &md ); - TestQgsMapToolAdvancedDigitizingUtils utils( &mapTool ); + TestQgsMapToolAdvancedDigitizingUtils utils( mMapTool ); utils.mouseClick( 4, 1, Qt::LeftButton ); utils.keyClick( Qt::Key_Backspace ); utils.mouseClick( 0, 0, Qt::LeftButton ); @@ -207,10 +217,10 @@ QgsFeatureId TestQgsMapToolCircle::drawCircleFrom2PointsWithDeletedVertex() QgsFeatureId TestQgsMapToolCircle::drawCircleFrom3Points() { - QgsMapToolCircle3Points mapTool( mParentTool, mCanvas ); - mCanvas->setMapTool( &mapTool ); + QgsMapToolShapeCircle3PointsMetadata md; + resetMapTool( &md ); - TestQgsMapToolAdvancedDigitizingUtils utils( &mapTool ); + TestQgsMapToolAdvancedDigitizingUtils utils( mMapTool ); utils.mouseClick( 0, 0, Qt::LeftButton ); utils.mouseClick( 0, 2, Qt::LeftButton ); utils.mouseMove( 1, 1 ); @@ -221,10 +231,10 @@ QgsFeatureId TestQgsMapToolCircle::drawCircleFrom3Points() QgsFeatureId TestQgsMapToolCircle::drawCircleFrom3PointsWithDeletedVertex() { - QgsMapToolCircle3Points mapTool( mParentTool, mCanvas ); - mCanvas->setMapTool( &mapTool ); + QgsMapToolShapeCircle3PointsMetadata md; + resetMapTool( &md ); - TestQgsMapToolAdvancedDigitizingUtils utils( &mapTool ); + TestQgsMapToolAdvancedDigitizingUtils utils( mMapTool ); utils.mouseClick( 0, 0, Qt::LeftButton ); utils.mouseClick( 4, 1, Qt::LeftButton ); utils.keyClick( Qt::Key_Backspace ); @@ -237,10 +247,10 @@ QgsFeatureId TestQgsMapToolCircle::drawCircleFrom3PointsWithDeletedVertex() QgsFeatureId TestQgsMapToolCircle::drawCircleFromCenterPoint() { - QgsMapToolCircleCenterPoint mapTool( mParentTool, mCanvas ); - mCanvas->setMapTool( &mapTool ); + QgsMapToolShapeCircleCenterPointMetadata md; + resetMapTool( &md ); - TestQgsMapToolAdvancedDigitizingUtils utils( &mapTool ); + TestQgsMapToolAdvancedDigitizingUtils utils( mMapTool ); utils.mouseClick( 0, 0, Qt::LeftButton ); utils.mouseMove( 0, 2 ); utils.mouseClick( 0, 2, Qt::RightButton ); @@ -250,10 +260,10 @@ QgsFeatureId TestQgsMapToolCircle::drawCircleFromCenterPoint() QgsFeatureId TestQgsMapToolCircle::drawCircleFromCenterPointWithDeletedVertex() { - QgsMapToolCircleCenterPoint mapTool( mParentTool, mCanvas ); - mCanvas->setMapTool( &mapTool ); + QgsMapToolShapeCircleCenterPointMetadata md; + resetMapTool( &md ); - TestQgsMapToolAdvancedDigitizingUtils utils( &mapTool ); + TestQgsMapToolAdvancedDigitizingUtils utils( mMapTool ); utils.mouseClick( 4, 1, Qt::LeftButton ); utils.keyClick( Qt::Key_Backspace ); utils.mouseClick( 0, 0, Qt::LeftButton ); @@ -281,12 +291,12 @@ void TestQgsMapToolCircle::testCircle_data() QString rowStringName; - for ( QString coordinate : mCoordinateList ) + for ( const QString &coordinate : std::as_const( mCoordinateList ) ) { mLayer = mVectorLayerMap[coordinate].get(); mCanvas->setCurrentLayer( mLayer ); - for ( QString drawMethod : mDrawingCircleMethods ) + for ( const QString &drawMethod : std::as_const( mDrawingCircleMethods ) ) { mLayer->startEditing(); newFid = mDrawFunctionPtrMap[drawMethod](); diff --git a/tests/src/app/testqgsmaptoolcircularstring.cpp b/tests/src/app/testqgsmaptoolcircularstring.cpp index acab4b01efdb..f83ca4b568cf 100644 --- a/tests/src/app/testqgsmaptoolcircularstring.cpp +++ b/tests/src/app/testqgsmaptoolcircularstring.cpp @@ -23,8 +23,7 @@ #include "qgsmaptooladdfeature.h" #include "testqgsmaptoolutils.h" -#include "qgsmaptoolcircularstringcurvepoint.h" -#include "qgsmaptoolcircularstringradius.h" +#include "qgsmaptoolshapecircularstringradius.h" class TestQgsMapToolCircularString : public QObject @@ -37,16 +36,18 @@ class TestQgsMapToolCircularString : public QObject private slots: void initTestCase(); void cleanupTestCase(); + void cleanup(); void testAddCircularStringCurvePoint(); void testAddCircularStringRadius(); - void testAddCircularStringCurvePointWithDeletedVertex(); void testAddCircularStringRadiusWithDeletedVertex(); void testAddCircularStringAfterClassicDigitizing(); private: + void resetMapTool( QgsMapToolShapeMetadata *metadata ); + QgisApp *mQgisApp = nullptr; - QgsMapToolCapture *mParentTool = nullptr; + QgsMapToolCapture *mMapTool = nullptr; QgsMapCanvas *mCanvas = nullptr; QgsVectorLayer *mLayer = nullptr; }; @@ -66,7 +67,7 @@ void TestQgsMapToolCircularString::initTestCase() mCanvas->setDestinationCrs( QgsCoordinateReferenceSystem( QStringLiteral( "EPSG:27700" ) ) ); // make testing layers - mLayer = new QgsVectorLayer( QStringLiteral( "LineStringZ?crs=EPSG:27700" ), QStringLiteral( "layer line Z" ), QStringLiteral( "memory" ) ); + mLayer = new QgsVectorLayer( QStringLiteral( "CompoundCurveZ?crs=EPSG:27700" ), QStringLiteral( "layer line Z" ), QStringLiteral( "memory" ) ); QVERIFY( mLayer->isValid() ); QgsProject::instance()->addMapLayers( QList() << mLayer ); @@ -74,55 +75,39 @@ void TestQgsMapToolCircularString::initTestCase() mCanvas->setLayers( QList() << mLayer ); mCanvas->setCurrentLayer( mLayer ); - mParentTool = new QgsMapToolAddFeature( mCanvas, QgsMapToolCapture::CaptureLine ); + mMapTool = new QgsMapToolAddFeature( mCanvas, QgsMapToolCapture::CaptureLine ); + mMapTool->setCurrentCaptureTechnique( QgsMapToolCapture::Shape ); + } void TestQgsMapToolCircularString::cleanupTestCase() { QgsApplication::exitQgis(); + delete mMapTool; } -void TestQgsMapToolCircularString::testAddCircularStringCurvePoint() +void TestQgsMapToolCircularString::cleanup() { - QgsSettingsRegistryCore::settingsDigitizingDefaultZValue.setValue( 333 ); - mLayer->startEditing(); - - QgsMapToolCircularStringCurvePoint mapTool( mParentTool, mCanvas ); - mCanvas->setMapTool( &mapTool ); - - TestQgsMapToolAdvancedDigitizingUtils utils( &mapTool ); - utils.mouseClick( 0, 0, Qt::LeftButton ); - utils.mouseClick( 1, 1, Qt::LeftButton ); - utils.mouseClick( 0, 2, Qt::LeftButton ); - utils.mouseClick( 0, 2, Qt::RightButton ); - const QgsFeatureId newFid = utils.newFeatureId(); - - QCOMPARE( mLayer->featureCount(), ( long )1 ); - const QgsFeature f = mLayer->getFeature( newFid ); - - const QString wkt = "CompoundCurveZ (CircularStringZ (0 0 333, 1 1 333, 0 2 333))"; - QCOMPARE( f.geometry().asWkt(), wkt ); + mMapTool->clean(); +} - mLayer->rollBack(); - QgsSettingsRegistryCore::settingsDigitizingDefaultZValue.setValue( 0 ); +void TestQgsMapToolCircularString::resetMapTool( QgsMapToolShapeMetadata *metadata ) +{ + mMapTool->setCurrentCaptureTechnique( QgsMapToolCapture::CaptureTechnique::Shape ); + mMapTool->setCurrentShapeMapTool( metadata ) ; } -void TestQgsMapToolCircularString::testAddCircularStringCurvePointWithDeletedVertex() +void TestQgsMapToolCircularString::testAddCircularStringCurvePoint() { QgsSettingsRegistryCore::settingsDigitizingDefaultZValue.setValue( 333 ); mLayer->startEditing(); - QgsMapToolCircularStringCurvePoint mapTool( mParentTool, mCanvas ); - mCanvas->setMapTool( &mapTool ); + mMapTool->setCurrentCaptureTechnique( QgsMapToolCapture::CaptureTechnique::CircularString ); - TestQgsMapToolAdvancedDigitizingUtils utils( &mapTool ); + TestQgsMapToolAdvancedDigitizingUtils utils( mMapTool ); utils.mouseClick( 0, 0, Qt::LeftButton ); - utils.mouseClick( 4, 1, Qt::LeftButton ); - utils.keyClick( Qt::Key_Backspace ); utils.mouseClick( 1, 1, Qt::LeftButton ); utils.mouseClick( 0, 2, Qt::LeftButton ); - utils.mouseClick( 4, 1, Qt::LeftButton ); - utils.keyClick( Qt::Key_Backspace ); utils.mouseClick( 0, 2, Qt::RightButton ); const QgsFeatureId newFid = utils.newFeatureId(); @@ -135,15 +120,16 @@ void TestQgsMapToolCircularString::testAddCircularStringCurvePointWithDeletedVer mLayer->rollBack(); QgsSettingsRegistryCore::settingsDigitizingDefaultZValue.setValue( 0 ); } + void TestQgsMapToolCircularString::testAddCircularStringRadius() { QgsSettingsRegistryCore::settingsDigitizingDefaultZValue.setValue( 111 ); mLayer->startEditing(); - QgsMapToolCircularStringRadius mapTool( mParentTool, mCanvas ); - mCanvas->setMapTool( &mapTool ); + QgsMapToolShapeCircularStringRadiusMetadata md; + resetMapTool( &md ); - TestQgsMapToolAdvancedDigitizingUtils utils( &mapTool ); + TestQgsMapToolAdvancedDigitizingUtils utils( mMapTool ); utils.mouseClick( 0, 0, Qt::LeftButton ); utils.mouseClick( 1, 1, Qt::LeftButton ); utils.mouseClick( 0, 2, Qt::LeftButton ); @@ -165,10 +151,10 @@ void TestQgsMapToolCircularString::testAddCircularStringRadiusWithDeletedVertex( QgsSettingsRegistryCore::settingsDigitizingDefaultZValue.setValue( 111 ); mLayer->startEditing(); - QgsMapToolCircularStringRadius mapTool( mParentTool, mCanvas ); - mCanvas->setMapTool( &mapTool ); + QgsMapToolShapeCircularStringRadiusMetadata md; + resetMapTool( &md ); - TestQgsMapToolAdvancedDigitizingUtils utils( &mapTool ); + TestQgsMapToolAdvancedDigitizingUtils utils( mMapTool ); utils.mouseClick( 0, 0, Qt::LeftButton ); utils.mouseClick( 1, 1, Qt::LeftButton ); utils.mouseClick( 4, 1, Qt::LeftButton ); @@ -194,21 +180,20 @@ void TestQgsMapToolCircularString::testAddCircularStringAfterClassicDigitizing() QgsSettingsRegistryCore::settingsDigitizingDefaultZValue.setValue( 333 ); mLayer->startEditing(); - TestQgsMapToolAdvancedDigitizingUtils utilsClassic( mParentTool ); + mMapTool->setCurrentCaptureTechnique( QgsMapToolCapture::CaptureTechnique::StraightSegments ); - mCanvas->setMapTool( mParentTool ); + TestQgsMapToolAdvancedDigitizingUtils utilsClassic( mMapTool ); utilsClassic.mouseClick( 2, 1, Qt::LeftButton ); utilsClassic.mouseClick( 2, 0, Qt::LeftButton ); utilsClassic.mouseClick( 0, 0, Qt::LeftButton ); - QgsMapToolCircularStringCurvePoint mapTool( mParentTool, mCanvas ); - mCanvas->setMapTool( &mapTool ); + mMapTool->setCurrentCaptureTechnique( QgsMapToolCapture::CaptureTechnique::CircularString ); - TestQgsMapToolAdvancedDigitizingUtils utilsCircular( &mapTool ); + TestQgsMapToolAdvancedDigitizingUtils utilsCircular( mMapTool ); utilsCircular.mouseClick( 1, 1, Qt::LeftButton ); utilsCircular.mouseClick( 0, 2, Qt::LeftButton ); - mCanvas->setMapTool( mParentTool ); + mMapTool->setCurrentCaptureTechnique( QgsMapToolCapture::CaptureTechnique::StraightSegments ); utilsClassic.mouseClick( 2, 2, Qt::LeftButton ); utilsClassic.mouseClick( 4, 2, Qt::LeftButton ); diff --git a/tests/src/app/testqgsmaptoolellipse.cpp b/tests/src/app/testqgsmaptoolellipse.cpp index c5d3e7563952..f545774de40f 100644 --- a/tests/src/app/testqgsmaptoolellipse.cpp +++ b/tests/src/app/testqgsmaptoolellipse.cpp @@ -25,28 +25,30 @@ #include "qgsmaptooladdfeature.h" #include "testqgsmaptoolutils.h" -#include "qgsmaptoolellipsecenterpoint.h" -#include "qgsmaptoolellipsecenter2points.h" -#include "qgsmaptoolellipseextent.h" -#include "qgsmaptoolellipsefoci.h" +#include "qgsmaptoolcapture.h" + +#include "qgsmaptoolshapeellipsecenterpoint.h" +#include "qgsmaptoolshapeellipsecenter2points.h" +#include "qgsmaptoolshapeellipseextent.h" +#include "qgsmaptoolshapeellipsefoci.h" class TestQgsMapToolEllipse : public QObject { Q_OBJECT public: - TestQgsMapToolEllipse(); + TestQgsMapToolEllipse() = default; private slots: - void initTestCase(); - void cleanupTestCase(); + void initTestCase(); // will be called before the first testfunction is executed. + void cleanupTestCase(); // will be called after the last testfunction was executed. void testEllipse_data(); void testEllipse(); private: QgisApp *mQgisApp = nullptr; - QgsMapToolCapture *mParentTool = nullptr; + QgsMapToolCapture *mMapTool = nullptr; QgsMapCanvas *mCanvas = nullptr; std::map> mVectorLayerMap = {}; @@ -67,6 +69,8 @@ class TestQgsMapToolEllipse : public QObject void initAttributs(); + void resetMapTool( QgsMapToolShapeMetadata *metadata ); + QgsFeatureId drawEllipseFromCenterAndPoint(); QgsFeatureId drawEllipseFromCenterAndPointWithDeletedVertex(); QgsFeatureId drawEllipseFromCenterAnd2Points(); @@ -83,8 +87,6 @@ class TestQgsMapToolEllipse : public QObject unsigned int segments( ) { return QgsSettingsRegistryCore::settingsDigitizingOffsetQuadSeg.value() * 12; } }; -TestQgsMapToolEllipse::TestQgsMapToolEllipse() = default; - //runs before all tests void TestQgsMapToolEllipse::initTestCase() @@ -119,7 +121,9 @@ void TestQgsMapToolEllipse::initTestCase() QgsProject::instance()->addMapLayers( layerList ); mCanvas->setLayers( layerList ); - mParentTool = new QgsMapToolAddFeature( mCanvas, QgsMapToolCapture::CaptureLine ); + mMapTool = new QgsMapToolAddFeature( mCanvas, QgsMapToolCapture::CaptureLine ); + mMapTool->setCurrentCaptureTechnique( QgsMapToolCapture::Shape ); + mCanvas->setMapTool( mMapTool ); initAttributs(); } @@ -183,21 +187,28 @@ void TestQgsMapToolEllipse::initAttributs() void TestQgsMapToolEllipse::cleanupTestCase() { - - for ( QString coordinate : mCoordinateList ) + for ( const QString &coordinate : std::as_const( mCoordinateList ) ) { mVectorLayerMap[coordinate].reset(); } + + delete mMapTool; + QgsApplication::exitQgis(); } +void TestQgsMapToolEllipse::resetMapTool( QgsMapToolShapeMetadata *metadata ) +{ + mMapTool->clean(); + mMapTool->setCurrentCaptureTechnique( QgsMapToolCapture::Shape ); + mMapTool->setCurrentShapeMapTool( metadata ) ; +} QgsFeatureId TestQgsMapToolEllipse::drawEllipseFromCenterAndPoint() { - QgsMapToolEllipseCenterPoint mapTool( mParentTool, mCanvas ); - mCanvas->setMapTool( &mapTool ); + resetMapTool( new QgsMapToolShapeEllipseCenterPointMetadata() ); - TestQgsMapToolAdvancedDigitizingUtils utils( &mapTool ); + TestQgsMapToolAdvancedDigitizingUtils utils( mMapTool ); utils.mouseClick( 0, 0, Qt::LeftButton ); utils.mouseMove( 1, -1 ); utils.mouseClick( 1, -1, Qt::RightButton ); @@ -207,10 +218,9 @@ QgsFeatureId TestQgsMapToolEllipse::drawEllipseFromCenterAndPoint() QgsFeatureId TestQgsMapToolEllipse::drawEllipseFromCenterAndPointWithDeletedVertex() { - QgsMapToolEllipseCenterPoint mapTool( mParentTool, mCanvas ); - mCanvas->setMapTool( &mapTool ); + resetMapTool( new QgsMapToolShapeEllipseCenterPointMetadata() ); - TestQgsMapToolAdvancedDigitizingUtils utils( &mapTool ); + TestQgsMapToolAdvancedDigitizingUtils utils( mMapTool ); utils.mouseClick( 4, 1, Qt::LeftButton ); utils.keyClick( Qt::Key_Backspace ); utils.mouseClick( 0, 0, Qt::LeftButton ); @@ -222,10 +232,9 @@ QgsFeatureId TestQgsMapToolEllipse::drawEllipseFromCenterAndPointWithDeletedVert QgsFeatureId TestQgsMapToolEllipse::drawEllipseFromCenterAnd2Points() { - QgsMapToolEllipseCenter2Points mapTool( mParentTool, mCanvas ); - mCanvas->setMapTool( &mapTool ); + resetMapTool( new QgsMapToolShapeEllipseCenter2PointsMetadata() ); - TestQgsMapToolAdvancedDigitizingUtils utils( &mapTool ); + TestQgsMapToolAdvancedDigitizingUtils utils( mMapTool ); utils.mouseClick( 0, 0, Qt::LeftButton ); utils.mouseClick( 0, 1, Qt::LeftButton ); utils.mouseMove( 0, -1 ); @@ -236,10 +245,9 @@ QgsFeatureId TestQgsMapToolEllipse::drawEllipseFromCenterAnd2Points() QgsFeatureId TestQgsMapToolEllipse::drawEllipseFromCenterAnd2PointsWithDeletedVertex() { - QgsMapToolEllipseCenter2Points mapTool( mParentTool, mCanvas ); - mCanvas->setMapTool( &mapTool ); + resetMapTool( new QgsMapToolShapeEllipseCenter2PointsMetadata() ); - TestQgsMapToolAdvancedDigitizingUtils utils( &mapTool ); + TestQgsMapToolAdvancedDigitizingUtils utils( mMapTool ); utils.mouseClick( 0, 0, Qt::LeftButton ); utils.mouseClick( 4, 1, Qt::LeftButton ); utils.keyClick( Qt::Key_Backspace ); @@ -252,10 +260,9 @@ QgsFeatureId TestQgsMapToolEllipse::drawEllipseFromCenterAnd2PointsWithDeletedVe QgsFeatureId TestQgsMapToolEllipse::drawEllipseFromExtent() { - QgsMapToolEllipseExtent mapTool( mParentTool, mCanvas ); - mCanvas->setMapTool( &mapTool ); + resetMapTool( new QgsMapToolShapeEllipseExtentMetadata() ); - TestQgsMapToolAdvancedDigitizingUtils utils( &mapTool ); + TestQgsMapToolAdvancedDigitizingUtils utils( mMapTool ); utils.mouseClick( 0, 0, Qt::LeftButton ); utils.mouseMove( 2, 2 ); utils.mouseClick( 2, 2, Qt::RightButton ); @@ -265,10 +272,9 @@ QgsFeatureId TestQgsMapToolEllipse::drawEllipseFromExtent() QgsFeatureId TestQgsMapToolEllipse::drawEllipseFromExtentWithDeletedVertex() { - QgsMapToolEllipseExtent mapTool( mParentTool, mCanvas ); - mCanvas->setMapTool( &mapTool ); + resetMapTool( new QgsMapToolShapeEllipseExtentMetadata() ); - TestQgsMapToolAdvancedDigitizingUtils utils( &mapTool ); + TestQgsMapToolAdvancedDigitizingUtils utils( mMapTool ); utils.mouseClick( 4, 1, Qt::LeftButton ); utils.keyClick( Qt::Key_Backspace ); utils.mouseClick( 0, 0, Qt::LeftButton ); @@ -280,10 +286,9 @@ QgsFeatureId TestQgsMapToolEllipse::drawEllipseFromExtentWithDeletedVertex() QgsFeatureId TestQgsMapToolEllipse::drawEllipseFromFoci() { - QgsMapToolEllipseFoci mapTool( mParentTool, mCanvas ); - mCanvas->setMapTool( &mapTool ); + resetMapTool( new QgsMapToolShapeEllipseFociMetadata() ); - TestQgsMapToolAdvancedDigitizingUtils utils( &mapTool ); + TestQgsMapToolAdvancedDigitizingUtils utils( mMapTool ); utils.mouseClick( 0, 0, Qt::LeftButton ); utils.mouseMove( 1, -1 ); utils.mouseClick( 1, -1, Qt::LeftButton ); @@ -295,10 +300,9 @@ QgsFeatureId TestQgsMapToolEllipse::drawEllipseFromFoci() QgsFeatureId TestQgsMapToolEllipse::drawEllipseFromFociWithDeletedVertex() { - QgsMapToolEllipseFoci mapTool( mParentTool, mCanvas ); - mCanvas->setMapTool( &mapTool ); + resetMapTool( new QgsMapToolShapeEllipseFociMetadata() ); - TestQgsMapToolAdvancedDigitizingUtils utils( &mapTool ); + TestQgsMapToolAdvancedDigitizingUtils utils( mMapTool ); utils.mouseClick( 4, 1, Qt::LeftButton ); utils.keyClick( Qt::Key_Backspace ); utils.mouseClick( 0, 0, Qt::LeftButton ); @@ -328,12 +332,12 @@ void TestQgsMapToolEllipse::testEllipse_data() QString rowStringName; - for ( QString coordinate : mCoordinateList ) + for ( const QString &coordinate : std::as_const( mCoordinateList ) ) { mLayer = mVectorLayerMap[coordinate].get(); mCanvas->setCurrentLayer( mLayer ); - for ( QString drawMethod : mDrawingEllipseMethods ) + for ( const QString &drawMethod : std::as_const( mDrawingEllipseMethods ) ) { mLayer->startEditing(); mLayer->dataProvider()->truncate(); diff --git a/tests/src/app/testqgsmaptoolrectangle.cpp b/tests/src/app/testqgsmaptoolrectangle.cpp index eb54a18f6b48..17ff02047d15 100644 --- a/tests/src/app/testqgsmaptoolrectangle.cpp +++ b/tests/src/app/testqgsmaptoolrectangle.cpp @@ -24,9 +24,9 @@ #include "qgsgeometryutils.h" #include "testqgsmaptoolutils.h" -#include "qgsmaptoolrectanglecenter.h" -#include "qgsmaptoolrectangleextent.h" -#include "qgsmaptoolrectangle3points.h" +#include "qgsmaptoolshaperectanglecenter.h" +#include "qgsmaptoolshaperectangleextent.h" +#include "qgsmaptoolshaperectangle3points.h" class TestQgsMapToolRectangle : public QObject @@ -39,6 +39,7 @@ class TestQgsMapToolRectangle : public QObject private slots: void initTestCase(); void cleanupTestCase(); + void cleanup(); void testRectangleFromCenter(); void testRectangleFromCenterWithDeletedVertex(); @@ -50,8 +51,10 @@ class TestQgsMapToolRectangle : public QObject void testRectangleFrom3PointsProjectedWithDeletedVertex(); private: + void resetMapTool( QgsMapToolShapeMetadata *metadata ); + QgisApp *mQgisApp = nullptr; - QgsMapToolCapture *mParentTool = nullptr; + QgsMapToolCapture *mMapTool = nullptr; QgsMapCanvas *mCanvas = nullptr; QgsVectorLayer *mLayer = nullptr; }; @@ -79,12 +82,25 @@ void TestQgsMapToolRectangle::initTestCase() mCanvas->setLayers( QList() << mLayer ); mCanvas->setCurrentLayer( mLayer ); - mParentTool = new QgsMapToolAddFeature( mCanvas, QgsMapToolCapture::CaptureLine ); + mMapTool = new QgsMapToolAddFeature( mCanvas, QgsMapToolCapture::CaptureLine ); + mMapTool->setCurrentCaptureTechnique( QgsMapToolCapture::Shape ); + mCanvas->setMapTool( mMapTool ); } void TestQgsMapToolRectangle::cleanupTestCase() { QgsApplication::exitQgis(); + delete mMapTool; +} + +void TestQgsMapToolRectangle::cleanup() +{ + mMapTool->clean(); +} + +void TestQgsMapToolRectangle::resetMapTool( QgsMapToolShapeMetadata *metadata ) +{ + mMapTool->setCurrentShapeMapTool( metadata ) ; } void TestQgsMapToolRectangle::testRectangleFromCenter() @@ -92,10 +108,10 @@ void TestQgsMapToolRectangle::testRectangleFromCenter() QgsSettingsRegistryCore::settingsDigitizingDefaultZValue.setValue( 333 ); mLayer->startEditing(); - QgsMapToolRectangleCenter mapTool( mParentTool, mCanvas ); - mCanvas->setMapTool( &mapTool ); + QgsMapToolShapeRectangleCenterMetadata md; + resetMapTool( &md ); - TestQgsMapToolAdvancedDigitizingUtils utils( &mapTool ); + TestQgsMapToolAdvancedDigitizingUtils utils( mMapTool ); utils.mouseClick( 0, 0, Qt::LeftButton ); utils.mouseMove( 2, 1 ); utils.mouseClick( 2, 1, Qt::RightButton ); @@ -118,10 +134,10 @@ void TestQgsMapToolRectangle::testRectangleFromCenterWithDeletedVertex() QgsSettingsRegistryCore::settingsDigitizingDefaultZValue.setValue( 333 ); mLayer->startEditing(); - QgsMapToolRectangleCenter mapTool( mParentTool, mCanvas ); - mCanvas->setMapTool( &mapTool ); + QgsMapToolShapeRectangleCenterMetadata md; + resetMapTool( &md ); - TestQgsMapToolAdvancedDigitizingUtils utils( &mapTool ); + TestQgsMapToolAdvancedDigitizingUtils utils( mMapTool ); utils.mouseClick( 4, 1, Qt::LeftButton ); utils.keyClick( Qt::Key_Backspace ); utils.mouseClick( 0, 0, Qt::LeftButton ); @@ -146,10 +162,10 @@ void TestQgsMapToolRectangle::testRectangleFromExtent() QgsSettingsRegistryCore::settingsDigitizingDefaultZValue.setValue( 222 ); mLayer->startEditing(); - QgsMapToolRectangleExtent mapTool( mParentTool, mCanvas ); - mCanvas->setMapTool( &mapTool ); + QgsMapToolShapeRectangleExtentMetadata md; + resetMapTool( &md ); - TestQgsMapToolAdvancedDigitizingUtils utils( &mapTool ); + TestQgsMapToolAdvancedDigitizingUtils utils( mMapTool ); utils.mouseClick( 0, 0, Qt::LeftButton ); utils.mouseMove( 2, 1 ); utils.mouseClick( 2, 1, Qt::RightButton ); @@ -171,10 +187,10 @@ void TestQgsMapToolRectangle::testRectangleFromExtentWithDeletedVertex() QgsSettingsRegistryCore::settingsDigitizingDefaultZValue.setValue( 222 ); mLayer->startEditing(); - QgsMapToolRectangleExtent mapTool( mParentTool, mCanvas ); - mCanvas->setMapTool( &mapTool ); + QgsMapToolShapeRectangleExtentMetadata md; + resetMapTool( &md ); - TestQgsMapToolAdvancedDigitizingUtils utils( &mapTool ); + TestQgsMapToolAdvancedDigitizingUtils utils( mMapTool ); utils.mouseClick( 4, 1, Qt::LeftButton ); utils.keyClick( Qt::Key_Backspace ); utils.mouseClick( 0, 0, Qt::LeftButton ); @@ -200,10 +216,10 @@ void TestQgsMapToolRectangle::testRectangleFrom3PointsDistance() QgsSettingsRegistryCore::settingsDigitizingDefaultZValue.setValue( 111 ); mLayer->startEditing(); - QgsMapToolRectangle3Points mapTool( mParentTool, mCanvas, QgsMapToolRectangle3Points::DistanceMode ); - mCanvas->setMapTool( &mapTool ); + QgsMapToolShapeRectangle3PointsMetadata md( QgsMapToolShapeRectangle3PointsMetadata::CreateMode::Distance ); + resetMapTool( &md ); - TestQgsMapToolAdvancedDigitizingUtils utils( &mapTool ); + TestQgsMapToolAdvancedDigitizingUtils utils( mMapTool ); utils.mouseClick( 0, 0, Qt::LeftButton ); utils.mouseMove( 2, 0 ); utils.mouseClick( 2, 0, Qt::LeftButton ); @@ -227,10 +243,10 @@ void TestQgsMapToolRectangle::testRectangleFrom3PointsDistanceWithDeletedVertex( QgsSettingsRegistryCore::settingsDigitizingDefaultZValue.setValue( 111 ); mLayer->startEditing(); - QgsMapToolRectangle3Points mapTool( mParentTool, mCanvas, QgsMapToolRectangle3Points::DistanceMode ); - mCanvas->setMapTool( &mapTool ); + QgsMapToolShapeRectangle3PointsMetadata md( QgsMapToolShapeRectangle3PointsMetadata::CreateMode::Distance ); + resetMapTool( &md ); - TestQgsMapToolAdvancedDigitizingUtils utils( &mapTool ); + TestQgsMapToolAdvancedDigitizingUtils utils( mMapTool ); utils.mouseClick( 0, 0, Qt::LeftButton ); utils.mouseMove( 2, 0 ); utils.mouseClick( 3, 0, Qt::LeftButton ); @@ -257,10 +273,10 @@ void TestQgsMapToolRectangle::testRectangleFrom3PointsProjected() QgsSettingsRegistryCore::settingsDigitizingDefaultZValue.setValue( 111 ); mLayer->startEditing(); - QgsMapToolRectangle3Points mapTool( mParentTool, mCanvas, QgsMapToolRectangle3Points::ProjectedMode ); - mCanvas->setMapTool( &mapTool ); + QgsMapToolShapeRectangle3PointsMetadata md( QgsMapToolShapeRectangle3PointsMetadata::CreateMode::Projected ); + resetMapTool( &md ); - TestQgsMapToolAdvancedDigitizingUtils utils( &mapTool ); + TestQgsMapToolAdvancedDigitizingUtils utils( mMapTool ); utils.mouseClick( 0, 0, Qt::LeftButton ); utils.mouseMove( 2, 0 ); utils.mouseClick( 2, 0, Qt::LeftButton ); @@ -284,10 +300,10 @@ void TestQgsMapToolRectangle::testRectangleFrom3PointsProjectedWithDeletedVertex QgsSettingsRegistryCore::settingsDigitizingDefaultZValue.setValue( 111 ); mLayer->startEditing(); - QgsMapToolRectangle3Points mapTool( mParentTool, mCanvas, QgsMapToolRectangle3Points::ProjectedMode ); - mCanvas->setMapTool( &mapTool ); + QgsMapToolShapeRectangle3PointsMetadata md( QgsMapToolShapeRectangle3PointsMetadata::CreateMode::Projected ); + resetMapTool( &md ); - TestQgsMapToolAdvancedDigitizingUtils utils( &mapTool ); + TestQgsMapToolAdvancedDigitizingUtils utils( mMapTool ); utils.mouseClick( 0, 0, Qt::LeftButton ); utils.mouseMove( 2, 0 ); utils.mouseClick( 3, 0, Qt::LeftButton ); diff --git a/tests/src/app/testqgsmaptoolregularpolygon.cpp b/tests/src/app/testqgsmaptoolregularpolygon.cpp index bf7350b52547..8535afa381e0 100644 --- a/tests/src/app/testqgsmaptoolregularpolygon.cpp +++ b/tests/src/app/testqgsmaptoolregularpolygon.cpp @@ -24,9 +24,9 @@ #include "qgsgeometryutils.h" #include "testqgsmaptoolutils.h" -#include "qgsmaptoolregularpolygon2points.h" -#include "qgsmaptoolregularpolygoncenterpoint.h" -#include "qgsmaptoolregularpolygoncentercorner.h" +#include "qgsmaptoolshaperegularpolygon2points.h" +#include "qgsmaptoolshaperegularpolygoncenterpoint.h" +#include "qgsmaptoolshaperegularpolygoncentercorner.h" class TestQgsMapToolRegularPolygon : public QObject @@ -39,6 +39,7 @@ class TestQgsMapToolRegularPolygon : public QObject private slots: void initTestCase(); void cleanupTestCase(); + void cleanup(); void testRegularPolygonFrom2Points(); void testRegularPolygonFrom2PointsWithDeletedVertex(); @@ -48,8 +49,10 @@ class TestQgsMapToolRegularPolygon : public QObject void testRegularPolygonFromCenterAndCronerWithDeletedVertex(); private: + void resetMapTool( QgsMapToolShapeMetadata *metadata ); + QgisApp *mQgisApp = nullptr; - QgsMapToolCapture *mParentTool = nullptr; + QgsMapToolCapture *mMapTool = nullptr; QgsMapCanvas *mCanvas = nullptr; QgsVectorLayer *mLayer = nullptr; }; @@ -77,12 +80,25 @@ void TestQgsMapToolRegularPolygon::initTestCase() mCanvas->setLayers( QList() << mLayer ); mCanvas->setCurrentLayer( mLayer ); - mParentTool = new QgsMapToolAddFeature( mCanvas, QgsMapToolCapture::CaptureLine ); + mMapTool = new QgsMapToolAddFeature( mCanvas, QgsMapToolCapture::CaptureLine ); + mMapTool->setCurrentCaptureTechnique( QgsMapToolCapture::Shape ); + mCanvas->setMapTool( mMapTool ); } void TestQgsMapToolRegularPolygon::cleanupTestCase() { QgsApplication::exitQgis(); + delete mMapTool; +} + +void TestQgsMapToolRegularPolygon::cleanup() +{ + mMapTool->clean(); +} + +void TestQgsMapToolRegularPolygon::resetMapTool( QgsMapToolShapeMetadata *metadata ) +{ + mMapTool->setCurrentShapeMapTool( metadata ) ; } void TestQgsMapToolRegularPolygon::testRegularPolygonFrom2Points() @@ -90,10 +106,10 @@ void TestQgsMapToolRegularPolygon::testRegularPolygonFrom2Points() QgsSettingsRegistryCore::settingsDigitizingDefaultZValue.setValue( 333 ); mLayer->startEditing(); - QgsMapToolRegularPolygon2Points mapTool( mParentTool, mCanvas ); - mCanvas->setMapTool( &mapTool ); + QgsMapToolShapeRegularPolygon2PointsMetadata md; + resetMapTool( &md ); - TestQgsMapToolAdvancedDigitizingUtils utils( &mapTool ); + TestQgsMapToolAdvancedDigitizingUtils utils( mMapTool ); utils.mouseClick( 0, 0, Qt::LeftButton ); utils.mouseMove( 2, 1 ); utils.mouseClick( 2, 1, Qt::RightButton ); @@ -113,10 +129,10 @@ void TestQgsMapToolRegularPolygon::testRegularPolygonFrom2PointsWithDeletedVerte QgsSettingsRegistryCore::settingsDigitizingDefaultZValue.setValue( 333 ); mLayer->startEditing(); - QgsMapToolRegularPolygon2Points mapTool( mParentTool, mCanvas ); - mCanvas->setMapTool( &mapTool ); + QgsMapToolShapeRegularPolygon2PointsMetadata md; + resetMapTool( &md ); - TestQgsMapToolAdvancedDigitizingUtils utils( &mapTool ); + TestQgsMapToolAdvancedDigitizingUtils utils( mMapTool ); utils.mouseClick( 4, 1, Qt::LeftButton ); utils.keyClick( Qt::Key_Backspace ); utils.mouseClick( 0, 0, Qt::LeftButton ); @@ -140,10 +156,10 @@ void TestQgsMapToolRegularPolygon::testRegularPolygonFromCenterAndPoint() QgsSettingsRegistryCore::settingsDigitizingDefaultZValue.setValue( 222 ); mLayer->startEditing(); - QgsMapToolRegularPolygonCenterPoint mapTool( mParentTool, mCanvas ); - mCanvas->setMapTool( &mapTool ); + QgsMapToolShapeRegularPolygonCenterPointMetadata md; + resetMapTool( &md ); - TestQgsMapToolAdvancedDigitizingUtils utils( &mapTool ); + TestQgsMapToolAdvancedDigitizingUtils utils( mMapTool ); utils.mouseClick( 0, 0, Qt::LeftButton ); utils.mouseMove( 2, 1 ); utils.mouseClick( 2, 1, Qt::RightButton ); @@ -163,10 +179,10 @@ void TestQgsMapToolRegularPolygon::testRegularPolygonFromCenterAndPointWithDelet QgsSettingsRegistryCore::settingsDigitizingDefaultZValue.setValue( 222 ); mLayer->startEditing(); - QgsMapToolRegularPolygonCenterPoint mapTool( mParentTool, mCanvas ); - mCanvas->setMapTool( &mapTool ); + QgsMapToolShapeRegularPolygonCenterPointMetadata md; + resetMapTool( &md ); - TestQgsMapToolAdvancedDigitizingUtils utils( &mapTool ); + TestQgsMapToolAdvancedDigitizingUtils utils( mMapTool ); utils.mouseClick( 4, 1, Qt::LeftButton ); utils.keyClick( Qt::Key_Backspace ); utils.mouseClick( 0, 0, Qt::LeftButton ); @@ -190,10 +206,10 @@ void TestQgsMapToolRegularPolygon::testRegularPolygonFromCenterAndCroner() QgsSettingsRegistryCore::settingsDigitizingDefaultZValue.setValue( 111 ); mLayer->startEditing(); - QgsMapToolRegularPolygonCenterCorner mapTool( mParentTool, mCanvas ); - mCanvas->setMapTool( &mapTool ); + QgsMapToolShapeRegularPolygonCenterCornerMetadata md; + resetMapTool( &md ); - TestQgsMapToolAdvancedDigitizingUtils utils( &mapTool ); + TestQgsMapToolAdvancedDigitizingUtils utils( mMapTool ); utils.mouseClick( 0, 0, Qt::LeftButton ); utils.mouseMove( 2, 1 ); utils.mouseClick( 2, 1, Qt::RightButton ); @@ -213,10 +229,10 @@ void TestQgsMapToolRegularPolygon::testRegularPolygonFromCenterAndCronerWithDele QgsSettingsRegistryCore::settingsDigitizingDefaultZValue.setValue( 111 ); mLayer->startEditing(); - QgsMapToolRegularPolygonCenterCorner mapTool( mParentTool, mCanvas ); - mCanvas->setMapTool( &mapTool ); + QgsMapToolShapeRegularPolygonCenterCornerMetadata md; + resetMapTool( &md ); - TestQgsMapToolAdvancedDigitizingUtils utils( &mapTool ); + TestQgsMapToolAdvancedDigitizingUtils utils( mMapTool ); utils.mouseClick( 4, 1, Qt::LeftButton ); utils.keyClick( Qt::Key_Backspace ); utils.mouseClick( 0, 0, Qt::LeftButton ); diff --git a/tests/src/gui/testqgsrelationreferencewidget.cpp b/tests/src/gui/testqgsrelationreferencewidget.cpp index a782811e3b2c..b6591f7872c6 100644 --- a/tests/src/gui/testqgsrelationreferencewidget.cpp +++ b/tests/src/gui/testqgsrelationreferencewidget.cpp @@ -619,7 +619,7 @@ void TestQgsRelationReferenceWidget::testAddEntry() QVERIFY( w.mCurrentMapTool ); QgsFeature feat( mLayer1->fields() ); - w.mMapToolDigitize->digitized( feat ); + emit w.mMapToolDigitize->digitizingCompleted( feat ); QCOMPARE( w.mComboBox->identifierValues().at( 0 ).toInt(), 13 ); } diff --git a/tests/src/python/test_qgsgeometry.py b/tests/src/python/test_qgsgeometry.py index 0a56313998b8..9ddda6c5cff8 100644 --- a/tests/src/python/test_qgsgeometry.py +++ b/tests/src/python/test_qgsgeometry.py @@ -40,6 +40,7 @@ QgsProject, QgsVertexId, QgsAbstractGeometryTransformer, + QgsCircle, Qgis ) from qgis.PyQt.QtCore import QDir, QPointF, QRectF @@ -2336,6 +2337,29 @@ def multi_polygon_geom(): return QgsGeometry.fromMultiPolygonXY(poly_points) # n def multi_polygon1_geom(): return QgsGeometry.fromMultiPolygonXY(poly_points[:1]) # noqa: E704,E261 def multi_polygon2_geom(): return QgsGeometry.fromMultiPolygonXY(poly_points[1:]) # noqa: E704,E261 + def multi_surface_geom(): + ms = QgsMultiSurface() + p = polygon1_geom() + ms.addGeometry(p.constGet().clone()) + return QgsGeometry(ms) + + def curve(): + cs = QgsCircularString() + cs.setPoints([QgsPoint(31, 32), QgsPoint(34, 36), QgsPoint(37, 39)]) + return cs.toCurveType() + + circle = QgsCircle(QgsPoint(10, 10), 5) + + def circle_polygon(): + p = QgsPolygon() + p.setExteriorRing(circle.toCircularString()) + return p + + def circle_curvepolygon(): + p = QgsCurvePolygon() + p.setExteriorRing(circle.toCircularString()) + return p + geoms = {} # initial geometry parts = {} # part to add expec = {} # expected WKT result @@ -2373,6 +2397,11 @@ def multi_polygon2_geom(): return QgsGeometry.fromMultiPolygonXY(poly_points[1:] parts[T] = [QgsPoint(p[0], p[1], 3.0, wkbType=QgsWkbTypes.PointZ) for p in line_points[1]] expec[T] = "MultiLineStringZ ((0 0 4, 1 0 4, 1 1 4, 2 1 4, 2 0 4),(3 0 3, 3 1 3, 5 1 3, 5 0 3, 6 0 3))" + T = 'linestring_add_curve' + geoms[T] = polyline1_geom() + parts[T] = curve() + expec[T] = 'MultiLineString ({},{})'.format(polyline1_geom().asWkt()[len('LineString '):], curve().curveToLine().asWkt()[len('LineString '):]) + T = 'polygon_add_ring_1_point' geoms[T] = polygon1_geom() parts[T] = poly_points[1][0][0:1] @@ -2448,6 +2477,16 @@ def multi_polygon2_geom(): return QgsGeometry.fromMultiPolygonXY(poly_points[1:] types[T] = QgsWkbTypes.PolygonGeometry expec[T] = 'MultiPolygon (((0 0, 1 0, 1 1, 2 1, 2 2, 0 2, 0 0)))' + T = 'multipolygon_add_curvepolygon' + geoms[T] = multi_polygon1_geom() + parts[T] = circle_curvepolygon() + expec[T] = 'MultiPolygon ({},{})'.format(polygon1_geom().asWkt()[len('Polygon '):], circle_polygon().asWkt()[len('Polygon '):]) + + T = 'multisurface_add_curvepolygon' + geoms[T] = multi_surface_geom() + parts[T] = circle_curvepolygon() + expec[T] = 'MultiSurface (Polygon ((0 0, 1 0, 1 1, 2 1, 2 2, 0 2, 0 0)),CurvePolygon (CircularString (10 15, 15 10, 10 5, 5 10, 10 15)))' + for t in parts.keys(): with self.subTest(t=t): expected_result = resul.get(t, Qgis.GeometryOperationResult.Success)