5

I ran a program that created points on the nearest edge of a polygon, but it only appears in the iface.mapLayer() canvas.

The code is taken from the answer in: https://gis.stackexchange.com/a/94428

enter image description here

You can see that no layer is selected but the points are still showing.

How do I get the points onto a vector layer or a shapefile?

EDIT: This is the modified code

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) 

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)
  • Taken exactly from the other post or modified? Can you show your code exactly as it is run? – Michael Stimson Feb 6 '17 at 23:13
  • @MichaelMiles-Stimson Just made an update. Pretty much the same. – Tali Feb 6 '17 at 23:21
  • Assuming your layer 1 is an editable point layer you should only need to reset the geometry like feature.setGeometry(p2) and update the feature. I can't recall exactly how to update a feature but perhaps this page might help docs.qgis.org/testing/en/docs/pyqgis_developer_cookbook/… – Michael Stimson Feb 7 '17 at 0:09
  • Are you wanting to know how to convert the memory layer to a shapefile so it is saved to disk? – artwork21 Feb 7 '17 at 13:24
6

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:

Before running 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:

After running code


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)
  • I have a question though. Will all the features from the original points be stored in the new layer? And how could this be added? – Tali Feb 7 '17 at 22:42
  • 1
    @NathalieVonHuth - Most welcome, glad it worked! I've edited the post to include how to add the original features of your point layer before adding the rubberband snapped features :) – Joseph Feb 8 '17 at 10:17

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.