Removing one point from a multipoint feature class

1724
5
10-19-2010 04:15 PM
JohnReiser
New Contributor III
Hello,

I have a multipoint feature class generated from LAS to Multipoint. In the data, there are a few erroneous points I'd like to delete. The area covered ranges in elevation from 50 to 250 feet above sea level. What I figured I could do is iterate through all the points and remove any that have a Z value below 0 or above 1000.

import arcgisscripting, os, sys, re
gp = arcgisscripting.create(9.3)

if len(sys.argv)< 2:
    gp.AddError("Insufficient parameters.")
    sys.exit(2)

ifc = sys.argv[1]
des = gp.Describe(ifc)
sfn = des.ShapeFieldName
oid = des.OIDFieldName

result = gp.GetCount_management(ifc)
cnt = int(result.GetOutput(0))
gp.AddMessage("%d features in feature class." % cnt)
cursor = gp.updatecursor(ifc)
row = cursor.next()
gp.SetProgressor("step", "Iterating through Multipoints...", 0, cnt, 1)
while row:
    feat = row.GetValue(sfn)
    partnum = 0
    partcount = feat.PartCount
    while partnum < partcount:
        point = feat.GetPart(partnum)
        if((point.z > 1000) or (point.z < 0)):
            gp.AddWarning("Multipoint feature outside of threshold.")
            gp.AddMessage("%d -> %d -> %s" % (row.GetValue(oid), partnum, str(point.z)))
            feat.Remove(partnum)
#        else:    
#            gp.AddMessage(str(partnum) + "->" + str(point.z))
        partnum += 1
    gp.SetProgressorPosition()
    row = cursor.next()


The commented out section, if moved into the if((point.z > 1000) or (point.z < 0)): block will correctly identify the points outside my range. I just don't know how to remove the point in question as I iterate over the array of multipoint parts. I thought I could use the "remove" method on the feature array to remove that specific part, but "feat" does not have the remove method (ie feat.remove(partnum)). point.remove(0) doesn't work either.

Do I have to reconstruct a multipart feature, omitting any offending points and then replace the record, or is there some way to remove vertices/multipoint parts as I'm walking through?

Thanks in advance for your help.
0 Kudos
5 Replies
FrankPerks
New Contributor II
To remove a row within the feature class you need to use the cursor.deleterow method

e.g.:>

import arcgisscripting, os, sys, re
gp = arcgisscripting.create(9.3)

if len(sys.argv)< 2:
    gp.AddError("Insufficient parameters.")
    sys.exit(2)

ifc = sys.argv[1]
des = gp.Describe(ifc)
sfn = des.ShapeFieldName
oid = des.OIDFieldName

result = gp.GetCount_management(ifc)
cnt = int(result.GetOutput(0))
gp.AddMessage("%d features in feature class." % cnt)
cursor = gp.updatecursor(ifc)
row = cursor.next()
gp.SetProgressor("step", "Iterating through Multipoints...", 0, cnt, 1)
while row:
    feat = row.GetValue(sfn)
    partnum = 0
    partcount = feat.PartCount
    while partnum < partcount:
        point = feat.GetPart(partnum)
        if((point.z > 1000) or (point.z < 0)):
            gp.AddWarning("Multipoint feature outside of threshold.")
            gp.AddMessage("%d -> %d -> %s" % (row.GetValue(oid), partnum, str(point.z)))
            # To remove you must use updatecursor.deleterow(<row>)
            cursor.deleterow(row)
            # ^^^^^^^^^^^^^^
            ###feat.Remove(partnum)
#        else:    
#            gp.AddMessage(str(partnum) + "->" + str(point.z))
        partnum += 1
    gp.SetProgressorPosition()
    row = cursor.next()
0 Kudos
JohnReiser
New Contributor III
That wil remove one record from the feature class. Each record has 3500 LIDAR returns, so removing one record is overkill to rid myself of one erroneous return. I have a few bad returns and they not all within the same record, so removing whole records will leave gaps in my terrain. I need to remove one point within the set of 3500 stored in one record. Multipart to singlepart is not a viable option, as it makes the file sizes increase considerably.

Thanks.
0 Kudos
LoganPugh
Occasional Contributor III
This seems to work for me:
import arcgisscripting

gp = arcgisscripting.create(9.3)

ifc = r"c:\temp\test.gdb\testMulti"

des = gp.Describe(ifc)
sfn = des.ShapeFieldName
oid = des.OIDFieldName

result = gp.GetCount_management(ifc)
cnt = int(result.GetOutput(0))
gp.AddMessage("%d features in feature class." % cnt)
cursor = gp.updatecursor(ifc)
row = cursor.next()
while row:
    feat = row.GetValue(sfn)
    pointArray = feat.GetPart()
    boolNeedsUpdate = 0
    pointCount = pointArray.Count
    pointIndex = pointCount - 1
    while pointIndex >= 0:
        point = pointArray.GetObject(pointIndex)
        if((point.z > 1000) or (point.z < 0)):
            boolNeedsUpdate = 1
            gp.AddWarning("Multipoint feature outside of threshold.")
            gp.AddMessage("%d -> %d -> %s" % (row.GetValue(oid), pointIndex, str(point.z)))
            pointArray.Remove(pointIndex)
        pointIndex -= 1
    if boolNeedsUpdate:
        gp.AddMessage("Removing point(s)")
        row.shape = pointArray
        cursor.UpdateRow(row)
    row = cursor.next()


What I'm doing is getting an array of point objects from the geometry object (GetPart() with no arguments returns an array of points instead of a single point object), then iterating through the array backwards since we're removing items from it, and removing the points with the invalid Z values. After that we set the row's shape to the new pointArray and update the row before moving on to the next row.
0 Kudos
JohnReiser
New Contributor III
This seems to work for me:


And it works for me, too. Many thanks!
0 Kudos
DanLee
by Esri Regular Contributor
Esri Regular Contributor
You might be able to use geoprocessing tools to do this:
1. Use Multipart To Singlepart tool to convert your multipoint feature class to single points. Each point will carry the ORIG_FID field.
2. Select the points you need to delete.
3. Run Delete Features tool.
4. Use Dissolve tool with ORIG_FID as the dissolve field. You should get your multipoints back.

Regards,
0 Kudos