10 votos

Pautas para usar ArcObjects desde Python

Por el momento, ¿Cómo puedo acceder a ArcObjects desde Python? es mi más leer y se hace referencia a Q&a sobre los SIG de Intercambio de la Pila. A pesar de que el éxito, es probablemente uno de mis puntos débiles cuando se trata de uso real. Una gran parte de esa pobre mostrando deriva de mi poca habilidad para leer y comprender la ArcObjects docs.

Así que, para cualquier tarea ¿cuáles son algunas de las pautas para traducir .net/c++/java/... docs y ejemplos en sus python equivalentes? (que el lenguaje es el mejor sitio para trabajar a partir de ese asunto?) y ¿cuál es el mejor índice de aterrizaje o página de inicio? qué cosas debería centrarse en, y es probable que, al menos, tan importante, de lo que puede ser libremente ignorado?

Suponga que su audiencia es al menos algo de python alfabetizados y analfabetos en el desarrollo de otros idiomas. Caminar con nosotros a través de un pequeño ejercicio de codificación, desde la idea inicial y la investigación para el trabajo de python resultados.

9voto

steveax Puntos 316

Yo no soy muy fuerte en esta zona, pero he modificado los Fragmentos de módulo y han hecho un par de contenedores para muy simples tareas. Tengo un ejemplo de la adición de elementos de la línea. En el ejemplo que bajo el principal bloque de forma un triángulo a la vista de diseño justo fuera del documento.

Yo uso este script en conjunción con otro y arcpy de búsqueda, los cursores para hacer gráficos tablas en el diseño de líneas individuales y elementos de texto, pero que rápidamente se mueve lejos de la "simple" ejemplo. El siguiente código es bastante sencillo y utiliza una versión modificada de los fragmentos:

from snippets import *
def add_line(pApp=None, name='Line', x=None, y=None, end_x=None, end_y=None,
             x_len=0, y_len=0, anchor=0, view='layout'):
    '''adds a line to an ArcMap Document

    Required:
    pApp -- reference to either open ArcMap document or path on disk
    name -- name of line element

    Optional:
    x -- start x coordinate, if none, middle of the extent will be used (data view)
    y -- start y coordinate, if none, middle of the extent will be used (data view)
    end_x -- end x coordinate, if making straight lines use x_len
    end_y -- end y coordinate, if making straight lines use y_len
    x_len -- length of line in east/west direction
    y_len -- length of line in north/south direction
    anchor -- anchor point for line element
    view -- choose view for text element (layout|data)

        Anchor Points:
        esriTopLeftCorner   0   Anchor to the top left corner.
        esriTopMidPoint     1   Anchor to the top mid point.
        esriTopRightCorner  2   Anchor to the top right corner.
        esriLeftMidPoint    3   Anchor to the left mid point.
        esriCenterPoint     4   Anchor to the center point.
        esriRightMidPoint   5   Anchor to the right mid point.
        esriBottomLeftCorner    6   Anchor to the bottom left corner.
        esriBottomMidPoint  7   Anchor to the bottom mid point.
        esriBottomRightCorner   8   Anchor to the botton right corner.
    '''
    GetDesktopModules()
    import comtypes.gen.esriFramework as esriFramework
    import comtypes.gen.esriArcMapUI as esriArcMapUI
    import comtypes.gen.esriSystem as esriSystem
    import comtypes.gen.esriGeometry as esriGeometry
    import comtypes.gen.esriCarto as esriCarto
    import comtypes.gen.esriDisplay as esriDisplay
    import comtypes.gen.stdole as stdole

    # set mxd
    if not pApp:
        pApp = GetApp()
    pDoc = pApp.Document
    pMxDoc = CType(pDoc, esriArcMapUI.IMxDocument)
    pMap = pMxDoc.FocusMap
    pMapL = pMap
    if view.lower() == 'layout':
        pMapL = pMxDoc.PageLayout
    pAV = CType(pMapL, esriCarto.IActiveView)
    pSD = pAV.ScreenDisplay

    # set coords for elment
    pFact = CType(pApp, esriFramework.IObjectFactory)
    if view.lower() == 'data':
        pEnv = pAV.Extent
        if x == None:
            x = (pEnv.XMin + pEnv.XMax) / 2
        if y == None:
            y = (pEnv.YMin + pEnv.YMax) / 2
    else:
        # default layout position, move off page
        if x == None: x = -4
        if y == None: y = 4

    # from point
    pUnk_pt = pFact.Create(CLSID(esriGeometry.Point))
    pPt = CType(pUnk_pt, esriGeometry.IPoint)
    pPt.PutCoords(x, y)

    # to point
    pUnk_pt2 = pFact.Create(CLSID(esriGeometry.Point))
    pPt2 = CType(pUnk_pt2, esriGeometry.IPoint)
    if x_len or y_len:
        pPt2.PutCoords(x + x_len, y + y_len)
    elif end_x or end_y:
        pPt2.PutCoords(end_x, end_y)

    # line (from point - to point)
    pUnk_line = pFact.Create(CLSID(esriGeometry.Polyline))
    pLg = CType(pUnk_line, esriGeometry.IPolyline)
    pLg.FromPoint = pPt
    pLg.ToPoint = pPt2

    # preset color according to RGB values
    pUnk_color = pFact.Create(CLSID(esriDisplay.RgbColor))
    pColor = CType(pUnk_color, esriDisplay.IRgbColor)
    pColor.Red, pColor.Green, pColor.Blue = (0,0,0) #black line

    # set line properties
    pUnk_line = pFact.Create(CLSID(esriDisplay.SimpleLineSymbol))
    pLineSymbol = CType(pUnk_line, esriDisplay.ISimpleLineSymbol)
    pLineSymbol.Color = pColor

    # create the actual element
    pUnk_elm = pFact.Create(CLSID(esriCarto.LineElement))
    pLineElement = CType(pUnk_elm, esriCarto.ILineElement)
    pLineElement.Symbol = pLineSymbol
    pElement = CType(pLineElement, esriCarto.IElement)

    # elm properties
    pElmProp = CType(pElement, esriCarto.IElementProperties3)
    pElmProp.Name = name
    pElmProp.AnchorPoint = esriCarto.esriAnchorPointEnum(anchor)
    pElement.Geometry = pLg

    # add to map
    pGC = CType(pMapL, esriCarto.IGraphicsContainer)
    pGC.AddElement(pElement, 0)
    pGCSel = CType(pMapL, esriCarto.IGraphicsContainerSelect)
    pGCSel.SelectElement(pElement)
    iOpt = esriCarto.esriViewGraphics + \
    esriCarto.esriViewGraphicSelection
    pAV.PartialRefresh(iOpt, None, None)
    return pElement

