Esiste lo strumento ArcPy per il ridimensionamento dei poligoni come lo strumento Scala della barra degli strumenti Modifica avanzata in ArcMap?


17

Sto scrivendo uno script Python per ArcGIS 10.3. Conosco l' Scale toolinterfaccia ArcGIS ma non riesco a trovare un comando così arcpico. Esiste?

Come puoi vedere nell'immagine, Scale toolfunziona diversamente da Buffer tool- cambia la forma del poligono originale. Quindi la domanda è:

Posso usare Scale tool(disponibile dall'interfaccia ArcGIS) usando arcpy?

inserisci qui la descrizione dell'immagine


2
Che ne dici di buffering e rimozione del vecchio poligono !? il buffer può essere utilizzato con valori positivi e negativi!
Farid Cheraghi,

La domanda riguarda lo strumento arcpy esistente, non su come ridimensionare un poligono.
Mr. Che

Il titolo, la domanda e il commento sembrano essere in contrasto tra loro. Se le domande duplicate fornite non rispondono alla tua domanda, potresti modificare la domanda per chiarire cosa stai cercando?
Aaron

1
Lo strumento Buffer di Mr.Che può essere utilizzato negli script Python tramite arcpy.Buffer_analysis (...)
Farid Cheraghi,

Questo è super! Come posso aggiornare ogni classe di funzionalità di un numero in una tabella anziché ridimensionare tutte le funzionalità di 0,5, ad esempio? Grazie
user1655130

Risposte:


27

Non sono a conoscenza di nulla nell'API arcpy che farà il ridimensionamento per te, ma scrivere una funzione per farlo sarebbe relativamente semplice.

Il codice seguente esegue il ridimensionamento per le funzionalità 2D e non tiene conto dei valori M o Z:

import arcpy
import math

def scale_geom(geom, scale, reference=None):
    """Returns geom scaled to scale %"""
    if geom is None: return None
    if reference is None:
        # we'll use the centroid if no reference point is given
        reference = geom.centroid

    refgeom = arcpy.PointGeometry(reference)
    newparts = []
    for pind in range(geom.partCount):
        part = geom.getPart(pind)
        newpart = []
        for ptind in range(part.count):
            apnt = part.getObject(ptind)
            if apnt is None:
                # polygon boundaries and holes are all returned in the same part.
                # A null point separates each ring, so just pass it on to
                # preserve the holes.
                newpart.append(apnt)
                continue
            bdist = refgeom.distanceTo(apnt)

            bpnt = arcpy.Point(reference.X + bdist, reference.Y)
            adist = refgeom.distanceTo(bpnt)
            cdist = arcpy.PointGeometry(apnt).distanceTo(bpnt)

            # Law of Cosines, angle of C given lengths of a, b and c
            angle = math.acos((adist**2 + bdist**2 - cdist**2) / (2 * adist * bdist))

            scaledist = bdist * scale

            # If the point is below the reference point then our angle
            # is actually negative
            if apnt.Y < reference.Y: angle = angle * -1

            # Create a new point that is scaledist from the origin 
            # along the x axis. Rotate that point the same amount 
            # as the original then translate it to the reference point
            scalex = scaledist * math.cos(angle) + reference.X
            scaley = scaledist * math.sin(angle) + reference.Y

            newpart.append(arcpy.Point(scalex, scaley))
        newparts.append(newpart)

    return arcpy.Geometry(geom.type, arcpy.Array(newparts), geom.spatialReference)

Puoi chiamarlo con un oggetto geometria, un fattore di scala (1 = stessa dimensione, 0,5 = mezza dimensione, 5 = 5 volte più grande, ecc.) E un punto di riferimento opzionale:

scale_geom(some_geom, 1.5)

Usalo insieme ai cursori per ridimensionare un'intera classe di entità, supponendo che la classe di caratteristiche di destinazione esista già:

incur = arcpy.da.SearchCursor('some_folder/a_fgdb.gdb/orig_fc', ['OID@','SHAPE@'])
outcur = arcpy.da.InsertCursor('some_folder/a_fgdb.gdb/dest_fc', ['SHAPE@'])

for row in incur:
    # Scale each feature by 0.5 and insert into dest_fc
    outcur.insertRow([scale_geom(row[1], 0.5)])
del incur
del outcur

modifica: ecco un esempio usando un'approssimazione della geometria del test, per 0,5 e 5 volte: inserisci qui la descrizione dell'immagine

Testato anche con poligoni multi-ring (fori)! inserisci qui la descrizione dell'immagine

Una spiegazione, come richiesto:

scale_geomprende un singolo poligono e scorre attraverso ciascun vertice, misurando la distanza da esso a un punto di riferimento (per impostazione predefinita, il centroide del poligono).
Tale distanza viene quindi ridimensionata dalla scala fornita per creare il nuovo vertice "ridimensionato".

Il ridimensionamento viene eseguito essenzialmente tracciando una linea alla lunghezza in scala dal punto di riferimento attraverso il vertice originale, con la fine della linea che diventa il vertice in scala.
L'angolo e la rotazione sono lì perché è più semplice calcolare la posizione dell'estremità della linea lungo un singolo asse e quindi ruotarla "in posizione".


1
Ho testato questo script e funziona benissimo. Sei un dannato genio! =) Grazie mille. Lascerò senza riserve questa domanda, quindi più persone la vedranno nelle "domande futili".
Mr. Che

1
Ho scoperto che quando tento di elaborare un poligono con un buco, si verifica un arresto anomalo dello script in linea bdist = refgeom.distanceTo(apnt). Puoi testarlo e risolverlo?
Mr. Che

@ Mr.Che Oops, ho dimenticato che ArcPy restituisce tutti gli anelli di una parte poligonale nello stesso array. Gli anelli sono separati da punti nulli. È una soluzione semplice, per favore vedi la modifica.
Evil Genius,

Ciao. È possibile ottenere una piccola spiegazione di come funziona lo script, io non sono bravo a scrivere codice e non ottengo tutte le righe, quindi non funziona per me, per favore?
Pietro,

@peter Certo, ho aggiunto una breve spiegazione di ciò che sta succedendo. Non è pensato per essere uno script autonomo, ma qualcosa da integrare in uno script tutto tuo. Lo snippet di codice in basso mostra un esempio di come potrebbe essere utilizzato.
Evil Genius
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.