แนวทางการใช้ ArcObjects จาก Python


10

เท่านี้การเข้าถึง ArcObjects จาก Python เป็นคำถามและคำตอบที่อ่านมากที่สุดของฉันใน GIS Stack Exchange แม้ว่าความสำเร็จนั้นอาจเป็นหนึ่งในจุดอ่อนที่สุดของฉันเมื่อพูดถึงการใช้งานจริง ส่วนใหญ่ของที่แสดงยากจนมาจากความยากจนของฉันที่จะอ่านและทำความเข้าใจArcObjects เอกสาร

ดังนั้นสำหรับงานที่ได้รับอะไรบ้างแนวทางสำหรับการแปล. net / c ++ / java / ... เอกสารและตัวอย่างในการเทียบเท่าของหลาม? (ภาษาใดเป็นภาษาที่ดีที่สุดในการทำงานจากเรื่องนั้น) และดัชนีที่ดีที่สุดหรือหน้า Landing Page เริ่มต้นจากอะไร สิ่งใดที่ควรเพ่งความสนใจไปและอย่างน้อยก็สำคัญเหมือนกันสิ่งที่สามารถเพิกเฉยได้อย่างอิสระ?

สมมติว่าผู้ชมของคุณใช้ภาษาไพ ธ อนค่อนข้างน้อยและไม่รู้หนังสือในภาษาที่ใช้ในการพัฒนาอื่น ๆ นำเราไปสู่การฝึกเขียนโปรแกรมขนาดเล็กตั้งแต่แนวคิดเริ่มต้นและการวิจัยไปจนถึงผลลัพธ์การทำงานของหลาม


1
มันอาจไม่เพิ่มอะไรเลยในการสนทนาที่นี่ แต่ฉันต้องการระบุสำหรับบันทึกที่ฉันสนใจจริงๆที่เห็นชุดของการพัฒนาชุดนี้ ขอบคุณแมตต์ ฉันพบบทความหนึ่งโดยDarren Wiensสร้าง MXD ตั้งแต่เริ่มต้นและเติมเค้าโครงด้วยคำแนะนำ ดูเหมือนว่าโมดูลตัวอย่างของ Mark Cederholm มีประโยชน์จริง ๆ / มักใช้ในความพยายามเหล่านี้
Jim

ตัวอย่างที่เป็นไปได้ที่จะใช้: gis.stackexchange.com/questions/86007/… (การเปิดเผย: มันเป็นปัญหาที่ฉันกำลังทำอยู่และแจ้งให้ Q. เอาชนะฉันไปที่คำตอบ (สร้างขึ้นอย่างดี) รับเครดิตทั้งหมด ! ;-)
matt wilkie

Arcobjects อาจเข้าได้ยากเอกสารความช่วยเหลือตกลง แต่ตัวอย่างดีกว่า: หนึ่งในปัญหาที่ยิ่งใหญ่ที่สุดคือการสืบทอดการสืบทอดของวัตถุหนึ่งไปยังอีกวัตถุหนึ่งเช่นฉันมีวัตถุ X ตอนนี้ฉันจะนำวัตถุ Y ไปได้อย่างไร ? หากคุณสามารถใช้งาน Visual Studio 2008 หรือ Express 2010 (ดาวน์โหลดฟรีหากคุณสามารถหามันได้) จากนั้นติดตั้ง SDK คุณจะได้รับเอกสารความช่วยเหลือและตัวอย่างมากมายจากในเครื่อง
Michael Stimson

1
@mattwilkie หวังว่านี่จะไม่ทำให้น้ำสกปรกมากนัก ... แต่สำหรับการย้ายรหัส. NET ที่มีอยู่ไปยัง python และการหารูปแบบการเลือกพิมพ์, python สำหรับ. NETดูเหมือนจะตรงไปตรงมามากกว่าวิธีของ comtypes ที่กล่าวว่าฉันเพิ่งค้นพบหลามสำหรับ. NET และยังไม่ได้ทดสอบ
2856

