Lea los temas de ayuda...
1 Featureclass a matriz NumPy
FeatureClassToNumPyArray se puede usar para extraer los vértices de las entidades geométricas. Si son de una sola parte sin huecos, entonces tienes una representación exacta que se puede usar para recrear las entradas. Si no es así, la reconstrucción requiere algo de trabajo (ver https://github.com/Dan-Patterson/numpy_geometry para el módulo `npg`).
2 Matriz NumPy a Featureclass
NumPyArrayToFeatureClass no sobrescribirá una clase de entidad existente, incluso si el entorno overwriteOutput está configurado en True.
------------------------------
Paso a paso... se adjunta un cuaderno
# ---- Importaciones
importar arcpy
importar numpy como np
desde numpy.lib.recfunctions importar structured_to_unstructured como stu
desde numpy.lib.recfunctions importar append_fields # como arcpy ExtendTable
Asumiré que estás usando un cuaderno en ArcGIS Pro. Haré una demostración de una conversión simple de polígonos a todos los puntos. Las otras opciones también pueden ser codificadas, o simplemente compra un nivel de licencia superior de Pro.
Asume que tu capa está en un mapa. Especifica el nombre de la capa y si deseas conservar campos adicionales de la tabla.
# Especifica la capa a usar para la variable `lyr_name`
# Esto solo funciona para featureclasses... sin más comprobaciones de errores... la presión está sobre ti
#
lyr_name = 'sq3' # -- ingresa el nombre del featureclass
extra_fields = True # -- True conserva todos los campos extra, False de lo contrario... ¿solo algunos? escribe el tuyo propio
Ahora el gran paso.
- verifica que la capa exista en el mapa activo. Si existe, continúa, de lo contrario termina.
- se obtiene la fuente de datos de la capa y la referencia espacial,
- una lista de campos para eliminar del resultado (líneas 11-15)
- se crea una matriz (líneas 16-21). Esta es una matriz numpy producida por la función arcpy.da diseñada para este propósito.
- sigue una limpieza, se especifican los campos de salida y se agregan al resultado (si hay alguno)
- se crea la clase de entidad de salida (línea 36)
- y se añade al mapa (línea 37)
# ---- Proyecto, mapa y colección de capas
# Se verifica el proyecto actual con el mapa activo para el nombre de capa que especificaste arriba.
# Si existe, los vértices se convertirán en una clase de entidad puntual.
#
aprx = arcpy.mp.ArcGISProject("CURRENT")
mapa = aprx.activeMap
capas = mapa.listLayers(lyr_name)
si capas:
in_fc = capas[0].dataSource # -- ruta al featureclass
SR = arcpy.Describe(in_fc).spatialReference
ignore_flds = ['OBJECTID', 'Shape', 'Shape_Area', 'Shape_Length'] # -- agrega si quieres
keep_flds = ["OID@", "SHAPE@X", "SHAPE@Y"]
si extra_fields:
add_flds = [f.name para f en arcpy.ListFields(in_fc) si f.name no está en ignore_flds]
keep_flds = keep_flds + add_flds
arr = arcpy.da.FeatureClassToNumPyArray(
in_fc,
field_names=keep_flds,
spatial_reference=SR,
explode_to_points=True
)
# -- comprobaciones para la clase de entidad de salida
out_fc = in_fc + "_pnts"
si arcpy.Exists(out_fc): # -- elimina si existe
arcpy.management.Delete(out_fc)
#
# -- comprobaciones del arreglo y combinación de valores coordenados
dt_ = arr.dtype
dt_names = [(i[0].replace("@", "_"), i[1]) para i en arr.dtype.descr]
arr.dtype = dt_names
#
final_arr = append_fields(arr, ["Pnt_x", "Pnt_y"], [arr["SHAPE_X"], arr["SHAPE_Y"]])
print("\nCampos de salida :\n{}".format(final_arr.dtype.names))
#
# -- produce la salida y añade al mapa.
arcpy.da.NumPyArrayToFeatureClass(final_arr, out_fc, ["SHAPE_X", "SHAPE_Y"], spatial_reference=SR)
mapa.addDataFromPath(out_fc) # -- añade resultados al mapa
#
sino:
print("No hay ninguna capa llamada {}".format(lyr_name))
Y los resultados son
Te ahorraré el contenido de la tabla, pero están ahí.
--------------
Si prefieres la ventana python
importar arcpy
importar numpy como np
in_fc = r"C:\...ruta a tu capa...\...nombre_capa..."
keep_flds = ["OID@", "SHAPE@X", "SHAPE@Y"]
SR = arcpy.Describe(in_fc).spatialReference
arr = arcpy.da.FeatureClassToNumPyArray(
in_fc,
field_names=keep_flds,
spatial_reference=SR,
explode_to_points=True
)
Which shows the structured array data format. (snipped to simplify)
arr
array([(1, 300009. , 5000001. ), (1, 300000. , 5000000. ),
(1, 300002. , 5000008. ), (1, 300008. , 5000010. ),
... snip
(7, 300004. , 5000009. ), (7, 300002. , 5000009. ),
(7, 300002. , 5000011. )],
dtype=[('OID@', '<i4'), ('SHAPE@X', '<f8'), ('SHAPE@Y', '<f8')])
You can then split the array into its constituent shapes using the OID@ field. Basically determine the difference in the sequential id values, where they differ from 0, get the positional index to use for splitting.
spl = np.nonzero(np.diff(arr["OID@"]))[0] + 1
From there, you can produce subarrays
subs = np.array_split(arr, spl)
subs[0] # -- the first as an example
array([(1, 300009.000, 5000001.000), (1, 300000.000, 5000000.000),
(1, 300002.000, 5000008.000), (1, 300008.000, 5000010.000),
(1, 300010.000, 5000010.000), (1, 300010.000, 5000008.000),
(1, 300009.000, 5000001.000), (1, 300003.000, 5000003.000),
(1, 300007.000, 5000003.000), (1, 300005.000, 5000007.000),
(1, 300003.000, 5000003.000)],
dtype=[('OID@', '<i4'), ('SHAPE@X', '<f8'), ('SHAPE@Y', '<f8')])
From there you could process to just take the first or last point (one of the main tool options that requires and advanced licence).
frst = [i[0] for i in subs] # let's grab the first point of each shape
frst
[(1, 300009.000, 5000001.000),
(2, 300010.000, 5000008.000),
(3, 300008.000, 5000011.000),
(4, 300006.000, 5000012.000),
(5, 300002.500, 5000013.000),
(6, 300004.000, 5000012.500),
(7, 300002.000, 5000011.000)]
As a teaser, you can even place a point at a certain percentage along the polygon perimeter with a little numpy magic
from numpy.lib.recfunctions import structured_to_unstructured as stu
base = [stu(a[["SHAPE@X", "SHAPE@Y"]]) for a in subs]
halfway = [_percent_along_(a, percent=50) for a in base]
halfway
[array([ 300010.000, 5000009.950]),
array([ 300008.500, 5000012.000]),
array([ 300005.000, 5000010.310]),
array([ 300005.056, 5000014.972]),
array([ 300000.214, 5000010.643]),
array([ 300002.527, 5000012.991]),
array([ 300003.894, 5000009.000])]
and the function for placing the points
def _percent_along_(a, percent=0):
"""Add a point along a poly feature at a distance from the start point."""
# a = _base_(a)
if percent > 1.:
percent /= 100.
dxdy = a[1:, :] - a[:-1, :] # coordinate differences
leng = np.sqrt(np.einsum('ij,ij->i', dxdy, dxdy)) # segment lengths
cumleng = np.concatenate(([0], np.cumsum(leng)))
perleng = cumleng / cumleng[-1]
if percent <= 0: # check for faulty distance or start point
return a[0]
if percent >= perleng[-1]: # check for greater distance than cumulative
return a[-1]
_end_ = np.digitize(percent, perleng)
x1, y1 = a[_end_]
_start_ = _end_ - 1
x0, y0 = a[_start_]
t = percent - perleng[_start_]
xt = x0 * (1. - t) + (x1 * t)
yt = y0 * (1. - t) + (y1 * t)
return np.array([xt, yt])
Or you can 'arcpy' it if you prefer to crank up Pro.
So, basic functionality shouldn't be completely removed by license levels. If you have the need convert features to points, remember that tools are available within.