Editando pontos finais na polilinha usando o ArcPy?

8

Estou tentando criar uma ferramenta de ajuste de ponto de extremidade de polilinha no Python usando o ArcGIS 10. usando um Cursor de Pesquisa que li nos valores para uma matriz de objetos de linha (que contêm o ID do recurso da linha e dois objetos "EndPoint" - primeiro e last - que contém as coordenadas X e Y de cada um), então processe alguma interpolação de dados dos pontos para dar a todos os pontos seus valores corretos.

Até agora, essa parte funciona perfeitamente. No entanto, quando tento voltar e editar o shapefile, posso ver os dados que estou alterando, mas não consigo editá-los.

Aqui está o código para atualizar os campos:

# --------------------------
#
# Update the file with the new EPs
#
# --------------------------

# Create update cursor
#
rows = arcpy.UpdateCursor(outputDirectory + "\\" + trails_fc + ".shp")

# Enter for loop for each feature/row
#
i = 0
for row in rows:
    # Create the geometry object
    #
    feat = row.getValue(shapefieldname)

    partnum = 0

    if feat.getPart(partnum)[0].X != allLines[i].startEP.x:
        arcpy.AddMessage("Change: " + str(feat.getPart(partnum)[0].X) + " to " + str(allLines[i].startEP.x) )
        feat.getPart(partnum)[0].X = allLines[i].startEP.x

    rows.updateRow(row)

    arcpy.AddMessage("Now is: " + str(feat.getPart(partnum)[0].X))

    i+=1

Minha leitura consiste em declarações como esta:

Alterar: -105.512166832 para -105.699533165 Agora é: -105.512166832

Por algum motivo, as linhas não estão atualizando. E para a minha vida, não consigo encontrar um tutorial ou instruções sobre como editar um ponto específico em uma polilinha. Só consigo encontrar como editar um ponto como um campo em um shapefile de ponto.

Alguém tem alguma ideia?

