Interesting question. In my opinion, a Python script which implements a custom QgsMapTool class is the way to go here. I don't know another way to interact with the geometry of a QgsRubberBand drawn on the map canvas.
I have developed a script which (I think) should do what you want which you are welcome to use and adapt. It could also be turned into a small plugin.
Please note the following points:
Your question is not entirely explicit about which geometry type your vector layer has, but I am assuming lines. If you have polygons with z values stored in the vertices, the script will need some modification.
The map tool works the same as the native freehand selection tool; click once to start digitizing, click again to finish.
Since you mentioned one new field for x, y & z intercept values, the script is designed to work when the digitized polygon crosses a line feature exactly once. If you do cross a feature more than once, only one of the intersection points will be saved (I think it's the one closest to the start point of the linestring). To help you know which intersection point's XYZ values are saved to the attribute table, each saved point is visualized with a QgsVertexMarker when you finish digitizing the rubber band.
I tested this on a line layer with MultiLineStringZ geometry:

Please see below for a gif showing how the tool works:

The full script is below. To use it, open the Python console using the
button (or Ctrl+Alt+P) and open a new editor with this button:

Paste in the script and click Run:

- Make sure your line layer is selected as the active layer and start digitizing on the canvas with the freehand tool.
#----------------------------------------------------------- # Copyright (C) 2021 Ben Wirf #----------------------------------------------------------- # Licensed under the terms of GNU GPL 2 # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. #--------------------------------------------------------------------- class DrawFreehandPolygon(QgsMapTool): def __init__(self, canvas): self.canvas = canvas QgsMapTool.__init__(self, self.canvas) self.polygon_rb = QgsRubberBand(self.canvas, QgsWkbTypes.PolygonGeometry) self.set_points = [] self.vertex_markers = [] self.drawing_mode = False def canvasPressEvent(self, e): self.set_points.append(e.mapPoint()) if self.drawing_mode == False: self.clear_markers() self.polygon_rb.reset() self.drawing_mode = True elif self.drawing_mode: self.clear_markers() self.polygon_rb.reset() pts_arr = [p for p in self.set_points] self.polygon_rb.setToGeometry(QgsGeometry.fromPolygonXY([pts_arr])) self.polygon_rb.setStrokeColor(QColor(240, 165, 105)) self.polygon_rb.setFillColor(QColor(240, 165, 105, 85)) self.polygon_rb.setWidth(2) self.polygon_rb.show() x_geom = self.transform_polygon(QgsProject.instance().crs(), iface.activeLayer().crs(), QgsGeometry.fromPolygonXY([pts_arr])) self.intersection_points(x_geom) self.drawing_mode = False self.set_points.clear() def canvasMoveEvent(self, e): if self.drawing_mode: self.polygon_rb.reset() self.set_points.append(e.mapPoint()) if len(self.set_points) > 2: pts_arr = [p for p in self.set_points] self.polygon_rb.setToGeometry(QgsGeometry.fromPolygonXY([pts_arr])) self.polygon_rb.setStrokeColor(QColor(240, 165, 105)) self.polygon_rb.setFillColor(QColor(240, 165, 105, 85)) self.polygon_rb.setWidth(2) self.polygon_rb.show() def transform_polygon(self, canvas_crs, layer_crs, g): if canvas_crs != layer_crs: xform = QgsCoordinateTransform(canvas_crs, layer_crs, QgsProject.instance()) g.transform(xform) return g def intersection_points(self, rb_geom): lyr = iface.activeLayer() current_fld_names = [fld.name() for fld in lyr.fields()] flds_to_add = [] if not 'X' in current_fld_names: flds_to_add.append(QgsField('X', QVariant.Double, '', len=25, prec=6)) if not 'Y' in current_fld_names: flds_to_add.append(QgsField('Y', QVariant.Double, '', len=25, prec=6)) if not 'Z' in current_fld_names: flds_to_add.append(QgsField('Z', QVariant.Double, '', len=25, prec=3)) if flds_to_add: lyr.dataProvider().addAttributes(flds_to_add) lyr.updateFields() x_idx = lyr.fields().lookupField('X') y_idx = lyr.fields().lookupField('Y') z_idx = lyr.fields().lookupField('Z') ### Clear existing X,Y,Z attributes for f in lyr.getFeatures(): lyr.dataProvider().changeAttributeValues({f.id(): {x_idx: NULL, y_idx: NULL, z_idx: NULL}}) ### intersections = [] for f in lyr.getFeatures(): if f.geometry().intersects(rb_geom): intersections.append(f.geometry().intersection(rb_geom)) for geom in intersections: feat_to_update = [f for f in lyr.getFeatures() if f.geometry().intersects(geom)][0] vert_pnts = [v for v in geom.vertices() if not QgsGeometry().fromPointXY(QgsPointXY(v)).buffer(0.0000001, 8).within(rb_geom)] if vert_pnts: self.create_vertex_marker(vert_pnts[0]) x_val = vert_pnts[0].x() y_val = vert_pnts[0].y() z_val = vert_pnts[0].z() lyr.dataProvider().changeAttributeValues({feat_to_update.id(): {x_idx: x_val, y_idx: y_val, z_idx: z_val}}) def create_vertex_marker(self, pt): m = QgsVertexMarker(self.canvas) m.setCenter(QgsPointXY(pt)) m.setColor(QColor(0, 0, 255)) m.setIconSize(7) m.setIconType(QgsVertexMarker.ICON_BOX) # or ICON_CROSS, ICON_CIRCLE m.setPenWidth(3) self.vertex_markers.append(m) def clear_markers(self): if self.vertex_markers: for m in self.vertex_markers: self.canvas.scene().removeItem(m) self.vertex_markers.clear() def deactivate(self): self.polygon_rb.reset() self.clear_markers() mt = DrawFreehandPolygon(iface.mapCanvas()) iface.mapCanvas().setMapTool(mt)