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

Val P
  • 3,858
  • 1
  • 8
  • 33
MartinMap
  • 8,262
  • 7
  • 50
  • 114
  • 6
  • 1
    See how to submit a feature request at https://gis.stackexchange.com/questions/208141/submitting-feature-request-for-qgis and, if you can't contribute as a programmer, I suggest some kind of crowdfunding for it. – Peter Krauss Oct 23 '22 at 08:52
  • Look this video https://youtu.be/v8WYtAEIDSM. Here explain sides of polygon, but you also can generate a geometry and calculate length and more things... – RBenet Oct 25 '22 at 13:09
  • This video is more complet: https://www.youtube.com/watch?v=57nOU660oHk – RBenet Oct 25 '22 at 13:19
  • @RBenet, that's a nice technique for symbolising your layer, but it does not address the core question here, to display the area and perimeter whilst the feature is being edited. I suspect it's reasonably easy to implement, for someone experienced in C++, by extending the existing Advanced Digitizing dialog (shown in the question). – Matt Oct 25 '22 at 14:40
  • 1
    this plugin should do for you, but I see that there is an open and unsolved problem https://github.com/lmotta/calcarea2 – pigreco Oct 25 '22 at 16:38
  • I placed a feature request: https://github.com/qgis/QGIS/issues/50789 – MartinMap Nov 04 '22 at 06:53

1 Answers1

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.

Mayo
  • 3,902
  • 3
  • 22