Kivak Wolf
fonte
1
Você tem apenas uma licença do ArcView? Se você possui o ArcEditor / ArcInfo, o que você está tentando realizar criando sua própria ferramenta de snap que a ferramenta de geoprocessamento SNAP do Arc10 não realizará (ArcToolbox> Ferramentas de edição)? ( help.arcgis.com/en/arcgisdesktop/10.0/help/index.html#//… )
RyanKDalton
É possível que exista outra maneira, mas estou tentando entender como manipular as coordenadas, independentemente de a ferramenta ser ou não completamente original. É tanto mais experiência quanto funcionalidade.
Kivak Wolf

Respostas:

6

Infelizmente, você não pode atribuir novos valores diretamente à geometria existente de um recurso - é necessário criar um novo objeto de geometria e atualizar o campo de forma do recurso com esse novo objeto. Felizmente, os objetos da matriz têm um replacemétodo. Portanto, em vez de tentar modificar diretamente a coordenada X do ponto dentro da matriz, você precisa:

  • Crie um novo arcpy.Pointobjeto com as coordenadas corretas (parece que você já deve ter feito isso)
  • Obter uma cópia do objeto da matriz armazenada no campo Forma da linha
  • Use o replacemétodo para definir o ponto desejado em sua matriz com o ponto modificado
  • Crie um novo objeto Polyline com essa matriz
  • Use o setValuemétodo do objeto de linha para atualizar o campo Shape com sua nova e polilinha correta
  • Use o updateRowmétodo do objeto cursor para inserir a linha alterada no conjunto de dados.

Concretamente:

for r in cur:
    ary = r.getValue("SHAPE").getPart(0)
    ary.replace(0,correct_point_object) # first arg 0 replaces the first point in the line
    newLine = arcpy.Polyline(ary)
    r.setValue("SHAPE",newLine)
    cur.updateRow(r)

Observe que o replacemétodo utiliza um índice e um valor. Infelizmente, ele não aceita, por exemplo, -1 como um índice até o último ponto da matriz. No entanto, você pode dizer my_array[my_array.count].

Parece que você está pré-computando as coordenadas X em outro lugar e as recuperando mais tarde. Se for esse o caso, eu provavelmente faria o trabalho todo e criaria novos objetos Polilinha com os pontos corretos para cada linha enquanto você calcula as coordenadas corretas. Isso provavelmente será mais fácil e limpo. Dessa forma, seu código pode ser mais parecido com

row_num = 0
    for r in cur:
        r.setValue(shapeField,correct_geometry_list[row_num])
        cur.updateRow(r)
        row_num += 1

O que, pelo menos para mim, é um pouco mais claro ... mas isso é estilístico!

Edite para adicionar:

Eu não poderia encaixar isso em um comentário. Sem ver seu código, é difícil dizer onde ele pode estar caindo. Aqui está um script testado completo que funciona para mim. Espero que sirva de referência. Observe que aqui estou calculando a nova geometria diretamente da antiga, em vez de fazer duas passagens; isso pode ou não ser possível, dependendo de como você está fazendo seus cálculos de posição de snap. Desta vez, também estou construindo um novo array baseado no antigo, em vez de usar o replacemétodo, caso necessário.

import arcpy

def offsetPoint(old_point,X_distance,Y_distance):
    """Trivial function to offset a point - replace with what you're
actually doing."""
    new_point = arcpy.Point(old_point.X+X_distance,
                            old_point.Y+Y_distance)
    return new_point

def offsetFirstPointInLine(line_geom,X_distance,Y_distance):
    """Takes a Polyline geometry object and returns a new Polyline with
the first point of the first part offset by the distance given."""
    array = line_geom.getPart(0)
    first_point = array[0]
    new_point = offsetPoint(first_point,X_distance,Y_distance)

    # Build a new array with your new point in the 0th position, and
    # the rest of the points from the old array.
    new_array = arcpy.Array([new_point]+
                            [array.getObject(x) for x in range(1,array.count)])

    # Then make a new Polyline object with that array.
    new_line = arcpy.Polyline(new_array)
    return new_line

fc = r"C:\Users\student\Documents\ArcGIS\Default.gdb\SomeStorms"

cur = arcpy.UpdateCursor(fc)

for r in cur:
    geom = r.getValue("SHAPE")
    r.setValue("SHAPE",offsetFirstPointInLine(geom,-45000,-5000))
    cur.updateRow(r)

del r,cur

Espero que isso ajude a esclarecer.

ThomM
fonte
Tive essa sensação de que poderia ser o caso. Muito obrigado por explicar como fazê-lo! Acho que vou criar as polilinhas inteiras como você disse. Dessa forma, tenho mais controle sobre isso, caso eu queira voltar e ajustar outra coisa.
Kivak Wolf
Infelizmente, não consegui fazer funcionar. Algo muito estranho está acontecendo. Se eu usar "ary = r.getValue (" SHAPE "). GetPart (0)" e criar imediatamente uma polilinha a partir de ary e definir o valor, o shapefile parecerá completamente diferente. Isso não deveria acontecer, deveria?
Kivak Wolf
É difícil dizer exatamente o que há de errado; Atualizei a resposta com uma solução mais completa, caso isso ajude. Na verdade - parece que você está criando a matriz e modificando o ponto; em vez disso, você deve definir um novo ponto e modificar a matriz para incluir esse ponto (ou criar uma nova matriz com esse ponto, como acima).
ThomM 22/11
ThomM: Obrigado pela explicação expandida! Eu realmente gostei disso! Como descobri ontem, estou criando o arcpy.Array (), arcpy.Point () se uso a classe arcpy.Ployline () corretamente. Mas parece que pode haver um erro na programação real do construtor da classe arcpy.Ployline (). Enviei um relatório de bug, mas parece que o construtor do arcpy.Polyline () está 'jogando fora' ou ignorando o arcpy.Point () s com valores semelhantes e ainda únicos. Então, enquanto eu pensava que meu problema era a falta de compreensão de como funciona, parece que pode ser um bug.
Kivak Wolf