if __name__ == '__main__':

    # testing (make a triangle)
    add_line(name='hypot', end_x=-2, end_y=2, anchor=3)
    add_line(name='vertLine', y_len=-2, anchor=1)
    add_line(name='bottom', y=2, end_x=-2, end_y=2)

enter image description here

Editar:

@matt wilkie

Como para deducir de las importaciones, que es donde se han de mirar por encima de la de ArcObjects Diagramas de Modelo o ver qué espacio de nombres de una determinada Clase o Interfaz que se llama en el .RED de ayuda del SDK de google docs. En algunos casos de más de un espacio de nombres puede ser utilizado debido a la herencia.

No soy experto en ArcObjects, por lo que normalmente me toma un tiempo para averiguar cuándo lanzar cosas con CType(). La mayor parte de este, que he recogido de muestras en línea. Además, la sintaxis de la VB.NET ejemplos parece estar más cerca de lo que usted hace en Python, pero el C# ejemplos más sentido para mí en términos de legibilidad (si eso tiene algún sentido). Pero, como una regla de oro que generalmente follwo estos pasos:

  1. Crear una variable para un nuevo objeto COM (generalmente de una clase) crear una instancia de un objeto
  2. Utilizar CType para lanzar el objeto COM para una interfaz(s) para permitir el acceso a los métodos y proerties. CType se también devolver el comtypes Puntero de Interfaz a través de la QueryInterface(). Una vez que el puntero se devuelve, entonces puede interactuar con sus propiedades y métodos.

No estoy seguro si estoy usando la terminología adecuada o no...soy principalmente un desarrollo en Python que "salpica" en algunos de ArcObjects...yo sólo he tocado la punta del iceberg.

Además, esta función auxiliar se los carga a todos los ArcObjects Objeto de Bibliotecas.olb):

def load_all():
    '''loads all object libraries'''
    from comtypes.client import GetModule
    mods = glob.glob(os.path.join(GetLibPath(), '*.olb'))
    for mod in mods:
        GetModule(mod)
    return


def GetLibPath():
    '''Reference to com directory which houses ArcObjects
    Ojbect Libraries (*.OLB)'''
    return glob.glob(os.path.join(arcpy.GetInstallInfo()['InstallDir'], 'com'))[0]

