PyQGIS – Getting M-Value from Shapefile by Mouse Click on Canvas in PyQGIS

pyqgispyqtpythonqgis-3qgis-plugins

I am new to QGIS plugin scripting (3.16 Hannover) (in Python 3.7).

I have lots of different layers in my layers panel and I want to be able to click on a button on my GUI, which then activates a function, so I can click on any vector on my map canvas, and then receive the M-value of the chosen feature in the vector layer. I want to store this M-value in a variable, so I can use it later.

First off I tried reading the documentation on https://qgis.org/pyqgis/3.2/gui/Map/QgsMapToolIdentify.html#qgis.gui.QgsMapToolIdentify.identifyVectorLayer
But I'm also new to programming in Python, so it's a bit difficult for me to understand.

I got the following code :

def canvas_clicked(self):
    self.canvas = self.iface.mapCanvas() # make mapcanvas variable
    self.pointTool = QgsMapToolEmitPoint(self.canvas) # using QgsMapToolEmitPoint to emit point, so i can retrieve x, y of mouse click
    self.pointTool.canvasClicked.connect(self.store_m_value) # connect function to mouseclick on canvas (in this function I want the program to store m-value of clicked vector in a variable)
    self.canvas.setMapTool(self.pointTool) # Set the map tool, so i can click the canvas

Then I connect my button (I use Qt designer – where i named my button btn_canvas_clicked) to the canvas_clicked function.

def run(self)
    self.dialog.btn_canvas_clicked.connect(self.canvas_clicked)

I tried the following to store the m-value unsuccesfully

def store_m_value(self, point, event)
   self.identify_vector = QgsMapToolIdentify(self.canvas)
   self.result = self.identify_vector.identify(point.x(), point.y(), [], QgsMapToolIdentify.DefaultQgsSetting)
   m_value = self.result.geometry().constGet().mAt(0)

I tried using following answer as a guideline for retrieving M value from vector layer:
enter link description here

Best Answer

There are two main issues with your code. First one is that QgsMapToolIdentify.identify() will return a list of identified features. So you will need index your result variable before accessing any geometries. For example:

self.result = self.identify_vector.identify(point.x(), point.y(), [], QgsMapToolIdentify.DefaultQgsSetting)
if self.result:
    m_value = self.result[0].geometry().constGet().mAt(0)

And second is that the mAt() function is only available on LineString geometries. So if you might have some point or polygon geometries that won't work either. With polygons I guess you would need to access the exterior LineString to get it's m values with something like geometry.exteriorRing().curveToLine().mAt(0) and for point geometries use the m() property.

In general you might not even need the additional step of using a QgsMapToolEmitPoint to retrieve the coordinates. Since you need to use QgsMapToolIdentify anyways you could use it's canvasReleaseEvent function which provides coordinates through the QgsMapMouseEvent parameter:

def store_m_value(event):
    result = identify_vector.identify(event.x(), event.y(), [], QgsMapToolIdentify.DefaultQgsSetting)
    if result:
        m_value = result[0].geometry().constGet().mAt(0) # only for LineString as explained above

identify_vector = QgsMapToolIdentify(iface.mapCanvas())
identify_vector.canvasReleaseEvent = store_m_value
iface.mapCanvas().setMapTool(identify_vector)