17

Is it possible in QGIS to see the area / perimeter of a shape or the length of a line while digitizing (not just after finishing it)?

I know, I can use the Advanced Digitizing Panel to get the coordinates, angles and length but not the area / perimeter. Labelling the unfinished object with $area shows the area just after the polygon is finished. enter image description here

7

1 Answer 1

1

This could be done with python, but because there are various digitizing tools you will need to write code for each different tool. Here is an example of how to get the area of a polygon that is being created. Paste this code as new script in the QGIS python console and click the run button.

canvas = iface.mapCanvas()

class EventFilter(QObject):
    def __init__(self, canvas):
        super().__init__(canvas.viewport())
        self.canvas = canvas
        self.parent = canvas.viewport()
        self.label = QLabel()
        
    def start(self):
        self.parent.installEventFilter(self)
        iface.cadDockWidget().findChildren(QLayout)[0].addWidget(self.label)
        self.label.show()
        
    def stop(self):
        self.parent.removeEventFilter(eventFilter)
        self.label.close()
        
    def eventFilter(self, obj, event):
        mapTool = self.canvas.mapTool()
        if event.type() == QMouseEvent.MouseMove and isinstance(mapTool, QgsMapToolDigitizeFeature) and mapTool.toolName() == 'Add feature':
            coordinates = QgsMapMouseEvent(self.canvas, event).snapPoint()
            layer = mapTool.layer()
            geometryType = layer.geometryType()
            
            if geometryType == QgsWkbTypes.PolygonGeometry:
                if len(mapTool.points()) >= 2:
                    geometry = QgsGeometry.fromPolygonXY([mapTool.points() + [coordinates]])
                    crsUnits = QgsDistanceArea()
                    crsUnits.setSourceCrs(layer.crs(), QgsProject.instance().transformContext())
                    area = QgsUnitTypes.formatArea(geometry.area(), 5, crsUnits.areaUnits(), keepBaseUnit=True)
                    self.label.setText(f'Area: {area}')
                else:
                    self.label.setText('Area: 0')
        return super().eventFilter(obj, event)

eventFilter = EventFilter(canvas)

Then, type this line manually to activate the area calculation eventFilter.start(), if you want to disable it run eventFilter.stop()

I think this code will have some bugs, I'm don't know so much about Qt, so the way I display the area is by placing a label in the lower part of the Advanced Digitizing Panel. Another thing to take in account, some how QGIS doesn't let you use the QgsMapTool canvas events in the default tools (Selct, Add Feature, Identify...), so what I did to update the label every time the mouse changes it position, was to install an event filter on the canvas viewport.

Note: This code is a very simplistic approach, so you will need to customize it for your needs.
For more complex geometry calculations threading will be a good idea.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.