[GIS] Converting Vertices of Polylines and Polygons to Points and Maintain Attributes

arcgis-desktoparcpypointpythonvertices

I'm pretty sure someone has done this before, but I'm having no luck. I'm using ArcGIS Standard version 10.2.1 and I want to convert all the vertices of a polyline or polygon to points. Essentially, I want to emulate the Feature Vertices to Points tool (which I can't use due to my ArcGIS license). I'm writing a python tool, so any answers should reflect a python/arcpy solution. Therefore, nothing like ET Geowizards, etc.

I want to maintain the fields of the original data and in addition, add X and Y fields as well as a point identifier. So, if the input fields look like this:

LABEL |  TYPE  |  CODE
abc   |  type1 |  3
def   |  type2 |  4

Then the resulting output points might look like this:

LABEL |  TYPE  |  CODE  |  LONG  |  LAT  | ID
abc   |  type1 |  3     |  153   | -27.5 | 1
abc   |  type1 |  3     |  150   | -27.5 | 2
def   |  type2 |  4     |  151   | -30   | 1
def   |  type2 |  4     |  151   | -29.5 | 2
def   |  type2 |  4     |  151   | -30.7 | 3
def   |  type2 |  4     |  151   | -30   | 4

I've looked at this solution, which is fantastic and quick, but it doesn't maintain the fields of the original data. I've also looked at modifying this blog post which seems to be the most promising, but again, I can't figure out how to keep the original fields.

My code looks something like this:

fields = arcpy.ListFields(input_fc)
arcpy.CreateFeatureclass_management(destination_workspace, point_file_name, "POINT")
for field in fields:
    fieldnames.append(field.name)
    if field.type in ('TEXT', 'FLOAT', 'DOUBLE', 'SHORT', 'LONG', 'DATE', 'BLOB', 'RASTER', 'GUID'):
        arcpy.AddField_management(point_file_name, field.name, field.type, field.precision, field.scale, field.length, field.aliasName, field.isNullable)

fieldnames.append("SHAPE@JSON")
cursor = arcpy.da.InsertCursor(output_fc, fieldnames)

with arcpy.da.SearchCursor(input_fc, fieldnames) as c:
        for row in c:
            geom = json.loads(row[-1])
            for path in geom['paths']:
                for pt in path:
                    cursor.insertRow(row[0:-1],pt)

It's failing with the insert cursor. The error message I'm getting is:

Traceback (most recent call last):
File "H:\Python\CreatePoints_v0_2.py", line 60, in
cursor.insertRow(row[0:-1],pt) RuntimeError: Cannot find field 'LABEL'

The input feature class has a field called "LABEL". However, it's not adding that label to the created feature class.

Note, I want to convert vertices, not centroids.

I'm probably going about this the wrong way, so if anyone has ideas on how to either modify my code, or point me in another direction, I'd be appreciative.

Best Answer

I think you're getting the error because the fieldnames list still contains the field LABEL, but you said you're not adding it to the output_fc.

for field in fields:
    fieldnames.append(field.name)

Right here you're getting all the field names.

If you do a print statement above this line:

cursor = arcpy.da.InsertCursor(output_fc, fieldnames)

I assume you'll see LABEL as a field which was not added to the output_fc.

You should only append the fields that you add to the output_fc.

I would think that this should work:

for field in fields:
    if field.type in ('TEXT', 'FLOAT', 'DOUBLE', 'SHORT', 'LONG', 'DATE', 'BLOB', 'RASTER', 'GUID'):
        arcpy.AddField_management(point_file_name, field.name, field.type, field.precision, field.scale, field.length, field.aliasName, field.isNullable)
        fieldnames.append(field.name)

Unless I'm misunderstanding and the problem is that you aren't able to add the LABEL field to the output_fc.


EDIT

The fields aren't adding because the TEXT is actually "String", DOUBLE is "Double", etc.

Try this:

for field in fields:
    print field.type

And see what the output is. You need to match that.

Here's what field.type returns:

http://help.arcgis.com/en/arcgisdesktop/10.0/help/index.html#//000v0000001p000000

All — All field types are returned. This is the default.
Date — Only field types of Date are returned.
Double — Only field types of Double are returned.
Geometry — Only field types of Geometry are returned.
GUID — Only field types of GUID are returned.
Integer — Only field types of Integer are returned.
OID — Only field types of OID are returned.
Raster — Only field types of Raster are returned.
Single — Only field types of Single are returned.
SmallInteger — Only field types of SmallInteger are returned.
String — Only field types of String are returned.

If I were you, I'd just use the template parameter to add the fields.

CreateFeatureclass_management (out_path, out_name, {geometry_type}, {template}, {has_m}, {has_z}, {spatial_reference})

So you could just put:

arcpy.CreateFeatureclass_management(destination_workspace, point_file_name, "POINT", input_fc, "", "", input_fc)

This will create the new feature class including all the fields in the input feature class and it's spatial reference.

Related Question