¿Existe la herramienta ArcPy para cambiar el tamaño de polígonos como la herramienta Escala de la barra de herramientas Edición avanzada en ArcMap?

17

Estoy escribiendo un script de Python para ArcGIS 10.3. Lo sé Scale toolen la interfaz de ArcGIS pero no puedo encontrar ese comando arcpy. ¿Existe?

Como puede ver en la imagen, el Scale tooltrabajo es diferente a Buffer tool: cambia la forma del polígono original. Entonces la pregunta es:

¿Puedo usar Scale tool(disponible desde la interfaz de ArcGIS) usando arcpy?

ingrese la descripción de la imagen aquí

Señor che
fuente
2
¿Qué hay de amortiguar y eliminar el antiguo polígono? El buffer se puede usar con valores positivos y negativos.
Farid Cheraghi
La pregunta es sobre la herramienta arcpy existente, no sobre cómo cambiar el tamaño de un polígono.
Sr. Che
Su título, pregunta y comentario parecen estar en desacuerdo entre sí. Si las preguntas duplicadas proporcionadas no responden a su pregunta, ¿podría editar su pregunta para aclarar lo que busca?
Aaron
1
La herramienta @ Mr.Che Buffer se puede usar en scripts de python a través de arcpy.Buffer_analysis (...)
Farid Cheraghi
Esto es super! ¿Cómo puedo actualizar cada clase de entidad por un número en una tabla en lugar de escalar todas las entidades por 0.5 por ejemplo? Gracias
user1655130

Respuestas:

27

No conozco nada en la API de arcpy que haga el escalado por usted, pero escribir una función para hacerlo sería relativamente simple.

El siguiente código escala las características 2D y no tiene en cuenta los valores 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)

Puede llamarlo con un objeto de geometría, un factor de escala (1 = mismo tamaño, 0.5 = medio tamaño, 5 = 5 veces más grande, etc.) y un punto de referencia opcional:

scale_geom(some_geom, 1.5)

Use esto junto con los cursores para escalar una clase de entidad completa, suponiendo que la clase de entidad de destino ya exista:

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

editar: aquí hay un ejemplo usando una aproximación de su geometría de prueba, por 0.5 y 5 veces: ingrese la descripción de la imagen aquí

¡También probado con polígonos de múltiples anillos (agujeros)! ingrese la descripción de la imagen aquí

Una explicación, según lo solicitado:

scale_geomtoma un solo polígono y recorre cada vértice, midiendo la distancia desde él hasta un punto de referencia (por defecto, el centroide del polígono).
Esa distancia es luego escalada por la escala dada para crear el nuevo vértice 'escalado'.

El escalado se realiza esencialmente dibujando una línea en la longitud escalada desde el punto de referencia a través del vértice original, con el final de la línea convirtiéndose en el vértice escalado.
El ángulo y la rotación están ahí porque es más sencillo calcular la posición del final de la línea a lo largo de un solo eje y luego rotarlo 'en su lugar'.

Genio malvado
fuente
1
Probé este script y funciona bien. Eres un maldito genio! =) Muchas gracias. Dejaré esta pregunta sin recompensar para que más personas la vean en las "preguntas futuras".
Sr. Che el
1
Descubrí que cuando intento procesar un polígono con un agujero, se produce un bloqueo del script en la línea bdist = refgeom.distanceTo(apnt). ¿Puedes probar y arreglar eso?
Sr. Che
@ Mr.Che Vaya, olvidé que ArcPy devuelve todos los anillos de una parte de polígono en la misma matriz. Los anillos están separados por puntos nulos. Es una solución fácil, vea la edición.
Evil Genius
Hola. ¿Es posible obtener una pequeña explicación de cómo funciona el script, soy malo en la codificación y no obtengo todas las líneas, por lo que no funciona para mí, por favor?
Peter
@peter Claro, he agregado una breve explicación de lo que está sucediendo. No está destinado a ser un script independiente, sino algo que se integrará en un script propio. El fragmento de código inferior muestra un ejemplo de cómo podría usarse.
Evil Genius