Skip to main content
additional issue with aggregate process
Source Link
GeorgeC
  • 8.3k
  • 7
  • 56
  • 143

UPDATE 2 For some reason it's only updating roads that have one section and not multiple and also where there more than one point within the buffer it's not putting in any value. I have cleaned up the code to try and see why it's not functioning as expected...

def Check_Intersection (c_sel, l, start_end): #Find points within start/end of line
    geom = l.geometry().asPolyline()
    g = QgsGeometry.fromPointXY(geom[start_end])
    buffer = g.buffer(10,4) #10m buffer with 4 segments
    #buffer_to_iface(buffer) #add buffer to map for testing
    for c in c_sel: # for each chainage point -ideally should be envelope in buffer area only
        #print (c['RoadMntnc'],c['distance']) #show value for testing
        if c.geometry().within(buffer):
            print(l.id(),c['RoadMntnc'],int(c['distance']))
            #Update record
#                layer.startEditing()
#                ntext=int(c['distance'])
#                fieldName='Start_Chainage2'
#                FieldIndex = l.fields().indexFromName(fieldName)
#                layer.changeAttributeValue(l.id(), FieldIndex, ntext)
#                layer.commitChanges()
            break
def  buffer_to_iface(buffer):       #buffer to iface for testing
    buff_layer = QgsVectorLayer('Polygon', 'buffer' , 'memory')
    prov = buff_layer.dataProvider()
    feat = QgsFeature()
    feat.setGeometry(buffer)
    prov.addFeatures([feat])
    buff_layer.updateExtents()
    QgsProject.instance().addMapLayers([buff_layer])[0]
    
roadlist=[]
layer = QgsProject.instance().mapLayersByName('DSC_Roads')[0]
chainage_layer= QgsProject.instance().mapLayersByName('DSC_Roads_10m_Chainage')[0]


for feature in layer.getFeatures(): # Create list of unique roads to work through
    if feature['RoadMntnc'] not in roadlist:
        roadlist.append(feature['RoadMntnc'])
#
#roadlist=['Kingston_Rd'] #for testing
#-----------------------------------------------------------------------

for road in roadlist: # for each road select line and point features
    request = QgsFeatureRequest(QgsExpression('"RoadMntnc"= \'{0}\''.format(road)))
    l_sel = layer.getFeatures(request)
    c_sel = chainage_layer.getFeatures(request)

    for l in l_sel: # repeat for each road segment
        print (str(l.id())+l['RoadMntnc'])
        start_end=0 #get start points
        Check_Intersection (c_sel,l,start_end)
    
print ('Completed')

layer.updateFields()

UPDATE 2 For some reason it's only updating roads that have one section and not multiple and also where there more than one point within the buffer it's not putting in any value. I have cleaned up the code to try and see why it's not functioning as expected...

def Check_Intersection (c_sel, l, start_end): #Find points within start/end of line
    geom = l.geometry().asPolyline()
    g = QgsGeometry.fromPointXY(geom[start_end])
    buffer = g.buffer(10,4) #10m buffer with 4 segments
    #buffer_to_iface(buffer) #add buffer to map for testing
    for c in c_sel: # for each chainage point -ideally should be envelope in buffer area only
        #print (c['RoadMntnc'],c['distance']) #show value for testing
        if c.geometry().within(buffer):
            print(l.id(),c['RoadMntnc'],int(c['distance']))
            #Update record
#                layer.startEditing()
#                ntext=int(c['distance'])
#                fieldName='Start_Chainage2'
#                FieldIndex = l.fields().indexFromName(fieldName)
#                layer.changeAttributeValue(l.id(), FieldIndex, ntext)
#                layer.commitChanges()
            break
def  buffer_to_iface(buffer):       #buffer to iface for testing
    buff_layer = QgsVectorLayer('Polygon', 'buffer' , 'memory')
    prov = buff_layer.dataProvider()
    feat = QgsFeature()
    feat.setGeometry(buffer)
    prov.addFeatures([feat])
    buff_layer.updateExtents()
    QgsProject.instance().addMapLayers([buff_layer])[0]
    
roadlist=[]
layer = QgsProject.instance().mapLayersByName('DSC_Roads')[0]
chainage_layer= QgsProject.instance().mapLayersByName('DSC_Roads_10m_Chainage')[0]


for feature in layer.getFeatures(): # Create list of unique roads to work through
    if feature['RoadMntnc'] not in roadlist:
        roadlist.append(feature['RoadMntnc'])
#
#roadlist=['Kingston_Rd'] #for testing
#-----------------------------------------------------------------------

for road in roadlist: # for each road select line and point features
    request = QgsFeatureRequest(QgsExpression('"RoadMntnc"= \'{0}\''.format(road)))
    l_sel = layer.getFeatures(request)
    c_sel = chainage_layer.getFeatures(request)

    for l in l_sel: # repeat for each road segment
        print (str(l.id())+l['RoadMntnc'])
        start_end=0 #get start points
        Check_Intersection (c_sel,l,start_end)
    
print ('Completed')

