Update existing point geometry to GPS XY via field calculator & python?

10069
15
08-08-2011 02:33 PM
AmyWright_Webber
New Contributor III
Hello -

Thank you in advance for any help you can offer!

I have a topology between a manhole FC and main lines FC set up so that we can manually snap the existing MH to the new GPS points and have the main lines stay attached.  While this works, there are thousands to do and we are looking for a better method.

Using a common manhole ID, I have moved the GPS coordinates into two attribute fields GPS_X and GPS_Y) in the attribute table of the manhole feature class.

Is it possible to update the position of the manhole point with the values in the GPS_X and GPS_Y fields using python and the field calculator (other suggestions welcome)? My hope would be that we could and that the main would follow the "move" of the manhole point due to the topology rules.

I have attached a screen shot showing the GPS points (green), the manholes, and main lines.  The attribute table shown is that of the manholes.

Any other suggestion on how to mass update the locations of the old manholes while moving the attached mains with them would be greatly appreciated!

Sincerely,

Amy
Tags (2)
15 Replies
JakeSkinner
Esri Esteemed Contributor
Before testing this, I would recommend making a copy of your feature dataset as a backup.  Here is some sample code that will move your point features based on the GPS fields:

import arcpy
from arcpy import env

env.workspace = "C:/Temp/Python/test.gdb"

fc = "Parker_R6_Manhole_1"

pnt = arcpy.Point()

rows = arcpy.UpdateCursor(fc)
for row in rows:
    pnt.X = row.GPS_X
    pnt.Y = row.GPS_Y
    row.shape = pnt
    rows.updateRow(row)

del row, rows


The tricky part is having the mains move with the manholes.  I was able to get this to work by specifying a larger cluster tolerance and setting the rank for the manhole feature class to 1, and the rank for the mains feature class to 2 within the topology.  If the distance the points moved is less than the cluster tolerance, the mains will snap to the updated manholes upon validation.
0 Kudos
AmyWright_Webber
New Contributor III
Thank you!!  This does work quite nicely for moving the existing points to the new GPS coordinates and I am saving it as I know it will come in handy.  This would be great to update manhole locations when you have not built your lines yet. 

However, as you pointed out this does not result in the mains moving automatically.  Results from increasing the cluster tolerance are mixed at best and each line needs to be reviewed to verify that it is snapped to the correct location.  Some of the moves from old to new location are only a few feet but most are more.  Since each feature has to be double checked - it is easier to just use the topology tool to move the manhole with the mains attached.

At this point it looks like we would need to either continue with the manual snapping of each old manhole to the new GPS PT using the topology tool in order to have the mains stay connected or write some custom code to add to what you provided.  This additional code would do something like select the end of the line coincident to the manhole and then move the endpoint of that line to the same new GPS location as the manhole.  Most pipes are two point lines so this would work in most cases without additional cleanup.

I am continueing to experiment with code solutions but in the meantime we are using the Topology to manually move the points with the mains attached since maintains the connectivity.

Suggestions or additional code advice to move the endpoints of the coincident lines are very much appreciated!

Thanks!

Sincerely

Amy
0 Kudos
JakeSkinner
Esri Esteemed Contributor
Hi Amy,

I looked into updating the polylines using python, but this may not be possible.  A polyline object's properties are all read-only.  Therefore I could not find a way to write new coordinate values to the end points of the mains.

Something you can do to possibly help you is to write some code to obtain the OBJECTIDs of the mains that need to be moved.  This will provide you a list with the feature's end points that are not snapped to a manhole.  Ex:

import arcpy
from arcpy import env

env.overwriteOutput = True
env.workspace = r"C:\Temp\Python\test.gdb"

fc = "swManhole"
fc2 = "swGravityMain"

pnt = arcpy.Point()

# Move Manholes to GPS location
rows = arcpy.UpdateCursor(fc)
for row in rows:
    pnt.X = row.POINT_X
    pnt.Y = row.POINT_Y
    row.shape = pnt
    rows.updateRow(row)

del row, rows

# Convert Main endpoints to points feature class
arcpy.FeatureVerticesToPoints_management(fc2, "Main_EndPts", "END")

# Find all Main endpoints within 5 feet of manholes
arcpy.Near_analysis("Main_EndPts", fc, "5")

# Create a layer of all Main endpoints within 5 feet of manholes
lyr = arcpy.MakeFeatureLayer_management("Main_EndPts", "Main_EndPts_Lyr", "NEAR_DIST > 0")

list = []

