4

How do I get X,Y coordinate with mouse click with enabling snapping so that only line's vertex point coordinates will be selected?

By using following code I can get latitude longitude of clicked position in map canvas of QGIS but cannot enable the snapping option .

from qgis.gui import QgsMapToolEmitPoint
class PrintClickedPoint(QgsMapToolEmitPoint):
    def __init__(self, canvas):
        self.canvas = canvas
        QgsMapToolEmitPoint.__init__(self, self.canvas)

    def canvasPressEvent( self, e ):
        point = self.toMapCoordinates(self.canvas.mouseLastXY())
        point = list(point)
        iface.mapCanvas().snappingUtils().toggleEnabled()
        print(point)

canvas_clicked = PrintClickedPoint( iface.mapCanvas() )
iface.mapCanvas().setMapTool( canvas_clicked )
1
  • You don't have any reference to the current layer. Maybe that is required. – wingnut Apr 9 at 6:15
3

Try the example below. Paste into a new editor in the Python console, select an active layer (must be a vector layer, since there is no safeguard in the script to handle raster layers etc!) and click run to test.

class PrintSnappedPoint(QgsMapToolEmitPoint):

    def __init__(self, canvas, transform=False):
        self.canvas = canvas
        QgsMapToolEmitPoint.__init__(self, self.canvas)
        self.transform = transform
        self.project = QgsProject.instance()
        self.l = iface.activeLayer()
        self.i = QgsSnapIndicator(self.canvas)
        self.u = self.canvas.snappingUtils()
        self.c = self.u.config()
        self.c.setEnabled(True)
        self.c.setMode(QgsSnappingConfig.AdvancedConfiguration)
        self.s = QgsSnappingConfig.IndividualLayerSettings(True, QgsSnappingConfig.VertexFlag, 25.00,
                    QgsTolerance.Pixels)
        self.c.setIndividualLayerSettings(self.l, self.s)
        self.u.setConfig(self.c)
        
        #Define source and destination crs's and instantiate QgsCoordinateTransform class
        self.src_crs = self.project.crs()
        #Best to change epsg code below to a local projected crs (e.g. UTM)
        self.dst_crs = QgsCoordinateReferenceSystem('EPSG:3857')
        self.x_form = QgsCoordinateTransform(self.src_crs, self.dst_crs, self.project)

    def canvasMoveEvent(self, e):
        m = self.u.snapToMap(e.pos())
        self.i.setMatch(m)

    def canvasPressEvent(self, e):
        if self.i.match().type():
            pointxy = self.i.match().point()
        else:
            pointxy = None
        if pointxy:
            if self.transform:
                tr = self.x_form.transform(pointxy)
                point = [tr.x(), tr.y()]
            else:
                point = [pointxy.x(), pointxy.y()]
            print('Point snapped to vertex: {}'.format(point))
            
    def deactivate(self):
        self.s = QgsSnappingConfig.IndividualLayerSettings(False, QgsSnappingConfig.NoSnapFlag, 25.00,
                    QgsTolerance.Pixels)
        self.c.setIndividualLayerSettings(self.l, self.s)
        self.u.setConfig(self.c)


canvas = iface.mapCanvas()
#to transform snapped click-points, pass True as 2nd argument to constructor
T = PrintSnappedPoint(canvas, True)
canvas.setMapTool(T)

Edit based on comments:

I have updated the code above to give an example of using QgsCoordinateTransform class to transform the the snapped click-point from the project crs to another crs of your choosing. In this example my project crs is epsg:4326 so I transform the point from that to epsg:3857. However, I would recommend changing the epsg code of the destination crs to an accurate local projected crs such as a UTM zone appropriate to your area.

To use the transform function, pass True as the 2nd argument to the constructor of the PrintSnappedPoint class constructor. If you don't pass a 2nd argument, the transform parameter will default to False and the snapped points will be printed according to the project crs.

Expected results shown in the gif below:

enter image description here

2
  • Thank You @Ben Code works perfectly.Can you please suggest how to get X,Y coordinate rather than latitude and longitude? – Devenepali Apr 13 at 5:34
  • No problem @Devenepali. If I understand what you are asking here, the answer is that if you simply use a projected crs you will get XY coordinates instead of geographic degrees. You can also use the QgsCoordinateTransform class to do an on-the-fly transformation from the current project crs to any projected crs. I have updated my answer to show an example of how to do this. – Ben W Apr 13 at 10:43

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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