Hướng dẫn sử dụng ArcObjects từ Python


10

Cho đến nay, truy cập ArcObjects từ Python? là câu hỏi và trả lời được đọc nhiều nhất của tôi trên Sàn giao dịch xếp chồng GIS. Mặc dù thành công đó, nó có lẽ là một trong những lĩnh vực yếu nhất của tôi khi sử dụng thực tế. Một phần lớn của sự nghèo nàn đó cho thấy xuất phát từ khả năng đọc và hiểu các tài liệu ArcObjects kém của tôi .

Vì vậy, đối với bất kỳ tác vụ nhất định, một số hướng dẫn để dịch .net / c ++ / java / ... tài liệu và ví dụ thành tương đương python của họ là gì? (ngôn ngữ nào là ngôn ngữ tốt nhất để làm việc cho vấn đề đó?) và chỉ mục hoặc trang đích tốt nhất để bắt đầu là gì? những thứ nên được tập trung vào, và có khả năng ít nhất là quan trọng, những gì có thể được tự do bỏ qua?

Giả sử khán giả của bạn ít nhất là một phần trăn biết chữ và không biết chữ trong các ngôn ngữ phát triển khác. Đưa chúng tôi qua một bài tập mã hóa nhỏ, từ ý tưởng ban đầu và nghiên cứu đến kết quả làm việc với trăn.


1
Nó có thể không thêm bất cứ điều gì vào cuộc trò chuyện ở đây nhưng tôi muốn tuyên bố về hồ sơ mà tôi thực sự thích thú khi thấy bộ hướng dẫn này phát triển. Cảm ơn Matt. Tôi đã tìm thấy một bài viết của Darren Wiens tạo MXD từ đầu và điền vào bố cục với các hướng dẫn. Dường như mô-đun đoạn trích của Mark Cederholm thực sự hữu ích / thường được sử dụng trong những nỗ lực này.
Jim

Một ví dụ có thể sử dụng: gis.stackexchange.com/questions/86007/, (tiết lộ: đó là vấn đề tôi đang làm việc, điều đó đã khiến Q. Đánh bại tôi với câu trả lời (được chế tạo tốt), nhận được tất cả tín dụng ! ;-)
matt wilkie

Arcobjects có thể khó vào, các tài liệu trợ giúp vẫn ổn nhưng các ví dụ thì tốt hơn: Một trong những vấn đề lớn nhất là tìm ra sự kế thừa của một đối tượng này, như tôi đã có đối tượng X, bây giờ làm thế nào để tôi có được đối tượng Y ? Nếu bạn có thể sử dụng Visual Studio 2008 hoặc 2010 express (tải xuống miễn phí nếu bạn có thể tìm thấy nó) thì hãy cài đặt SDK, bạn sẽ nhận được các tài liệu trợ giúp và một loạt các ví dụ cục bộ.
Michael Promotionson

1
@mattwilkie hy vọng điều này không làm vấy bẩn vùng nước này nhiều ... nhưng để chuyển mã .NET hiện tại sang python và tìm ra cú pháp truyền kiểu, python cho .NET có vẻ đơn giản hơn một chút so với cách tiếp cận comtypes. Điều đó nói rằng, tôi chỉ mới phát hiện ra python cho .NET và chưa thử nghiệm nó.
dùng2856

1
@mattwilkie vừa phát hiện python.Net yêu cầu phải cài đặt SDK ArcGIS (trừ khi các dll trình bao bọc lắp ráp được phân phối cùng với tập lệnh ...) ngoài ArcGIS Desktop, do đó không hoàn toàn di động như cách tiếp cận comtypes.
dùng2856

Câu trả lời:


9

Tôi cũng không mạnh lắm trong lĩnh vực này, nhưng tôi đã sửa đổi mô-đun Snippets và đã thực hiện một vài hàm bao cho các tác vụ rất đơn giản. Tôi có một ví dụ về việc chỉ thêm các yếu tố dòng. Ví dụ ở dưới khối chính tạo thành một hình tam giác cho khung nhìn bố cục ngay bên ngoài tài liệu.

Tôi sử dụng tập lệnh này kết hợp với các con trỏ tìm kiếm khác và phức tạp để tạo các bảng đồ họa trong bố cục từ các dòng riêng lẻ và các thành phần văn bản, nhưng điều đó nhanh chóng di chuyển ra khỏi ví dụ "đơn giản". Mã dưới đây khá đơn giản và sử dụng một phiên bản sửa đổi của đoạn trích:

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)

