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: