Czy w narzędziu ArcMap jest narzędzie ArcPy do zmiany rozmiaru wielokąta, jak narzędzie Skalowanie paska narzędzi Zaawansowana edycja?

17

Piszę skrypt Pythona dla ArcGIS 10.3. Wiem o Scale toolinterfejsie ArcGIS, ale nie mogę znaleźć takiego polecenia. Istnieje?

Jak widać na zdjęciu, Scale tooldziała on inaczej niż Buffer tool- zmienia formę oryginalnego wielokąta. Pytanie brzmi:

Czy mogę korzystać Scale tool(dostępne z interfejsu ArcGIS) za pomocą Arcpy?

wprowadź opis zdjęcia tutaj

Mr. Che
źródło
2
Co powiesz na buforowanie i usuwanie starego wielokąta !? bufor może być używany z wartościami dodatnimi i ujemnymi!
Farid Cheraghi,
Pytanie dotyczy istniejącego narzędzia Arcpy, a nie sposobu zmiany rozmiaru wielokąta.
Pan Che
Twój tytuł, pytanie i komentarz wydają się ze sobą sprzeczne. Jeśli dostarczone zduplikowane pytania nie odpowiadają na twoje pytanie, czy możesz je edytować, aby wyjaśnić, czego szukasz?
Aaron
1
@ Narzędzie Mr.Che Buffer może być używane w skryptach Pythona poprzez arcpy.Buffer_analysis (...)
Farid Cheraghi
To jest super! Jak mogę zaktualizować każdą klasę funkcji o liczbę w tabeli, zamiast na przykład skalować wszystkie funkcje o 0,5? Dzięki
użytkownik1655130,

Odpowiedzi:

27

Nie znam niczego w Arcpy API, które wykonałoby skalowanie za ciebie, ale napisanie funkcji, która by to zrobiła, byłoby stosunkowo proste.

Poniższy kod wykonuje skalowanie elementów 2D i nie uwzględnia wartości M ani 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)

Możesz to nazwać obiektem geometrycznym, współczynnikiem skali (1 = taki sam rozmiar, 0,5 = pół rozmiaru, 5 = 5 razy większy itp.) I opcjonalnym punktem odniesienia:

scale_geom(some_geom, 1.5)

Użyj tego w połączeniu z kursorami, aby skalować całą klasę obiektów, zakładając, że docelowa klasa obiektów już istnieje:

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

edycja: oto przykład z przybliżeniem twojej geometrii testowej, 0,5 i 5 razy: wprowadź opis zdjęcia tutaj

Przetestowano również z wielokątami wielokątnymi (dziurami)! wprowadź opis zdjęcia tutaj

Wyjaśnienie, zgodnie z prośbą:

scale_geompobiera pojedynczy wielokąt i zapętla się przez każdy wierzchołek, mierząc odległość od niego do punktu odniesienia (domyślnie środek ciężkości wielokąta).
Odległość ta jest następnie skalowana na podstawie skali podanej w celu utworzenia nowego „skalowanego” wierzchołka.

Skalowanie odbywa się zasadniczo poprzez narysowanie linii na skalowanej długości od punktu odniesienia przez oryginalny wierzchołek, przy czym koniec linii staje się skalowanym wierzchołkiem.
Kąt i obrót istnieje, ponieważ łatwiej jest obliczyć położenie końca linii wzdłuż jednej osi, a następnie obrócić go „na miejsce”.

Zły geniusz
źródło
1
Przetestowałem ten skrypt i działa dobrze. Jesteś cholernym geniuszem! =) Bardzo dziękuję. Nie pozostawiam tego pytania bez odpowiedzi, aby więcej osób zobaczyło je w „pytaniach przyszłościowych”.
Pan Che
1
Przekonałem się, że kiedy próbuję przetworzyć wielokąt z dziurą - powoduje to awarię skryptu w linii bdist = refgeom.distanceTo(apnt). Czy możesz to przetestować i naprawić?
Mr. Che
@ Mr.Che Ups, zapomniałem, że ArcPy zwraca wszystkie pierścienie części wielokąta w tej samej tablicy. Pierścienie są oddzielone punktami zerowymi. To łatwa poprawka, zobacz edycję.
Zły geniusz
Witaj. Czy to możliwe, aby uzyskać małe wyjaśnienie działania skryptu, jestem kiepski w kodowaniu i nie otrzymuję wszystkich wierszy, więc nie działa dla mnie, proszę?
Piotr
@ Peter Pewnie, dodałem krótkie wyjaśnienie tego, co się dzieje. To nie ma być samodzielny skrypt, ale coś, co można zintegrować ze swoim własnym skryptem. Dolny fragment kodu pokazuje przykład, w jaki sposób można go użyć.
Zły geniusz