nhập mô tả hình ảnh ở đây

Biên tập:

@matt wilkie

Đối với việc tìm ra các mục nhập, đó là nơi bạn sẽ phải xem qua Sơ đồ mô hình ArcObjects hoặc xem không gian tên mà một Lớp hoặc Giao diện cụ thể đang được gọi từ trong tài liệu trợ giúp .NET SDK. Trong một số trường hợp, nhiều không gian tên có thể được sử dụng do kế thừa.

Tôi không phải là chuyên gia về ArcObjects, vì vậy tôi thường phải mất một thời gian để tìm ra khi nào nên thực hiện mọi thứ với CType (). Hầu hết điều này, tôi đã chọn từ các mẫu trực tuyến. Ngoài ra, cú pháp từ các ví dụ VB.NET dường như gần với những gì bạn làm trong Python, nhưng các ví dụ C # có ý nghĩa hơn đối với tôi về khả năng đọc (nếu điều đó có ý nghĩa gì). Nhưng, theo nguyên tắc thông thường, tôi thường theo dõi các bước sau:

  1. Tạo một biến cho một đối tượng COM mới (thường là một lớp) để khởi tạo một đối tượng
  2. Sử dụng CType để truyền đối tượng COM sang (các) giao diện để cho phép truy cập vào các phương thức và các chương trình. CType cũng sẽ trả về Con trỏ Giao diện comtypes thông qua QueryInterface (). Khi con trỏ được trả về, bạn có thể tương tác với các thuộc tính và phương thức của nó.

Không chắc chắn liệu tôi có sử dụng thuật ngữ thích hợp hay không ... Tôi chủ yếu là một nhà phát triển Python "vọc" trong một số ArcObjects ... Mặc dù vậy, tôi chỉ chạm vào phần nổi của tảng băng trôi.

Ngoài ra, hàm trợ giúp này sẽ tải tất cả các Thư viện đối tượng ArcObjects (.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]

cảm ơn vì ví dụ hữu ích Lực đẩy của Q là (dự định) ít hơn đối với các công thức nấu ăn nhiệm vụ cụ thể và nhiều hơn về cách người ta nhận và viết thông tin để xây dựng công thức ở vị trí đầu tiên. Chẳng hạn, làm thế nào bạn biết import comtypes.gen.esriArcMapUI as esriArcMapUIvà sau đó sử dụng pMxDoc = CType(pDoc, esriArcMapUI.IMxDocument)(và khám phá cú pháp trong câu lệnh đó)?
matt wilkie 7/1/2015

Tôi chỉnh sửa câu trả lời ban đầu của mình để cố gắng trả lời câu hỏi của bạn. Tôi cũng có một vài ví dụ khác, nhưng đoạn trích trên có lẽ là dễ đọc nhất.
crmackey 7/1/2015

Ngoài ra, tôi đã mua cuốn sách này vào năm ngoái: amazon.com/Beginning-ArcGIS-Desktop-Development-USE/dp/
Kẻ

7

Trong một bài viết khác, có liên quan nhưng hơi khác, tôi đã cung cấp một câu trả lời có thể được quan tâm cho những người dùng python đang cố gắng quấn đầu quanh các tài liệu trợ giúp Esri ArcObjects ..

Tôi đến từ phía bên kia: Tôi đã biết ArcObjects từ lâu (rất lâu) trước khi tôi nghe nói về python và nhờ những bài đăng như thế này, tôi có thể đưa một số ArcObject quan trọng vào kịch bản dễ dàng của python (xem bài đăng này để biết ví dụ ). Tôi nhớ sự thất vọng của việc cố gắng hiểu sự kế thừa, phương pháp và tính chất; những tình huống khó xử như tôi đã có X liên quan đến Y ... vậy làm thế nào để tôi chuyển từ X sang Y.Method ()?

Câu trả lời là xem CoClass thực hiện giao diện (xem toàn văn ở đây ) .. để biết ví dụ cơ bản, nếu tôi muốn xem liệu một lớp có truy vấn định nghĩa không, và nếu vậy thì nó là gì:

Trong 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);

Thay vì ctype(đó là nổi bật trong VB) C sử dụng # ()hoặc ascho đúc, ví dụ IObject x = (IObject)y;là (cơ bản) giống như IObject x = y as IObject;đó sẽ là dim x as IObject = ctype(y,IObject)trong VB.

Tôi có thể nói rằng tôi cần IFeatureLayer để truy cập IFeatureLayerDefDef vì: nhập mô tả hình ảnh ở đây