1
@mattwilkie เพิ่งค้นพบ python.Net จำเป็นต้องติดตั้ง ArcGIS SDK (ยกเว้นกรณีที่ชุดตัวห่อหุ้มแอสเซมบลีถูกแจกจ่ายด้วยสคริปต์ ... ) นอกเหนือจาก ArcGIS Desktop ดังนั้นจึงไม่ใช่แบบพกพาเหมือนกับวิธี comtypes
2856

คำตอบ:


9

ฉันไม่แข็งแรงมากในพื้นที่นี้ แต่ฉันได้ปรับเปลี่ยนโมดูล Snippets และได้ทำ wraps คู่สำหรับงานง่าย ๆ ฉันมีตัวอย่างแค่เพิ่มองค์ประกอบของเส้น ตัวอย่างที่อยู่ใต้บล็อกหลักจะสร้างรูปสามเหลี่ยมเป็นมุมมองเค้าโครงนอกเอกสาร

ฉันใช้สคริปต์นี้ร่วมกับเคอร์เซอร์ค้นหาอื่นและ arcpy เพื่อสร้างตารางกราฟิกในเค้าโครงจากแต่ละบรรทัดและองค์ประกอบข้อความ แต่จะย้ายอย่างรวดเร็วจากตัวอย่าง "ง่าย" รหัสด้านล่างนั้นค่อนข้างง่ายและใช้ตัวอย่างข้อมูลที่แก้ไข:

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)

ป้อนคำอธิบายรูปภาพที่นี่

แก้ไข:

@matt wilkie

สำหรับการค้นหาการนำเข้านั่นคือที่ที่คุณจะต้องดู ArcObjects Model Diagrams หรือดูว่า namespace ที่ Class หรือ Interface นั้นถูกเรียกจากใน SDK ช่วยเหลือของ doc. ในบางกรณีสามารถใช้เนมสเปซมากกว่าหนึ่งรายการได้เนื่องจากการสืบทอด

ฉันไม่มีความเชี่ยวชาญใน ArcObjects ดังนั้นจึงมักจะใช้เวลาสักครู่กว่าจะคิดออกเมื่อต้องใช้งาน CType () ส่วนใหญ่ฉันเลือกจากตัวอย่างออนไลน์ ยิ่งไปกว่านั้นไวยากรณ์จากตัวอย่าง VB.NET นั้นดูเหมือนจะใกล้เคียงกับสิ่งที่คุณทำใน Python มากขึ้น แต่ตัวอย่าง C # นั้นทำให้ฉันมีความเข้าใจมากขึ้นในแง่ของการอ่านได้ง่ายขึ้น แต่ตามกฎของหัวแม่มือฉันมักจะทำตามขั้นตอนเหล่านี้:

  1. สร้างตัวแปรสำหรับวัตถุ COM ใหม่ (โดยปกติจะเป็นคลาส) เพื่อยกตัวอย่างวัตถุ
  2. ใช้ CType เพื่อส่งวัตถุ COM ไปยังอินเทอร์เฟซเพื่ออนุญาตการเข้าถึงวิธีการและคุณสมบัติต่าง ๆ CType จะส่งกลับ comtypes Interface Pointer ผ่าน QueryInterface () เมื่อตัวชี้ถูกส่งคืนคุณสามารถโต้ตอบกับคุณสมบัติและวิธีการของมันได้

ไม่แน่ใจว่าฉันใช้คำศัพท์ที่เหมาะสมหรือไม่ ... ฉันเป็นนักพัฒนางูใหญ่ที่ "dabbles" ใน ArcObjects บางแห่ง ... ฉันได้สัมผัสแค่ปลายภูเขาน้ำแข็งเท่านั้น

นอกจากนี้ฟังก์ชันตัวช่วยนี้จะโหลด ArcObjects Object Libraries (.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]

ขอบคุณสำหรับตัวอย่างที่มีประโยชน์! แรงขับของคิวนั้นมีน้อยลง (โดยมีจุดประสงค์) ในสูตรงานเฉพาะและอีกวิธีในการรับและเขียนข้อมูลเพื่อสร้างสูตรในตอนแรก ตัวอย่างเช่นคุณรู้จักimport comtypes.gen.esriArcMapUI as esriArcMapUIและใช้ในภายหลังอย่างไรpMxDoc = CType(pDoc, esriArcMapUI.IMxDocument)(และเปิดเผยไวยากรณ์ในคำสั่งนั้น)
matt wilkie