layer.updateFields()
Notice removed Authoritative reference needed by GeorgeC
Bounty Ended with César Arquero Cabral's answer chosen by GeorgeC
trying to use buffer of point
Source Link
GeorgeC
  • 8.3k
  • 7
  • 56
  • 143

UPDATE: Using César Arquero answer

The buffer to check needs to be around the start point of each road segment. All I need is the chainage feature that intersects this buffer - it should just be one point, but if more than one I need the lowest value.

from operator import itemgetter

def Update_Field(fieldName, ntext): # Function to simplify updating fields
    print (ntext)
    fieldIndex = layer.fields().indexFromName(fieldName)
    dpr.changeAttributeValues({feature.id(): {fieldIndex: ntext}})
    layer.commitChanges()

roadlist=[]
layer = QgsProject.instance().mapLayersByName('DSC_Roads')[0]
chainage_layer= QgsProject.instance().mapLayersByName('DSC_Roads_10m_Chainage')[0]

for feature in layer.getFeatures(): # Create list of unique roads to work through
    if feature['RoadMntnc'] not in roadlist:
        roadlist.append(feature['RoadMntnc'])
#
roadlist=['Dean_Rd'] #for testing
#-----------------------------------------------------------------------
#OPTION 1
for road in roadlist: # for each road get key attributes and sort
    i=1
    road_parts=[]
    request = QgsFeatureRequest(QgsExpression('"RoadMntnc"= \'{0}\''.format(road)))
    l_selection = layer.getFeatures(request)
    chainage_selection = chainage_layer.getFeatures(request)

    for l in l_selection:
        geom = l.geometry().asPolyline()
        print ("Start: " + str(geom[0]))
        print ("End: " + str(geom[-1]))
        for c in chainage_selection:
            buffer = geom[0].buffer(5,5) #5m buffer with 5 segments
            if c.geometry().intersects(buffer):
                print(l.id(),c['RoadMntnc'],c['distance'])
#if the above works then update record
#                ntext=str(l['distance'])
#                print(ntext)
#                fieldName='Start_Chainage'
#                Update_Field(fieldName,ntext)

UPDATE: Using César Arquero answer

The buffer to check needs to be around the start point of each road segment. All I need is the chainage feature that intersects this buffer - it should just be one point, but if more than one I need the lowest value.

from operator import itemgetter

def Update_Field(fieldName, ntext): # Function to simplify updating fields
    print (ntext)
    fieldIndex = layer.fields().indexFromName(fieldName)
    dpr.changeAttributeValues({feature.id(): {fieldIndex: ntext}})
    layer.commitChanges()

roadlist=[]
layer = QgsProject.instance().mapLayersByName('DSC_Roads')[0]
chainage_layer= QgsProject.instance().mapLayersByName('DSC_Roads_10m_Chainage')[0]

for feature in layer.getFeatures(): # Create list of unique roads to work through
    if feature['RoadMntnc'] not in roadlist:
        roadlist.append(feature['RoadMntnc'])
#
roadlist=['Dean_Rd'] #for testing
#-----------------------------------------------------------------------
#OPTION 1
for road in roadlist: # for each road get key attributes and sort
    i=1
    road_parts=[]
    request = QgsFeatureRequest(QgsExpression('"RoadMntnc"= \'{0}\''.format(road)))
    l_selection = layer.getFeatures(request)
    chainage_selection = chainage_layer.getFeatures(request)

    for l in l_selection:
        geom = l.geometry().asPolyline()
        print ("Start: " + str(geom[0]))
        print ("End: " + str(geom[-1]))
        for c in chainage_selection:
            buffer = geom[0].buffer(5,5) #5m buffer with 5 segments
            if c.geometry().intersects(buffer):
                print(l.id(),c['RoadMntnc'],c['distance'])
#if the above works then update record
#                ntext=str(l['distance'])
#                print(ntext)
#                fieldName='Start_Chainage'
#                Update_Field(fieldName,ntext)
Tweeted twitter.com/StackGIS/status/1172389501026439168
updated code to resolve some issues
Source Link
GeorgeC
  • 8.3k
  • 7
  • 56
  • 143
from operator import itemgetter

def Update_Field(fieldName, ntext): # Function to simplify updating fields
    print (ntext)
    fieldIndex = layer.fields().indexFromName(fieldName)
    dpr.changeAttributeValues({feature.id(): {fieldIndex: ntext}})
    layer.commitChanges()

roadlist=[]
layer = iface.activeLayer()
dpr = layer.dataProvider()

chainage_layer=QgsVectorLayer(r'Z:\My Drive\Mangoesmapping\Spatial Projects\2019\DSC\126_Road_Updates\Working\Output\DSC_Roads_10m_Chainage.tab', "Chainage", "ogr")
for#for feature in layer.getFeatures(): # Create list of unique roads to work through
    if#if feature['RoadMntnc'] not in roadlist:
    #    roadlist.append(feature['RoadMntnc'])