# Append X & Y values of Main endpoints to list
rows = arcpy.SearchCursor(lyr)
for row in rows:
    list.append(float(row.shape.centroid.X) + float(row.shape.centroid.Y))

del row, rows

OBJECTIDs = []

# Find OBJECTIDs of the Mains that need to be moved
rows = arcpy.SearchCursor(fc2)
for row in rows:
    geom = row.shape
    XY = float(geom.lastPoint.X) + float(geom.lastPoint.Y)
    if XY in list:
        OBJECTIDs.append(row.OBJECTID)

del row, rows

arcpy.Delete_management("Main_EndPts")

print OBJECTIDs
0 Kudos
DillonFitch
New Contributor
I'm not sure if anyone is still interested in this topic, but I just tried the initial code in this thread after creating a geometric network with my mains and nodes. It updated my point locations and it moved the lines too!

Dillon
0 Kudos
AlanTonkin
Occasional Contributor
Hi Jake,

I need to do exactly what Dillon was wanting to do but not as a standalone Python script. What code would need to be used to perform the same calculation from within the Field Calculator dialog (as depicted in his original attached screenshot)?

Any help or suggestions appreciated.

Alan
0 Kudos
JakeSkinner
Esri Esteemed Contributor
Hi Alan,

You can place the code within a function and execute it using the field calculator (right-click on 'Shape' field).  Ex:

def update():
  fc = r"C:\temp\python\test.gdb\Vehicle"
  pnt = arcpy.Point()
  rows = arcpy.UpdateCursor(fc)
  for row in rows:
    pnt.X = row.GPS_X
    pnt.Y = row.GPS_Y
    row.shape = pnt
    rows.updateRow(row)
  del row, rows


Be sure that you have 'Python' checked at the top of the field calculator, and you will want to specify 'update()' under the Pre-logic script code dialog.  Ex:

[ATTACH=CONFIG]33269[/ATTACH]
AlanTonkin
Occasional Contributor
Hi Alan,

You can place the code within a function and execute it using the field calculator.  Ex:

def update():
  fc = r"C:\temp\python\test.gdb\Vehicle"
  pnt = arcpy.Point()
  rows = arcpy.UpdateCursor(fc)
  for row in rows:
    pnt.X = row.GPS_X
    pnt.Y = row.GPS_Y
    row.shape = pnt
    rows.updateRow(row)
  del row, rows


Be sure that you have 'Python' checked at the top of the field calculator, and you will want to specify 'update()' under the Pre-logic script code dialog.  Ex:

[ATTACH=CONFIG]33269[/ATTACH]


Hi Jake,

Many thanks for the response. Can you explain to me why the following python code doesn't work?

I have joined my GPS shapefile to my point feature class (Point Z) based on a unique ID field present in both datasets. In the attribute window of my feature class I have 2 features selected (just as a test). I right-click on the SHAPE field and choose Field Calculator. I change my parser to Python and tick Show Codeblock.

Under the Pre-Logic Script Code, I have the following:

def SetToGPS( shape,newx,newy 😞
  point = shape.getPart(0)
  point.X = newx
  point.Y = newy
  return point

And under the bottom box I have:

SetToGPS( !mobile.SDE.WaterDevices.SHAPE!, !Gledhow_Devices_Surveyed_By_Andrew2.ArcMapX!, !Gledhow_Devices_Surveyed_By_Andrew2.ArcMapY! )

This results in a syntax error. In the code that you have suggested, the GPS_X and GPS_Y fields are presumed to be immediate fields in the feature class. In my case they are joined fields, so how do i reference them?

Regards,

Alan

Edited:

The following worked for me. I had to add immediate fields to the feature class to hold the new X & Y values (GPS_X & GPS_Y) and while the join was still present, calculate these fields with the values from my joined fields. I then removed the join from my feature class and the code below then ran without a problem:

CODE:

def Update(newx, newy):
  pnt = arcpy.Point()
  pnt.X = newx
  pnt.Y = newy
  return pnt

SHAPE =

Update( !GPS_X!, !GPS_Y!)

Jake, maybe you could explain why I couldn't do this while there was still a join present and why it only took immediate fields as input into the function?
0 Kudos
JeremyJung3
New Contributor

Alan and Jake,

 

The Python script works great, but unfortunately I have some Null Values in my GPS Data(we had to digitize some data). Is there any way to use the python script you provided and have it leave all Null or blank values alone? When I use the python script it will remove any points with no GPS data thus I'm losing points, any help would be appreciated thank you!

0 Kudos
JakeSkinner
Esri Esteemed Contributor
It appears this is a bug, NIM097273.
0 Kudos