ฉันแก้ไขคำตอบดั้งเดิมของฉันเพื่อพยายามตอบคำถามของคุณ ฉันมีตัวอย่างอีกสองสามตัวอย่างเช่นกัน แต่ตัวอย่างข้างต้นน่าจะอ่านง่ายที่สุด
crmackey

นอกจากนี้ฉันซื้อหนังสือเล่มนี้เมื่อปีที่แล้ว: amazon.com/Beginning-ArcGIS-Desktop-Development-using/dp/…
crmackey

7

ในอีกโพสต์ที่เกี่ยวข้อง แต่แตกต่างกันเล็กน้อยฉันโพสต์ให้คำตอบที่อาจเป็นที่สนใจสำหรับผู้ใช้งานงูใหญ่ที่พยายามจะคลุมศีรษะรอบ Esri ArcObjects ช่วยเอกสาร

ฉันมาจากอีกด้านหนึ่ง: ฉันรู้แล้วว่า ArcObjects มีความยาว (ยาว) ก่อนที่ฉันจะได้ยินงูหลามและต้องขอบคุณโพสต์แบบนี้ฉันจึงสามารถรวม ArcObjects ที่สำคัญไว้ในสคริปต์ง่าย ๆ ของงูหลาม (ดูโพสต์นี้เพื่อเป็นตัวอย่าง ) ฉันจำได้ถึงความยุ่งยากในการพยายามทำความเข้าใจการสืบทอดวิธีการและคุณสมบัติ สถานการณ์ที่ลำบากเช่นฉันมี X ซึ่งเกี่ยวข้องกับ Y ... ฉันจะได้รับจาก X ถึง Y.Method () ได้อย่างไร?

คำตอบคือดูที่ CoClasses ที่นำอินเตอร์เฟสไปใช้ (ดูข้อความเต็มได้ที่นี่ ) .. สำหรับตัวอย่างพื้นฐานถ้าฉันต้องการดูว่าเลเยอร์มีคิวรีคำจำกัดความหรือไม่และถ้าเป็นเช่นนั้น:

ใน 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);

แทนที่จะctype(ซึ่งเป็นที่โดดเด่นใน VB) C # ใช้()หรือasสำหรับหล่อเช่นIObject x = (IObject)y;เป็น (พื้นฐาน) เช่นเดียวIObject x = y as IObject;ซึ่งจะเป็นdim x as IObject = ctype(y,IObject)ใน VB

ฉันสามารถบอกได้ว่าฉันต้องการIFeatureLayerเพื่อไปที่IFeatureLayerDefinitionเพราะ: ป้อนคำอธิบายรูปภาพที่นี่

และเมื่อคุณอ่านเอกสารช่วยเหลือสำหรับ IFeatureLayer คุณจะเห็น: ป้อนคำอธิบายรูปภาพที่นี่

ซึ่งแสดงว่าปลอดภัยที่จะไป ILayer-> IFeatureLayer-> IFeatureLayerDef โดยที่ ILayer นั้นเป็น FeatureLayer ประเภท (หรือ CoClasses อื่น ๆ )

แล้วเกิดอะไรขึ้นกับฉันและฉันไม่มี The I หมายถึงอินเตอร์เฟสมันเป็นบิตที่ใช้งานได้โดยไม่มี I คือ CoClass ( ชนิด ) ดังนั้นสิ่งที่คุณต้องการใช้จริงควรเริ่มด้วย I และถ้าคุณสร้างใหม่หรือตรวจสอบชนิด แล้วข้ามอินเตอร์เฟซที่หนึ่งสามารถมี CoClasses จำนวนมากและ CoClass สามารถรองรับการเชื่อมต่อจำนวนมาก แต่มันเป็นอินเตอร์เฟซที่จริงไม่ทำงาน

ในหลาม:

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

