Déplacer / compenser des emplacements de points à l'aide d'ArcPy ou de ModelBuilder?

10

J'ai un certain nombre de couches CAD non géoréférencées (voir cette question ) qui ont des fonctionnalités d'annotation de texte. J'ai créé un modèle pour convertir le texte en points, mais après avoir converti l'annotation en une classe de points, je constate que les points d'ancrage du texte CAD ne coïncident pas avec le centre du texte CAD (qui est l'endroit où les points appartiennent).

Par conséquent, je voudrais programmer (en utilisant ArcPy ou ModelBuilder) [déplacer] une entité par rapport à son emplacement actuel (delta x, y) en utilisant une valeur X, Y mesurée que je fournirai.

Cela me permettrait de ramener les points SIG à leur place, au lieu du point d'ancrage CAD décalé.

Comment puis-je accomplir cette tâche?


@PolyGeo a donné une excellente réponse en utilisant SHAPE @ XY IN 10.1, mais actuellement j'utilise 10.0. Des idées 10,0?

RyanKDalton
la source

Réponses:

17

Ce code doit le faire à l'aide du jeton SHAPE @ XY fourni avec arcpy.da.UpdateCursor dans ArcGIS 10.1.

import arcpy
# Set some variables
fc = r"C:\temp\test.gdb\testFC"
fc2 = r"C:\temp\test.gdb\testFCcopy"
xOffset = 0.001
yOffset = 0.001
# Code to make a copy which will have its coordinates moved (and can be compared with original)
if arcpy.Exists(fc2):
    arcpy.Delete_management(fc2)
arcpy.Copy_management(fc,fc2)
# Perform the move
with arcpy.da.UpdateCursor(fc2, ["SHAPE@XY"]) as cursor:
    for row in cursor:
        cursor.updateRow([[row[0][0] + xOffset,row[0][1] + yOffset]])

Le modèle de codage utilisé ici provient d' ArcPy Café .

PolyGeo
la source
Pouah! Il m'a fallu jusqu'à ce matin pour réaliser que SHAPE @ XY n'est disponible qu'en 10.1 et que mon entreprise utilise toujours la 10.0. C'est une excellente réponse (à l'avenir), mais je vais attendre et voir si quelqu'un a des suggestions pour 10.0. Merci!
RyanKDalton
Plus d'informations sur un processus similaire pour quiconque lit ceci. Toujours 10.1. arcpy.wordpress.com/2013/06/07/disperse-overlapping-points
theJones
Est-ce que cela définit les valeurs n'importe où? Jamais utilisé le UpdateCursor comme ça auparavant. Habituellement, je fais + = puis je mets à jour la ligne. Sinon, la seule chose que je fais différemment dans ma version est que UpdateCursor utilise ['SHAPE @ X', 'SHAPE @ Y'] afin que vous puissiez y accéder en tant que ligne [0] et ligne [1] au lieu d'avoir à faire la ligne [0 ] [0] et la ligne [0] [1]. Pensez que c'est juste un peu plus facile à lire pour moi.
eseglem
Oui, c'est une façon valide de mettre à jour les lignes. En fait, je n'avais jamais vu une valeur passée dans updateRow () jusqu'à il y a quelques semaines. C'était en fait un exemple de mise à jour de la géométrie.
Paul
Merci beaucoup pour votre réponse PolyGeo! J'étais en fait assez impressionné que le code fonctionne sans modifications. J'utilise ArcGIS Desktop 10.6
Rie Mino
8

Je remercie @ artwork21 de m'avoir conduit à ma solution finale. En fait, j'ai trouvé un script presque complet dans l'article d'aide en ligne d'ArcGIS 10.0 intitulé « Exemples de calcul de champ », répertorié sous la sous-catégorie « Échantillons de code - géométrie » et « Pour une classe d'entités points, déplacez la coordonnée x de chaque point de 100 »

Le script final que j'ai utilisé dans l'outil "Calculer le champ" de ModelBuilder était:

Expression:

shiftXYCoordinates(!SHAPE!,%ShiftX%,%ShiftY%)

ShiftX et ShiftY sont des variables (en tant que paramètres) définies sur le canevas ModelBuilder.

Type d'expression:

PYTHON_9.3

Bloc de code:

def shiftXYCoordinates(shape,x_shift,y_shift):
   point = shape.getPart(0)
   point.X += float(x_shift)
   point.Y += float(y_shift)
   return point

