Lees de helponderwerpen...
1 Featureclass Naar NumPy Arraya0
FeatureClassToNumPyArray kan worden gebruikt om de vertices uit geometrie features te halen. Als ze enkelvoudig zijn zonder gaten, dan heb je een exacte representatie die kan worden gebruikt om de inputs te reconstrueren. Als dat niet het geval is, vergt reconstructie wat werk (zie https://github.com/Dan-Patterson/numpy_geometry voor de `npg` module).
2 NumPy Array naar Featureclassa0
NumPyArrayToFeatureClass zal een bestaande feature class niet overschrijven, zelfs niet als de overwriteOutput omgeving op True staat.
------------------------------
Stap voor stap... een notebook is bijgevoegd
# ---- Imports
import arcpy
import numpy as np
from numpy.lib.recfunctions import structured_to_unstructured as stu
from numpy.lib.recfunctions import append_fields # zoals arcpy ExtendTable
Ik ga ervan uit dat je een notebook gebruikt in ArcGIS Pro. Ik demonstreer een eenvoudige conversie van polygonen naar alle punten. De andere opties kunnen ook gecodeerd worden, of koop gewoon een hoger licentieniveau van Pro.
a0
Ga ervan uit dat je laag in een kaart staat. Specificeer de laagnaam en of je extra tabelvelden wilt meenemen.
# Specificeer de laag om te gebruiken voor de `lyr_name` variabele
# Dit werkt alleen voor featureclasses... geen verdere foutcontrole... de druk ligt erop
#
lyr_name = 'sq3' # -- voer de naam van de featureclass in
extra_fields = True # -- True behoudt alle extra velden, anders False... alleen sommige? schrijf je eigen code
a0
Nu de grote stap.
- controleer of de laag bestaat in de actieve kaart. Als dat zo is, ga door, anders stop.
- de datasource van de laag en de ruimtelijke referentie worden verkregen,
- een lijst met velden om uit te sluiten van de output (regels 11-15)
- een array wordt gemaakt (regels 16-21). Dit is een numpy array geproduceerd door de arcpy.da functie die hiervoor ontworpen is.
- wat opruiming volgt, outputvelden worden gespecificeerd en toegevoegd aan de output (indien aanwezig)
- de output featureclass wordt aangemaakt (regel 36)
- en toegevoegd aan de kaart (regel 37)
# ---- Project, kaart en laagcollectie
# Het huidige project met de actieve kaart wordt gecontroleerd op de hierboven opgegeven laagnaam.
# Als deze bestaat, worden de vertices geconverteerd naar een punt-featureclass.
#
aprx = arcpy.mp.ArcGISProject("CURRENT")
map_ = aprx.activeMap
lyrs = map_.listLayers(lyr_name)
if lyrs:
in_fc = lyrs[0].dataSource # -- pad naar de featureclass
SR = arcpy.Describe(in_fc).spatialReference
ignore_flds = ['OBJECTID', 'Shape', 'Shape_Area', 'Shape_Length'] # -- voeg toe als je wilt
keep_flds = ["OID@", "SHAPE@X", "SHAPE@Y"]
if extra_fields:
add_flds = [f.name for f in arcpy.ListFields(in_fc) if f.name not in 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
)
# -- controles voor output featureclass
out_fc = in_fc + "_pnts"
if arcpy.Exists(out_fc): # -- verwijder als het bestaat
arcpy.management.Delete(out_fc)
#
# -- array controles en combineren van coördinaatwaarden
dt_ = arr.dtype
dt_names = [(i[0].replace("@", "_"), i[1]) for i in arr.dtype.descr]
arr.dtype = dt_names
#
final_arr = append_fields(arr, ["Pnt_x", "Pnt_y"], [arr["SHAPE_X"], arr["SHAPE_Y"]])
print("\nOutputvelden :\n{}".format(final_arr.dtype.names))
#
# -- produceer de output en voeg toe aan de kaart.
arcpy.da.NumPyArrayToFeatureClass(final_arr, out_fc, ["SHAPE_X", "SHAPE_Y"], spatial_reference=SR)
map_.addDataFromPath(out_fc) # -- voeg resultaten toe aan de kaart
#
else:
print("Geen laag genaamd {}".format(lyr_name))
En de resultaten zijn
Ik zal je de tabelinhoud besparen, maar ze zijn er wel.
--------------
Als je liever het python venster gebruikt
import arcpy
import numpy as np
in_fc = r"C:\...pad naar je laag...\...laagnaam..."
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)' vertaald als 'Dit toont het gestructureerde array dataformaat. (ingekort ter vereenvoudiging)' maar volgens instructies moet dit vertaald worden dus: 'Toont het gestructureerde array dataformaat. (ingekort ter vereenvoudiging)'
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.