# Update geometry of feature with arcpy

I have buildings and road shapefile. I am creating centroids of building and connecting it to nearest road feature as shown in fig 1.

Code to draw a line between building centroid and road:

``````import arcpy
road = r"...\road.shp"
buildings = r"...\building.shp"

arcpy.env.workspace =  arcpy.Describe(buildings).path
centroid = os.path.join(arcpy.env.workspace, "centroid.shp")
connectingLines = os.path.join(arcpy.env.workspace, "connectingLines.shp")

arcpy.FeatureToPoint_management(buildings, centroid, "CENTROID")

arcpy.AddXY_management(centroid) #Adding POINT_X and POINT_Y
arcpy.Near_analysis(centroid, rd, "", "LOCATION", "NO_ANGLE" ) #Adding NEAR_X and NEAR_Y
arcpy.XYToLine_management(centroid, connectingLines, "POINT_X", "POINT_Y", "NEAR_X", "NEAR_Y")
``````

However, what i want is shown in fig 2. If the line connecting road and centroid of building passes through another building then the connecting line should connect to the nearest centroid of a building and not the road.

Possible solution but not complete: Draw the line between centroid and road as shown in fig 1. Delete all lines passing through more than one building. Divide the centroid points as connected and disconnected. Join the disconnected points to nearest connected points. Again delete the lines passing through more than two buildings and repeat process until all points are connected.

Limitation: does not connect centroid of buildings that need to cross more than 2 buildings before connecting to closest connected point.

`````` import arcpy,os, math
from os.path import basename, dirname, exists, join

rd = r"...\road.shp"
buildings = r"...\building.shp"

arcpy.env.workspace =  arcpy.Describe(buildings).path

# remove lines that intersect with more than one/two buildings
def RemoveLine(fc, cnt):
arcpy.AddField_management(fc, "count", "INTEGER" )

with arcpy.da.UpdateCursor(fc, ['count', 'SHAPE@']) as cursor:
for row in cursor:
arcpy.Delete_management("layer")
arcpy.MakeFeatureLayer_management(buildings, "layer")
arcpy.SelectLayerByLocation_management("layer", 'INTERSECT', row[1])
result = arcpy.GetCount_management("layer")
row[0] = int(result.getOutput(0))
cursor.updateRow(row)

arcpy.Delete_management("tempLayer")
if cnt == 1:
arcpy.MakeFeatureLayer_management(fc, "tempLayer")
arcpy.SelectLayerByAttribute_management("tempLayer",  "NEW_SELECTION", '"count" > 1')
arcpy.DeleteFeatures_management("tempLayer")

else:
arcpy.MakeFeatureLayer_management(fc, "tempLayer")
arcpy.SelectLayerByAttribute_management("tempLayer",  "NEW_SELECTION", '"count" > 2')
arcpy.DeleteFeatures_management("tempLayer")

centroid = os.path.join(arcpy.env.workspace, "b_centroid.shp")

arcpy.FeatureToPoint_management(buildings, centroid, "CENTROID")

centroidToRd = os.path.join(arcpy.env.workspace, "centroidToRd.shp")
arcpy.AddXY_management(centroid) # Adding POINT_X and POINT_Y
arcpy.Near_analysis(centroid, rd, "", "LOCATION", "NO_ANGLE" ) # Adding NEAR_X and NEAR_Y
arcpy.XYToLine_management(centroid, centroidToRd, "POINT_X", "POINT_Y", "NEAR_X", "NEAR_Y")

RemoveLine(centroidToRd, 1)

connectingLines = os.path.join(arcpy.env.workspace, "ConnectingLines.shp")
arcpy.CopyFeatures_management(centroidToRd, connectingLines)

cnt = 1
itr = 0
arr = [centroidToRd]

#iterate through centroid points until each one is connected to closest centroid or directly to road

while (cnt > 0  and itr < 5):

itr +=1

unique_name = arcpy.CreateUniqueName("feeder.shp")
arcpy.Delete_management("connected")
arcpy.MakeFeatureLayer_management(centroid, "connected")
arcpy.SelectLayerByLocation_management("connected", 'INTERSECT',    connectingLines, invert_spatial_relationship = "NOT_INVERT")

arcpy.Delete_management("disconnected")
arcpy.MakeFeatureLayer_management(centroid, "disconnected")
arcpy.SelectLayerByLocation_management("disconnected", 'INTERSECT', connectingLines, invert_spatial_relationship = "INVERT")
cnt = arcpy.GetCount_management("disconnected")
#print cnt

arcpy.AddXY_management("disconnected") # Adding POINT_X and POINT_Y
arcpy.Near_analysis("disconnected", "connected", "", "LOCATION", "NO_ANGLE" ) # Adding NEAR_X and NEAR_Y
arcpy.XYToLine_management("disconnected", unique_name, "POINT_X", "POINT_Y", "NEAR_X", "NEAR_Y")

RemoveLine(unique_name, 2)

arr.append(unique_name)
#print arr

arcpy.Delete_management("ConnectingLines.shp")
connectingLines = os.path.join(arcpy.env.workspace, "ConnectingLines.shp")
arcpy.Merge_management(arr, connectingLines)
``````
• You'll need to use an UpdateCursor (DA, of course) to wak each feature to determine if a centroid is closer (and in the right direction). Commented Mar 22, 2017 at 13:47
• The shortest line is the line to keep as all others feed into it in fig2. Also nearest centroid will mean the two smallest buildings will attach to each other, in that case you want to attach to a further centroid which happens to be nearer to road. Commented Mar 22, 2017 at 13:56

## 1 Answer

You could try this tool: SpanningTreeTools:

Tools for creating several variants of the euclidean minimum spanning tree as well as desire lines.

I tried the EMST tool with ArcMap 10.5 on a point layer of building centroids and nearest road. Maybe it is not exactly what you are looking for but worth a try. It it written in Python.

I used it in a model with Iterate Feature Selection.

• Interesting tool. The model is rather slow for large number of points but the tool itself could be useful for various purpose. I will test to integrate it with rest of my program. Thank you.
– Jio
Commented Mar 29, 2017 at 14:08