Étant donné que tous les modèles fonctionnent sur un ensemble sélectionné, vous devriez également pouvoir le créer en tant qu'outil générique qui fonctionnera en conjonction avec d'autres modèles / outils dans d'autres sessions de création de modèles. Le modèle très simple que j'ai créé (en tant que "plugin" vers d'autres modèles pour décaler les valeurs de coordonnées) ressemble à ceci. De cette façon, je peux contrôler le décalage sur une base d'ensemble de sélection (comme défini dans d'autres modèles):

Modèle ShiftXY

Cela a fonctionné comme un charme, merci à tous pour votre contribution!

RyanKDalton
la source
est-il possible de décaler l'entité par la valeur à l'intérieur du tableau, stockée dans la colonne?
Losbaltica
1
Ça devrait être. Attribuez simplement les paramètres ShiftX et ShiftY aux colonnes appropriées.
RyanKDalton
Je suis confus par ce que vous passez ici par "forme". Pouvez vous m'aider s'il vous plait?
jbchurchill
L '"Expression" montre les paramètres qui sont passés à la fonction de bloc de code appelée shiftXYCoordinates (). Le premier paramètre est donc! SHAPE !, qui est le champ de forme du calque.
RyanKDalton
5

Vous pouvez également utiliser ce script de calculatrice de champ pour déplacer les emplacements d'entités:

def XYsetVALUE( shape, X_value, Y_value): 
  myMoveX = 0.001
  myMoveY = 0.001
  point = shape.getPart(0) 
  point.X = X_value + myMoveX
  point.Y = Y_value + myMoveY
  return point 

XYsetVALUE (! SHAPE !,! X_COORD !,! Y_COORD!)

Vous pouvez inclure une méthode de calcul de champ supplémentaire dans votre modèle à l'aide de la fonction ci-dessus.

oeuvre21
la source
C'est une façon intéressante de le faire, je ne savais pas vraiment que vous pouviez calculer sur le champ de forme. Cela peut en fait être le moyen le plus simple de le faire s'il s'agit d'un décalage défini pour tous les points. Il serait probablement plus rapide de faire point.X + = myMoveX et point.Y + = myMoveY au lieu d'avoir besoin de passer les coordonnées X et Y pour cela.
eseglem
5

J'ai adapté la solution pour déplacer / décaler des points dans une certaine direction (angle) et une distance donnée.

Ressemble à:

def shiftXYCoordinates(shape,angle,distance):
point = shape.getPart(0)
point.Y += distance * math.cos(math.radians(angle))
point.X += distance * math.sin(math.radians(angle))
return point

et être appelé comme shiftXYCoordinates (! SHAPE !,! Angle!, 5000), si vous avez un "angle" de champ pour vos entités ponctuelles (ou avec une constante bien sûr). L'angle doit être donné en degrés décimaux. 0 se déplacera "vers le haut", 90 "vers la droite", etc.

Assurez-vous également de sélectionner le nom du champ «Forme» avant de lancer :)

(Solution testée dans ArcMap 10.0 SP5)

kgl
la source
4

Comme vous pouvez le voir, c'est beaucoup plus facile dans 10.1 lorsque vous avez accès aux jetons de curseur.

import arcpy
# Code to move features in copy of same dataset
fc = r"C:\temp\test.gdb\testFC"
fc2 = r"C:\temp\test.gdb\testFCcopy"
xOffset = 0.001
yOffset = 0.001
if arcpy.Exists(fc2):
    arcpy.Delete_management(fc2)
arcpy.Copy_management(fc, fc2)

shape = arcpy.Describe(fc2).ShapeFieldName

cursor = arcpy.UpdateCursor(fc2)
for row in cursor:    
    point = row.getValue(shape).getPart()
    row.setValue(shape, arcpy.Point(point.X + xOffset, point.Y + yOffset))
    cursor.updateRow(row) 

del point, row, cursor
Paul
la source
2

Cela fonctionne pour 10.0:

# Featureclass here
FC = r'featureclass'

fcount = 0
shapefield = arcpy.Describe(FC).shapeFieldName
featureUpdate = arcpy.UpdateCursor(FC)
for f in featureUpdate:
    # Hard coded shifts but easy enough to set up a lookup function if needed
    sLon = 0.001
    sLat = 0.001
    # Optional but I like to count to see where it is at in the process
    if fcount % 1000 == 0:
        print('Updating feature %s...' %(fcount))
    # Get the original value
    cF = f.getValue(shapefield)
    cPNT = cF.getPart()
    # Create a new point with the shifted value
    sPNT = arcpy.Point(cPNT.X - sLon, cPNT.Y - sLAT)
    # Set the shapefield to the new point and update feature
    f.setValue(shapefield, sPNT)
    featureUpdate.updateRow(f)
    fcount += 1
del featureUpdate
eseglem
la source