7voto

Flinkman Puntos 4821

En otro, ligeramente diferente pero relacionado, post me dio una respuesta que puede ser de interés para los usuarios de python tratando de envolver su cabeza alrededor de la Esri ArcObjects ayuda docs..

Me llegó desde el otro lado: yo ya sabía de ArcObjects mucho (mucho, mucho) antes de que yo siquiera había oído hablar de python y gracias a posts como estos soy capaz de incluir algunos críticos de ArcObjects en el fácil de secuencias de comandos de python (ver este post para ver un ejemplo). Recuerdo la frustración de tratar de entender la herencia, métodos y propiedades; dilemas como el que tengo X que es algo relacionado con a Y... entonces, ¿cómo puedo llegar de X a Y. (Método)?

La respuesta es buscar en las Coclases que implementan la interfaz (ver texto completo aquí).. para un ejemplo básico, si quiero ver si una capa tiene una definición de la consulta, y si es así ¿qué es lo:

En C#:

ILayer pLayer = pMap.get_Layer(LayerIndex);
IFeatureLayer pFtLayer = pLayer as IFeatureLayer; // also written pFtLayer = (IFeatureLayer) pLayer
IFeatureLayerDefinition pFtLayDef = (IFeatureLayerDefinition)pFtLayer; // also works as pFtLayDef = pFtLayer as IFeatureLayerDefinition;
if (pFtLayDef.DefinitionExpression.Length == 0)
    Console.WriteLine("No definition query");
else
    Console.WriteLine("Query is " + pFtLayDef.DefinitionExpression);

En lugar de ctype (que es prominente en VB) C# utiliza () o as para la fundición, por ejemplo IObject x = (IObject)y; es (básicamente) de la misma como IObject x = y as IObject; que serían dim x as IObject = ctype(y,IObject) en VB.

Puedo decir que tengo un IFeatureLayer para llegar a IFeatureLayerDefinitionporque: enter image description here

Y cuando usted lea la ayuda de doc para IFeatureLayer ver: enter image description here

Lo que indica que es seguro ir ILayer->IFeatureLayer->IFeatureLayerDef, siempre que el ILayer es del tipo FeatureLayer (o cualquier otra de las Coclases).

Así que ¿qué pasa con el yo y no yo? El yo medio de la interfaz, es lo que hace el trabajo, sin un yo es una Coclase (un tipo), así que cualquier cosa que usted desea utilizar realmente debería comenzar con un yo y si vas a crear una nueva, o comprobar el tipo, a continuación, saltar a la I. Una interfaz puede tener muchas Coclases y una Coclase puede apoyar muchas de las interfaces, pero es el interfaz que realmente hace el trabajo.

En python:

# I'm assuming arcpy is already imported and comtypes installed
from comtypes.client import GetModule, CreateObject
mC = GetModule(r'C:\Your path\Desktop10.1\com\esriCarto.olb')
mU = GetModule(r'C:\Your path\Desktop10.1\com\esriArcMapUI.olb')
mF = GetModule(r"C:\Your path\Desktop10.1\com\esriFramework.olb")

import comtypes.gen.esriCarto as esriCarto
import comtypes.gen.esriFramework as esriFramework
import comtypes.gen.esriArcMapUI as esriArcMapUI

app = CreateObject(mF.AppROT, interface=mF.IAppROT) # a reference to the ArcMap application
pDoc = ctype(app.Item(0).Document,mU.IMxDocument)   # a reference to the current document
pMap = pDoc.FocusMap # the currently active map
pLayer = pMap.get_layer(LayerIndex)
pFtLayer = ctype(pLayer,esriCarto.IFeatureLayer)
pFtLayDef = ctype(pFtLayer,esriCarto.IFeatureLayerDefinition)
if len(pFtLayDef.DefinitionExpression) == 0:
    print("No definition expression")
else:
    print("Query is " + pFtLayDef.DefinitionExpression)

Este ejemplo hace poco más de la C en el que se encuentra su camino a la aplicación actual, que sólo estaría disponible en la ventana de python o un complemento, si se trató de ejecutar desde la línea de comandos de la aplicación es Nulo y la secuencia de comandos sería después del accidente con una excepción de referencia nula.

i-Ciencias.com

I-Ciencias es una comunidad de estudiantes y amantes de la ciencia en la que puedes resolver tus problemas y dudas.
Puedes consultar las preguntas de otros usuarios, hacer tus propias preguntas o resolver las de los demás.

Powered by:

X