First we can create a point layer in memory using something like:
result = QgsVectorLayer("Point?crs=epsg:4326", "result", "memory")
pr = result.dataProvider()
fet = QgsFeature()
Then inside your for
loop, we can add points to the memory layer using the coordinates of the snapped geometry:
fet.setGeometry(QgsGeometry.fromPoint(p2))
pr.addFeatures([fet])
Then finally add the memory layer into the canvas:
QgsMapLayerRegistry.instance().addMapLayer(result)
So the full code could look something like this:
import math
from qgis.gui import *
from PyQt4.QtCore import Qt
lineLayer = iface.mapCanvas().layer(0)
pointLayer = iface.mapCanvas().layer(1)
canvas = iface.mapCanvas()
spIndex = QgsSpatialIndex() #create spatial index object
lineIter = lineLayer.getFeatures()
for lineFeature in lineIter:
spIndex.insertFeature(lineFeature)
result = QgsVectorLayer("Point?crs=epsg:4326", "result", "memory")
pr = result.dataProvider()
fet = QgsFeature()
pointIter = pointLayer.getFeatures()
for feature in pointIter:
ptGeom = feature.geometry()
pt = feature.geometry().asPoint()
nearestIds = spIndex.nearestNeighbor(pt,1) # we need only one neighbour
featureId = nearestIds[0]
nearestIterator = lineLayer.getFeatures(QgsFeatureRequest().setFilterFid(featureId))
nearFeature = QgsFeature()
nearestIterator.nextFeature(nearFeature)
closeSegResult = nearFeature.geometry().closestSegmentWithContext(ptGeom.asPoint())
closePoint = closeSegResult[1]
snapGeometry = QgsGeometry.fromPoint(QgsPoint(closePoint[0],closePoint[1]))
p1 = ptGeom.asPoint()
p2 = snapGeometry.asPoint()
dist = math.hypot(p2.x() - p1.x(), p2.y() - p1.y())
print dist
r = QgsRubberBand(canvas,QGis.Point)
r.setColor(Qt.red)
r.setToGeometry(snapGeometry,pointLayer)
fet.setGeometry(QgsGeometry.fromPoint(p2))
pr.addFeatures([fet])
QgsMapLayerRegistry.instance().addMapLayer(result)
Example:
Sample points and lines before we run the code:
After we run the code, the red points are rubberband snapped points on canvas, the blue points are those saved in the memory layer:
EDIT:
If you want to add your original points also to the memory layer, we can add the following lines after we have created the layer:
# Create new memory layer
mlayer = QgsVectorLayer("Point?crs=epsg:4326", "result", "memory")
mlayer_data = mlayer.dataProvider()
feature = QgsFeature()
# Get original features from point layer and add to memory layer
feats = [feat for feat in pointLayer.getFeatures()]
attr = pointLayer.dataProvider().fields().toList()
mlayer_data.addAttributes(attr)
mlayer.updateFields()
mlayer_data.addFeatures(feats)
So now your full code might look something like the following (note: I changed some naming terms):
import math
from qgis.gui import *
from PyQt4.QtCore import Qt
lineLayer = iface.mapCanvas().layer(0)
pointLayer = iface.mapCanvas().layer(1)
canvas = iface.mapCanvas()
spIndex = QgsSpatialIndex() #create spatial index object
lineIter = lineLayer.getFeatures()
for lineFeature in lineIter:
spIndex.insertFeature(lineFeature)
# Create new memory layer
mlayer = QgsVectorLayer("Point?crs=epsg:4326", "result", "memory")
mlayer_data = mlayer.dataProvider()
feature = QgsFeature()
# Get original features from point layer and add to memory layer
feats = [feat for feat in pointLayer.getFeatures()]
attr = pointLayer.dataProvider().fields().toList()
mlayer_data.addAttributes(attr)
mlayer.updateFields()
mlayer_data.addFeatures(feats)
pointIter = pointLayer.getFeatures()
for feature in pointIter:
ptGeom = feature.geometry()
pt = feature.geometry().asPoint()
nearestIds = spIndex.nearestNeighbor(pt,1) # we need only one neighbour
featureId = nearestIds[0]
nearestIterator = lineLayer.getFeatures(QgsFeatureRequest().setFilterFid(featureId))
nearFeature = QgsFeature()
nearestIterator.nextFeature(nearFeature)
closeSegResult = nearFeature.geometry().closestSegmentWithContext(ptGeom.asPoint())
closePoint = closeSegResult[1]
snapGeometry = QgsGeometry.fromPoint(QgsPoint(closePoint[0],closePoint[1]))
p1 = ptGeom.asPoint()
p2 = snapGeometry.asPoint()
dist = math.hypot(p2.x() - p1.x(), p2.y() - p1.y())
print dist
r = QgsRubberBand(canvas,QGis.Point)
r.setColor(Qt.red)
r.setToGeometry(snapGeometry,pointLayer)
feature.setGeometry(QgsGeometry.fromPoint(p2))
# Add rubberband snapped features to memory layer
mlayer_data.addFeatures([feature])
QgsMapLayerRegistry.instance().addMapLayer(mlayer)