[QGIS-Developer] Digitizing with Edit Menu

Yoann Quenach de Quivillic yoann.quenach at gmail.com
Mon May 1 13:17:18 PDT 2023


In that case, you could try the following to get the temp geometry being
drawn on the map.
*Note that this is kind of hackish, may not work for every tool, and might
break at any QGIS update*.

def getTempGeom():

    # Iter over map canvas items, starting from the end (most recent)
    for item in iface.mapCanvas().items()[::-1]:
        # If it is a valid QgsGeometryRubberBand, return its geometry
        if isinstance(item, QgsGeometryRubberBand):
            geom = item.geometry()
            if geom.area() > 0:
                return geom

        # If it is a valid QgsRubberBand, return its geometry
        if isinstance(item, QgsRubberBand):
            geom = item.asGeometry()
            if geom.area() > 0:
                return geom

In your eventFilter, you could just use getTempGeom, perform the area
computation, and display a tooltip with the current area.

Le lun. 1 mai 2023 à 18:00, Catania, Luke A ERDC-RDE-GRL-VA CIV <
Luke.A.Catania at erdc.dren.mil> a écrit :

> Thanks for taking the time to code that.  I originally coded with the
> featureAdded method.  When I first found it I was pretty happy with the
> solution, but then since the user does not get informed until after they
> draw the shape and it is already added to the layer and so the feature then
> needs to be deleted so they can try again.  This can go a few iterations.
>
>
>
> The previous version of the software I am working on which did not use
> QGIS but custom developed using R and Leaflet had this dynamic cursor that
> indicated the size and users miss that, so then I came across the
> eventFilter and applied that to the map canvas  and while still using the
> shapes from the edit menu basically used the mouse location to handle
> dynamically updating the cursor the a QLabel calculating the area bases on
> the shape being drawn.  It added more code, but out trainers are excited
> about this new feature..
>
>
>
>
>
>
>
> *From:* Yoann Quenach de Quivillic <yoann.quenach at gmail.com>
> *Sent:* Sunday, April 30, 2023 5:48 PM
> *To:* Catania, Luke A ERDC-RDE-GRL-VA CIV <Luke.A.Catania at erdc.dren.mil>
> *Cc:* qgis-developer at lists.osgeo.org
> *Subject:* Re: [QGIS-Developer] Digitizing with Edit Menu
>
>
>
> Have you considered listening to the featureAdded signal instead?
>
> The digitizing shape (aka rubberband) you see while digitizing is not
> really accessible. In fact, it isn't guaranteed to be the geometry of the
> feature being created. It could even not exist at all ; this is all
> dependent on the current QgsMapTool used.
>
>
>
> Rather than monitoring clicks, or accessing the rubberband, you could
> listen to the featureAdded signal. This signal is emitted when a new
> feature is added to the layer. You can then perform your check (e;g area
> validation), and delete the feature if the check fails. It won't even
> appear on screen.
>
>
>
> Here is a possible implementation. Note that I split the AreaValidator
> into three classes for genericity, but you could merge these three classes
> in a single one.
>
>
>
> LayerConnector : this is used to automatically connect all map layers to a
> function
>
> FeatureValidator: Specialization, connects all QgsVectorLayer featureAdded
> signal to a function that takes the layer and the feature being added as
> parameters
>
> AreaValidator: Contains the actual area computation, and possible deletion
> of the feature
>
>
>
>
>
> class LayerConnector(QObject):
>
>     """Generic class to connect to all QgsMapLayer"""
>
>
>
>     def __init__(self):
>
>         super().__init__()
>
>         QgsProject.instance().layerWasAdded.connect(self.connect_layer)
>
>         self.connect_layers()
>
>
>
>     def __del__(self):
>
>         QgsProject.instance().layerWasAdded.disconnect(self.connect_layer)
>
>         self.disconnect_layers()
>
>
>
>     def connect_layers(self):
>
>         print("Connecting")
>
>         for layer in QgsProject.instance().mapLayers().values():
>
>             self.connect_layer(layer)
>
>
>
>     def disconnect_layers(self):
>
>         print("DisConnecting")
>
>         for layer in QgsProject.instance().mapLayers().values():
>
>             self.disconnect_layer(layer)
>
>
>
>     def connect_layer(self, layer):
>
>         pass
>
>
>
>     def disconnect_layer(self, layer):
>
>         pass
>
>
>
> class FeatureValidator(LayerConnector):
>
>     """Connect all QgsVectorLayer to a process_feature method when a
> feature is added"""
>
>
>
>     def connect_layer(self, layer):
>
>         if not isinstance(layer, QgsVectorLayer):
>
>             return
>
>         layer.featureAdded.connect(self.on_feature_added)
>
>
>
>     def disconnect_layer(self, layer):
>
>         if not isinstance(layer, QgsVectorLayer):
>
>             return
>
>         layer.featureAdded.disconnect(self.on_feature_added)
>
>
>
>     def on_feature_added(self, id):
>
>         layer = self.sender()
>
>         feat = layer.getFeature(id)
>
>         self.process_feature(layer, feat)
>
>
>
>     def process_feature(self, layer, feature):
>
>         print(f"Feature {feature.id()} added to layer {layer.name()}")
>
>
>
> class AreaValidator(FeatureValidator):
>
>     def __init__(self, max_area):
>
>         super().__init__()
>
>         self.max_area = max_area
>
>
>
>     def process_feature(self, layer, feature):
>
>         geom = feature.geometry()
>
>         if not geom:
>
>             return
>
>
>
>         # Here you should handle CRS transformation
>
>         # before computing the feature area
>
>         area = geom.area()
>
>
>
>         if area > self.max_area:
>
>             iface.messageBar().pushWarning("Cannot add feature", f"Area
> too big : {round(area, 2)}")
>
>             layer.deleteFeature(feature.id())
>
>
>
> validator = AreaValidator(500)
>
>
>
> Le dim. 30 avr. 2023 à 18:42, Catania, Luke A ERDC-RDE-GRL-VA CIV via
> QGIS-Developer <qgis-developer at lists.osgeo.org> a écrit :
>
> When you digitize a shape using the Edit menu in QGIS is the shape
> accessible?  I am looking to get he area of the shape as it is drawn.  I
> have added an event filter to my code to capture the coordinates and
> calculate it by creating a QgsGeometry, but my code is getting complicated
> as there are many shapes that a user can draw from this menu so if I can
> get access to this shape if it is temporary in memory, then I can just
> calculate the area on the shape and not have to capture all the positions
> of the mouse when clicked and moved.
>
>
>
> _______________________________________________
> QGIS-Developer mailing list
> QGIS-Developer at lists.osgeo.org
> List info:
> Blockedhttps://lists.osgeo.org/mailman/listinfo/qgis-developerBlocked
> Unsubscribe:
> Blockedhttps://lists.osgeo.org/mailman/listinfo/qgis-developerBlocked
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.osgeo.org/pipermail/qgis-developer/attachments/20230501/7cc052ed/attachment-0001.htm>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: image001.png
Type: image/png
Size: 82922 bytes
Desc: not available
URL: <http://lists.osgeo.org/pipermail/qgis-developer/attachments/20230501/7cc052ed/attachment-0003.png>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: image002.png
Type: image/png
Size: 728686 bytes
Desc: not available
URL: <http://lists.osgeo.org/pipermail/qgis-developer/attachments/20230501/7cc052ed/attachment-0004.png>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: image003.png
Type: image/png
Size: 855843 bytes
Desc: not available
URL: <http://lists.osgeo.org/pipermail/qgis-developer/attachments/20230501/7cc052ed/attachment-0005.png>


More information about the QGIS-Developer mailing list