ตัวอย่างนี้ทำมากกว่า C เล็กน้อยซึ่งพบทางไปสู่แอปพลิเคชันปัจจุบันซึ่งจะมีให้เฉพาะในหน้าต่าง python หรือ addin เท่านั้นหากคุณลองเรียกใช้จากบรรทัดคำสั่งแอปพลิเคชั่นจะเป็น Null และสคริปต์จะ ขัดข้องด้วยข้อยกเว้นการอ้างอิง Null


ว้าวขอบคุณมากที่โพสต์ข้อความนี้! ฉันมีปัญหาในการทำความเข้าใจ ArcObject Diagrams เป็นเรื่องดีที่มีข้อมูลจากคนอย่างคุณที่มาจากรั้วอีกด้านหนึ่ง (มีประสบการณ์. NET ArcObjects มากมาย) สิ่งหนึ่งที่ฉันมีปัญหากับคือการเข้าถึงคลาสฟีเจอร์ที่อยู่ในชุดข้อมูลคุณลักษณะผ่าน comtypes และ python ฉันคิดว่าในอดีตฉันได้ลองเปิดชุดข้อมูลคุณลักษณะก่อนแล้วจากนั้นระดับคุณลักษณะ แต่ไม่มีโชค (ได้รับพอยน์เตอร์พอยน์เตอร์บางตัว) คุณมีตัวอย่างของไพ ธ อนไหม
crmackey

1
ไม่มากฉันแค่เริ่มต้นด้วย comtypes ใน python เท่านั้น แต่สำหรับการเปิดคลาสคุณลักษณะจากเวิร์กสเปซ (IFeatueWorkspace) วัตถุเพิ่งใช้ชื่อไม่รวมชุดข้อมูลคุณสมบัติเลย - ไม่สำคัญว่า มันอยู่ในชุดข้อมูลของคุณสมบัติชื่อทั้งหมดไม่ซ้ำกัน ... ดูhelp.arcgis.com/th/sdk/10.0/arcobjects_net/componenthelp/ ......คุณสามารถเปิดคำถามใหม่ด้วยรหัสและฉันจะดู ชุดข้อมูลคุณลักษณะสามารถใช้กับการวนซ้ำของชุดข้อมูล (IFeatureDataset.Subsets) แต่มันสะอาดกว่าที่จะเปิดด้วยชื่อ
Michael Stimson

1
ขอบคุณ @Michael Miles-Stimson ฉันจะให้อีกนัด หากฉันไม่สามารถเข้าใจได้ฉันจะโพสต์คำถามใหม่ด้วยรหัสปัจจุบันของฉัน
crmackey

@MichaelStimson ฉันเข้าใจว่าฉันสามารถใช้ arcobjects ใน python โดยใช้ comtypes ฉันไม่เคยใช้ arcobjects เนื่องจากไม่มีตัวอย่างในการทำงานเช่นสร้างชุดข้อมูลเครือข่ายโดยใช้ comtypes และ arcpy ฉันต้องเข้าใจ arcobjects ก่อนจึงจะสามารถใช้ comtypes ได้หรือไม่ หรือฉันสามารถเรียนรู้ comtypes ด้วยตัวเองเพื่อใช้ arcpy และ comtypes?
ketar

1
@ketar มันเป็นความคิดที่ดีที่จะรู้จัก ArcObjects เล็กน้อยก่อนที่จะลองใช้มันในไพ ธ อน แม้ว่าจะมีตัวอย่างของ ArcObjects จำนวนมากในหลาม (แต่) มีตัวอย่างใน ArcObjects ที่ช่วยอย่างเช่นresources.arcgis.com/th/help/arcobjects-net/conceptualhelp/ ...... สำหรับชุดข้อมูลเครือข่าย (บิลด์เป็นรายการสุดท้ายของมัน หน้า). รหัส ArcObjects มีความหมายมากกว่า verbose มากกว่า python (arcpy) อย่างมีนัยสำคัญ ส่วนตัวฉันต้องการรหัสใน VB หรือ C # แล้วเมื่อมีความสุขกับผลลัพธ์คัดลอก / วางในหลาม
Michael Stimson
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.