Và khi bạn đọc tài liệu trợ giúp cho IFeatureLayer bạn sẽ thấy: nhập mô tả hình ảnh ở đây

Điều đó chỉ ra rằng việc đi ILayer-> IFeatureLayer-> IFeatureLayerDef là an toàn, miễn là ILayer thuộc loại FeatureLayer (hoặc bất kỳ CoClass nào khác).

Vì vậy, những gì với tôi và không tôi? Giao diện I nghĩa là giao diện, đó là bit hoạt động, không có I là CoClass (một loại ), vì vậy mọi thứ bạn muốn sử dụng thực sự nên bắt đầu bằng I và nếu bạn đang tạo một cái mới hoặc kiểm tra loại sau đó bỏ qua giao diện I. Một giao diện có thể có nhiều CoClass và CoClass có thể hỗ trợ nhiều giao diện nhưng đó là giao diện thực sự hoạt động.

Trong trăn:

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

Mẫu này thực hiện nhiều hơn một chút so với chữ C ở chỗ nó tìm đường đến ứng dụng hiện tại, chỉ có sẵn trong cửa sổ python hoặc addin, nếu bạn đã thử chạy nó từ dòng lệnh thì ứng dụng là Null và tập lệnh sẽ sự cố với một ngoại lệ tham chiếu null.


Wow, cảm ơn bạn rất nhiều vì đã đăng bài này! Tôi đã có một số cuộc đấu tranh để hiểu Sơ đồ ArcObject. Thật tuyệt khi có một số thông tin đầu vào từ một người nào đó giống như bạn đến từ phía bên kia của hàng rào (rất nhiều kinh nghiệm .NET ArcObjects). Một điều tôi đã gặp một số khó khăn là truy cập vào một lớp tính năng nằm trong bộ dữ liệu tính năng thông qua comtypes và python. Tôi nghĩ rằng trong quá khứ tôi đã thử mở bộ dữ liệu tính năng trước và sau đó là lớp tính năng nhưng không gặp may mắn (nhận được một số con trỏ null). Bạn có mẫu trăn nào không?
crmackey

1
Không quá nhiều, tôi thực sự chỉ bắt đầu với comtypes trong python, nhưng đối với việc mở một lớp đối tượng từ một đối tượng không gian làm việc (IFeatueWorkspace) chỉ sử dụng tên, không bao gồm tập dữ liệu tính năng - không thành vấn đề nếu trong tập dữ liệu tính năng, tất cả các tên đều là duy nhất ... xem help.arcgis.com/en/sdk/10.0/arcobjects_net/componenthelp/. Bạn có thể mở một câu hỏi mới với một số mã và tôi sẽ xem qua. Bộ dữ liệu tính năng có thể được sử dụng với một bộ dữ liệu lặp (IFeatureDataset.Subets) nhưng nó sẽ sạch hơn khi chỉ mở với tên.
Michael Promotionson

1
Cảm ơn @Michael Miles-Promotionson. Tôi sẽ cung cấp cho nó một shot khác. Nếu tôi không thể tìm ra nó, tôi sẽ gửi một câu hỏi mới với mã hiện tại của tôi.
crmackey

@MichaelStimson Tôi hiểu rằng tôi có thể sử dụng arcobject trong python bằng cách sử dụng comtypes. Tôi chưa bao giờ sử dụng arcobjects. Vì không có mẫu nào để thực hiện các tác vụ, ví dụ: xây dựng bộ dữ liệu mạng bằng cách sử dụng comtypes và arcpy, trước tiên tôi có cần hiểu arcobject trước khi tôi có thể sử dụng comtypes không? Hoặc tôi chỉ có thể tự học comtypes để sử dụng arcpy và comtypes?
ketar

1
@ketar, đó là một ý tưởng tốt để biết một chút về ArcObject trước khi bạn cố gắng sử dụng chúng trong python. Mặc dù không có nhiều mẫu ArcObject trong python (nhưng) vẫn có các mẫu trong ArcObjects trợ giúp như resource.arcgis.com/en/help/arcobjects-net/conceptualhelp/ cho các bộ dữ liệu mạng (bản dựng là mục cuối cùng trên đó trang). Mã ArcObjects dài hơn đáng kể so với python (arcpy); cá nhân tôi sẽ mã bằng VB hoặc C # và sau đó hài lòng với kết quả sao chép / dán vào python.
Michael Promotionson
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.