Bearbeiten von Endpunkten in Polylinien mit ArcPy?

8

Ich versuche, in Python mit ArcGIS 10 ein Tool zum Einrasten von Polylinienendpunkten zu erstellen. Mithilfe eines Suchcursors habe ich die Werte in ein Array von Linienobjekten eingelesen (die die Feature-ID der Linie und zwei "EndPoint" -Objekte enthalten - first und last - die jeweils die X- und Y-Koordinate enthalten), dann verarbeiten Sie eine Dateninterpolation der Punkte, um allen Punkten ihre korrekten Werte zu geben.

Bisher funktioniert dieser Teil perfekt. Wenn ich jedoch versuche, zurück zu gehen und das Shapefile zu bearbeiten, kann ich die Daten sehen, die ich ändere, aber ich kann sie scheinbar nicht bearbeiten.

Hier ist der Code zum Aktualisieren der Felder:

# --------------------------
#
# 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

Meine Anzeige besteht aus Aussagen wie diesen:

Ändern Sie: -105.512166832 in -105.699533165 Jetzt lautet: -105.512166832

Aus irgendeinem Grund werden die Zeilen nicht aktualisiert. Und für mein Leben kann ich kein Tutorial oder Anweisungen zum Bearbeiten eines bestimmten Punkts in einer Polylinie finden. Ich kann nur herausfinden, wie ein Punkt als Feld in einem Punkt-Shapefile bearbeitet wird.

Hat jemand irgendwelche Ideen?

Kivak Wolf
quelle
1
Haben Sie nur eine ArcView-Lizenz? Wenn Sie über ArcEditor / ArcInfo verfügen, was möchten Sie erreichen, indem Sie ein eigenes Snap-Tool erstellen, das mit dem SNAP-Geoverarbeitungswerkzeug von Arc10 nicht ausgeführt werden kann (ArcToolbox> Bearbeitungswerkzeuge)? ( help.arcgis.com/de/arcgisdesktop/10.0/help/index.html#//… )
RyanKDalton
Es ist möglich, dass es einen anderen Weg gibt, aber ich versuche zu verstehen, wie man die Koordinaten manipuliert, ob das Werkzeug vollständig original ist oder nicht. Es ist so viel mehr Erfahrung als für Funktionalität.
Kivak Wolf

Antworten:

6

Leider können Sie der vorhandenen Geometrie eines Features keine neuen Werte direkt zuweisen. Stattdessen müssen Sie ein neues Geometrieobjekt erstellen und das Formfeld des Features mit diesem neuen Objekt aktualisieren. Glücklicherweise haben die Array-Objekte eine replaceMethode. Anstatt zu versuchen, die X-Koordinate des Punkts innerhalb des Arrays direkt zu ändern, müssen Sie:

  • Erstellen Sie ein neues arcpy.PointObjekt mit den richtigen Koordinaten (möglicherweise haben Sie dies bereits getan).
  • Ruft eine Kopie des Array-Objekts ab, das im Feld Form der Zeile gespeichert ist
  • Verwenden Sie die replaceMethode, um den gewünschten Punkt in Ihrem Array mit Ihrem geänderten Punkt festzulegen
  • Erstellen Sie mit diesem Array ein neues Polylinienobjekt
  • Verwenden Sie die setValueMethode des Zeilenobjekts , um das Feld Form mit Ihrer neuen, korrekten Polylinie zu aktualisieren
  • Verwenden Sie die updateRowMethode des Cursorobjekts, um die geänderte Zeile in das Dataset einzufügen.

Konkret:

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)

Beachten Sie, dass die replaceMethode einen Index und einen Wert verwendet. Leider akzeptiert es zB -1 nicht als Index für den letzten Punkt im Array. Sie können jedoch sagen my_array[my_array.count].

Es sieht so aus, als würden Sie die X-Koordinaten an einer anderen Stelle vorberechnen und später abrufen. Wenn dies der Fall ist, würde ich wahrscheinlich das ganze Schwein gehen und neue Polylinienobjekte mit den richtigen Punkten für jede Linie erstellen, während Sie die richtigen Koordinaten berechnen. Dies wird wahrscheinlich einfacher und sauberer sein. Auf diese Weise könnte Ihr Code eher so sein

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

Was zumindest für mich etwas klarer ist ... aber das ist stilistisch!

Bearbeiten, um hinzuzufügen:

Ich konnte das nicht in einen Kommentar einfügen. Ohne Ihren Code zu sehen, ist es schwer zu sagen, wo er umfallen könnte. Hier ist ein vollständig getestetes Skript, das für mich funktioniert. Hoffentlich dient es als Referenz. Beachten Sie, dass ich hier die neue Geometrie direkt aus der alten berechne, anstatt zwei Durchgänge durchzuführen. Dies kann möglich sein oder auch nicht, je nachdem, wie Sie Ihre Fangpositionsberechnungen durchführen. Auch dieses Mal konstruiere ich ein brandneues Array basierend auf dem alten, anstatt die replaceMethode zu verwenden, falls dies notwendig ist.

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

Hoffentlich hilft das, es aufzuklären.

ThomM
quelle
Ich hatte dieses sinkende Gefühl, das der Fall sein könnte. Vielen Dank für die Erklärung, wie es geht! Ich denke, ich werde einfach die gesamten Polylinien erstellen, wie Sie gesagt haben. Auf diese Weise habe ich mehr Kontrolle darüber, sollte ich zurückgehen und etwas anderes anpassen wollen.
Kivak Wolf
Nun, leider habe ich es nicht zum Laufen gebracht. Etwas sehr Seltsames ist los. Wenn ich "ary = r.getValue (" SHAPE "). GetPart (0)" verwende und dann sofort eine Polylinie aus ary erstelle und den Wert festlege, sieht das Shapefile völlig anders aus. Das sollte doch nicht passieren, oder?
Kivak Wolf
Es ist schwer zu sagen, was genau falsch ist. Ich habe die Antwort mit einer vollständigeren Lösung aktualisiert, falls es hilft. Eigentlich - es hört sich so an, als würden Sie das Array erstellen und dann den Punkt ändern. Stattdessen sollten Sie einen neuen Punkt erstellen und dann das Array so ändern, dass es diesen Punkt enthält (oder ein neues Array mit diesem Punkt wie oben erstellen).
ThomM
ThomM: Danke für die erweiterte Erklärung! Ich weiß das wirklich zu schätzen! Wie ich gestern herausgefunden habe, erstelle ich arcpy.Array (), arcpy.Point () und verwende die arcpy.Ployline () -Klasse korrekt. Es scheint jedoch, dass die eigentliche Programmierung des Klassenkonstruktors arcpy.Ployline () einen Fehler enthält. Ich habe einen Fehlerbericht eingereicht, aber es scheint, dass der Konstruktor für arcpy.Polyline () arcpy.Point () mit ähnlichen, aber immer noch eindeutigen Werten "wegwirft" oder ignoriert. Während ich dachte, mein Problem sei das Unverständnis darüber, wie es funktioniert, scheint es, dass es ein Fehler sein könnte.
Kivak Wolf