Existe a ferramenta ArcPy para redimensionamento de polígonos como a ferramenta Escala da barra de ferramentas Edição Avançada no ArcMap?

17

Estou escrevendo um script python para o ArcGIS 10.3. Conheço a Scale toolinterface do ArcGIS, mas não consigo encontrar esse comando arcpy. Isso existe?

Como você pode ver na figura, o Scale tooltrabalho é diferente de Buffer tool- ele muda a forma do polígono original. Então a questão é:

Posso usar Scale tool(disponível na interface do ArcGIS) usando o arcpy?

insira a descrição da imagem aqui

Mr. Che
fonte
2
Que tal armazenar em buffer e remover o polígono antigo !? buffer pode ser usado com valores positivos e negativos!
Farid Cheraghi
A questão é sobre a ferramenta arcpy existente, não sobre como redimensionar um polígono.
Che Che
Seu título, pergunta e comentário parecem estar em desacordo. Se as perguntas duplicadas fornecidas não responderem à sua pergunta, você poderia editá-la para esclarecer o que está buscando?
Aaron
1
@ Ferramenta Tampão Mr.Che pode ser usado em scripts python através arcpy.Buffer_analysis (...)
Farid Cheraghi
Isso é super! Como posso atualizar todas as classes de recursos por um número em uma tabela, em vez de dimensionar todos os recursos em 0,5, por exemplo? Graças
user1655130

Respostas:

27

Não estou ciente de nada na API do arcpy que fará o dimensionamento para você, mas escrever uma função para fazer isso seria relativamente simples.

O código abaixo faz o dimensionamento para recursos 2D e não leva em consideração os valores M ou 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)

Você pode chamá-lo com um objeto de geometria, um fator de escala (1 = mesmo tamanho, 0,5 = metade do tamanho, 5 = 5 vezes maior etc.) e um ponto de referência opcional:

scale_geom(some_geom, 1.5)

Use isso em conjunto com os cursores para dimensionar uma classe de recurso inteira, assumindo que a classe de recurso de destino já 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

edit: veja um exemplo usando uma aproximação da sua geometria de teste, por 0,5 e 5 vezes: insira a descrição da imagem aqui

Também testado com polígonos com vários anéis (orifícios)! insira a descrição da imagem aqui

Uma explicação, conforme solicitado:

scale_geompega um único polígono e percorre cada vértice, medindo a distância até um ponto de referência (por padrão, o centróide do polígono).
Essa distância é então dimensionada pela escala fornecida para criar o novo vértice 'dimensionado'.

O dimensionamento é feito basicamente desenhando uma linha no comprimento dimensionado do ponto de referência até o vértice original, com o final da linha se tornando o vértice dimensionado.
O material de ângulo e rotação existe porque é mais direto calcular a posição do final da linha ao longo de um único eixo e depois girá-lo 'no lugar'.

Gênio do mal
fonte
1
Eu testei esse script e funciona bem. Você é maldito gênio! =) Muito obrigado. Deixarei essa questão de lado, para que mais pessoas a vejam nas "perguntas futuras".
Che Che
1
Descobri que quando tento processar um polígono com um orifício - isso resulta em uma falha de script na linha bdist = refgeom.distanceTo(apnt). Você pode testar e corrigir isso?
Che Che
@ Mr.Che Opa, esqueci que o ArcPy retorna todos os anéis de uma parte de polígono na mesma matriz. Os anéis são separados por pontos nulos. É uma solução fácil, consulte a edição.
Mal Genius
Olá. É possível obter uma pequena explicação de como o script funciona, eu sou péssimo em codificação e não entendo todas as linhas, portanto não está funcionando para mim, por favor?
peter
@ Peter Claro, eu adicionei uma breve explicação do que está acontecendo. Não é para ser um script independente, mas para ser integrado a um script próprio. O trecho de código inferior mostra um exemplo de como ele pode ser usado.
Evil Genius