Here is aare two Python solution:
Rubber Band approach:
searches for the nearest point on the road
creates a rubber band
labels the rubber band
from qgis.gui import * from qgis.utils import * from qgis.core import * from PyQt4 import QtGui, uic from PyQt4.QtGui import * from PyQt4.QtCore import * p_lyr = QgsMapLayerRegistry.instance().mapLayersByName('points')[0] l_lyr = QgsMapLayerRegistry.instance().mapLayersByName('roads')[0] lines = [feature for feature in l_lyr.getFeatures()] def removeCanvasItems(): canvas_items = [ i for i in iface.mapCanvas().scene().items() if issubclass(type(i), QgsRubberBand) or issubclass(type(i), QgsTextAnnotationItem) or issubclass(type(i), QgsVertexMarker)] if canvas_items: for item in canvas_items: if item in iface.mapCanvas().scene().items(): iface.mapCanvas().scene().removeItem(item) def nearest_road(): #removeCanvasItems() #removes the old rubberbands, calling this causes a mini dump for point in p_lyr.getFeatures(): minDistPoint = min([l.geometry().closestSegmentWithContext(QgsPoint(point.geometry().asPoint())) for l in lines])[1] points = [QgsPoint(point.geometry().asPoint()), QgsPoint(minDistPoint[0], minDistPoint[1])] r_polyline = QgsRubberBand(iface.mapCanvas(), False) r_polyline.setToGeometry(QgsGeometry.fromPolyline(points), None) r_polyline.setWidth(2) r_polyline.setColor(QColor(0,255,0,255)) seg = QgsFeature() seg.setGeometry(QgsGeometry.fromPolyline(points)) geom = seg.geometry() length = seg.geometry().length() symbol = QgsMarkerSymbolV2() symbol.setSize(0) lbltext = QTextDocument(str(round(length,2)) + 'm') label = QgsTextAnnotationItem(iface.mapCanvas()) label.setMapPosition(seg.geometry().interpolate(length/2.0).asPoint()) label.setDocument(lbltext) label.setFrameSize(QSizeF(lbltext.size().width(),lbltext.size().height())) label.setFrameBorderWidth(0) label.setFrameColor(QColor("#ff4b00")) label.setFrameBackgroundColor(QColor("#ff4b00")) label.setMarkerSymbol(symbol) nearest_road() #calling the function the first time p_lyr.geometryChanged.connect(nearest_road) # creates new rubberband when point is moved p_lyr.featureAdded.connect(nearest_road) # creates new rubberband when a new point is created
Vector Layer approach:
Instead of rubber bands you could use a temporary layer, which stores the label lines and refrehs on the signaldistance. In my case I will addhave a shapefile with two attributes: id (int), and distance(double). With this layer you can better label and style your features.
The function removeFeatures()
, removes all features from the distance layer. Better way is to my postget the ID of the feature that is moved and deletes only this line from the provider. I think I will update this soon.
from qgis.gui import *
from qgis.utils import *
from qgis.core import *
from PyQt4.QtGui import *
from PyQt4.QtCore import *
p_lyr = QgsMapLayerRegistry.instance().mapLayersByName('points')[0]
l_lyr = QgsMapLayerRegistry.instance().mapLayersByName('roads')[0]
lines = [feature for feature in l_lyr.getFeatures()]
d_lyr = QgsMapLayerRegistry.instance().mapLayersByName('distance')[0]
prov = d_lyr.dataProvider()
def removeFeatures():
with edit(d_lyr):
listOfIds = [feat.id() for feat in d_lyr.getFeatures()]
d_lyr.deleteFeatures( listOfIds )
def nearest_road():
removeFeatures()
for point in p_lyr.getFeatures():
minDistPoint = min([l.geometry().closestSegmentWithContext(QgsPoint(point.geometry().asPoint())) for l in lines])[1]
points = [QgsPoint(point.geometry().asPoint()), QgsPoint(minDistPoint[0], minDistPoint[1])]
seg = QgsFeature()
seg.setGeometry(QgsGeometry.fromPolyline(points))
geom = seg.geometry()
length = seg.geometry().length()
seg.setAttributes([1,seg.geometry().length()])
prov.addFeatures([seg])
d_lyr.updateExtents()
d_lyr.triggerRepaint()
d_lyr.updateFields()
nearest_road()
p_lyr.geometryChanged.connect(nearest_road)
p_lyr.featureAdded.connect(nearest_road)