roadlist=['Kingston_Rd'] #Manual road list roadlist=['Kingston_Rd']for testing
for road in roadlist: # for each road get key attributes and sort
    print (road)
    layer.selectByExpression('"RoadMntnc"= \'{0}\''.format(road), QgsVectorLayer.SetSelection)
    selection=layer.selectedFeatures()
    l_selection=layer.selectedFeatures()
    i=1
    road_parts=[]
    chainage_layer.selectByExpression('"RoadMntnc"= \'{0}\''.format(road), QgsVectorLayer.SetSelection)
    chainage_selection=chainage_layer.selectedFeatures()
    for f in selection:
        for l in chainage_selection:
            if f.geometry().intersects(l.geometry()): #how do I check if a 1m buffer of the start point has a chainge point within it?
                print (l.id(),l['RoadMntnc'], l['distance'])
#if the above works then update record
                #ntext=str(item['Distance'])
                #print (ntext)
                #fieldName='Start_Chainage'
                #Update_Field(fieldName,ntext)
    

All values are printed in the last line - how to I change the if statement to just show the distance value from the chainage value within 1m of the start of the line?

How do I write the expression to utilize the two selections and/oror modify the aggregate function to use the two selections or use an envelope to collect the required value?

from operator import itemgetter

def Update_Field(fieldName, ntext): # Function to simplify updating fields
    print (ntext)
    fieldIndex = layer.fields().indexFromName(fieldName)
    dpr.changeAttributeValues({feature.id(): {fieldIndex: ntext}})
    layer.commitChanges()

roadlist=[]
layer = iface.activeLayer()
dpr = layer.dataProvider()

chainage_layer=QgsVectorLayer(r'Z:\My Drive\Mangoesmapping\Spatial Projects\2019\DSC\126_Road_Updates\Working\Output\DSC_Roads_10m_Chainage.tab', "Chainage", "ogr")
for feature in layer.getFeatures(): # Create list of unique roads to work through
    if feature['RoadMntnc'] not in roadlist:
        roadlist.append(feature['RoadMntnc'])
    roadlist=['Kingston_Rd']
for road in roadlist: # for each road get key attributes and sort
    print (road)
    layer.selectByExpression('"RoadMntnc"= \'{0}\''.format(road), QgsVectorLayer.SetSelection)
    selection=layer.selectedFeatures()
    l_selection=layer.selectedFeatures()
    i=1
    road_parts=[]
    chainage_layer.selectByExpression('"RoadMntnc"= \'{0}\''.format(road), QgsVectorLayer.SetSelection)
    chainage_selection=chainage_layer.selectedFeatures()
    for f in selection:
        for l in chainage_selection:
            if f.geometry().intersects(l.geometry()): #how do I check if a 1m buffer of the start point has a chainge point within it?
                print (l.id(),l['RoadMntnc'], l['distance'])
    

All values are printed in the last line - how to I change the if statement?

How do I write the expression to utilize the two selections and/or modify the aggregate function to use the two selections?

from operator import itemgetter

def Update_Field(fieldName, ntext): # Function to simplify updating fields
    print (ntext)
    fieldIndex = layer.fields().indexFromName(fieldName)
    dpr.changeAttributeValues({feature.id(): {fieldIndex: ntext}})
    layer.commitChanges()

roadlist=[]
layer = iface.activeLayer()
dpr = layer.dataProvider()

chainage_layer=QgsVectorLayer(r'Z:\My Drive\Mangoesmapping\Spatial Projects\2019\DSC\126_Road_Updates\Working\Output\DSC_Roads_10m_Chainage.tab', "Chainage", "ogr")
#for feature in layer.getFeatures(): # Create list of unique roads to work through
    #if feature['RoadMntnc'] not in roadlist:
    #    roadlist.append(feature['RoadMntnc'])
roadlist=['Kingston_Rd'] #Manual road list for testing
for road in roadlist: # for each road get key attributes and sort
    print (road)
    layer.selectByExpression('"RoadMntnc"= \'{0}\''.format(road), QgsVectorLayer.SetSelection)
    selection=layer.selectedFeatures()
    l_selection=layer.selectedFeatures()
    i=1
    road_parts=[]
    chainage_layer.selectByExpression('"RoadMntnc"= \'{0}\''.format(road), QgsVectorLayer.SetSelection)
    chainage_selection=chainage_layer.selectedFeatures()
    for f in selection:
        for l in chainage_selection:
            if f.geometry().intersects(l.geometry()): #how do I check if a 1m buffer of the start point has a chainge point within it?
                print (l.id(),l['RoadMntnc'], l['distance'])
#if the above works then update record
                #ntext=str(item['Distance'])
                #print (ntext)
                #fieldName='Start_Chainage'
                #Update_Field(fieldName,ntext)
    

All values are printed in the last line - how to I change the if statement to just show the distance value from the chainage value within 1m of the start of the line?

How do I write the expression to utilize the two selections or modify the aggregate function to use the two selections or use an envelope to collect the required value?

Notice added Authoritative reference needed by GeorgeC
Bounty Started worth 50 reputation by GeorgeC
updated code to resolve some issues
Source Link
GeorgeC
  • 8.3k
  • 7
  • 56
  • 143
Loading
Source Link
GeorgeC
  • 8.3k
  • 7
  • 56
  • 143
Loading