Python에서 ArcObject를 사용하기위한 지침


10

지금까지 Python에서 ArcObject액세스하고 있습니까? GIS Stack Exchange에서 가장 많이 읽고 참조한 Q & A입니다. 그 성공에도 불구하고 실제로 사용하는 데있어 가장 약한 부분 중 하나 일 것입니다. 그 불쌍한 전시의 대부분은 ArcObjects 문서 를 읽고 이해하는 저의 가난한 능력에서 비롯됩니다 .

그렇다면 주어진 작업에 대해 .net / c ++ / java / ... docs 및 예제를 파이썬으로 변환하는 지침은 무엇입니까? (어떤 언어가 그 문제에 가장 적합한가요?) 그리고 가장 좋은 색인 또는 방문 페이지는 무엇입니까? 어떤 것에 중점을 두어야하고, 적어도 중요한 것은 자유롭게 무시할 수있는 것은 무엇입니까?

청중이 적어도 파이썬 문맹이고 다른 개발 언어에서는 문맹이라고 가정하십시오. 초기 아이디어와 연구에서 작동하는 파이썬 결과에 이르기까지 작은 코딩 연습을 통해 우리를 안내하십시오.


1
여기서 대화에 아무것도 추가하지 않을 수도 있지만이 연습 세트가 발전하는 것을보고 정말로 관심이있는 기록을 말하고 싶습니다. 고마워 매트. Darren Wiens 가 MXD를 처음부터 작성하고 안내선으로 레이아웃을 채우는 기사를 찾았습니다 . Mark Cederholm의 스 니펫 모듈 은 이러한 노력에 실제로 도움이되고 종종 사용되는 것으로 보입니다 .
Jim

사용 가능한 예 : gis.stackexchange.com/questions/86007/… (공개 : 내가 작업 한 문제이므로 Q를 자극했습니다. (잘 만들어진) 답변으로 나를이기십시오. ! ;-)
matt wilkie

Arcobjects는 들어가기가 어려울 수 있지만 도움말 문서는 괜찮지 만 예제는 더 좋습니다. 가장 큰 문제 중 하나는 X 객체가있는 것처럼 하나의 객체를 다른 객체로 상속하는 것입니다. 이제 객체 Y를 얻는 방법 ? Visual Studio 2008 또는 2010 express (무료로 다운로드 할 수있는 경우 무료로 다운로드)를 얻을 수있는 경우 SDK를 설치하면 도움말 문서와 여러 예제가 로컬로 제공됩니다.
Michael Stimson

1
@mattwilkie 잘만되면 이것은 물을 너무 많이 버리지 않습니다 ...하지만 기존 .NET 코드를 파이썬으로 이식하고 유형 캐스팅 구문을 파악하기 위해 .NET 용 python 은 comtypes 접근 방식보다 조금 더 직설적입니다 . 즉, .NET 용 Python 만 발견했으며 아직 테스트하지 않았습니다.
user2856

1
@mattwilkie는 python을 발견했습니다 .Net은 ArcGIS Desktop 외에도 ArcGIS SDK가 설치되어 있어야합니다 (어셈블리 래퍼 dll이 스크립트와 함께 배포되지 않는 한 ...). comtypes 접근 방식만큼 이식성이 떨어집니다.
user2856

답변:


9

나는이 분야에서도 강하지는 않지만 Snippets 모듈을 수정했으며 매우 간단한 작업을 위해 몇 개의 래퍼를 만들었습니다. 선 요소를 추가하는 예가 있습니다. 메인 블록 아래의 예 는 문서 바로 바깥의 레이아웃보기에 삼각형을 형성합니다.

이 스크립트를 다른 검색 커서와 함께 사용하여 개별 행과 텍스트 요소의 레이아웃에서 그래픽 테이블을 만들지 만 "간단한"예제에서 빠르게 멀어집니다. 아래 코드는 매우 간단하며 수정 된 스 니펫 버전을 사용합니다.

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를 살펴 보거나 .NET SDK 도움말 문서에서 특정 클래스 또는 인터페이스가 호출되는 네임 스페이스를 확인해야합니다. 경우에 따라 상속으로 인해 둘 이상의 네임 스페이스를 사용할 수 있습니다.

나는 ArcObjects의 전문가가 아니므로 CType ()으로 물건을 캐스팅 할 때를 알아내는 데 보통 시간이 걸립니다. 이 중 대부분은 온라인에서 샘플을 가져 왔습니다. 또한 VB.NET 예제의 구문은 Python에서 수행하는 작업에 더 가까운 것처럼 보이지만 C # 예제는 가독성 측면에서 더 의미가 있습니다 (그렇다면 이해가됩니다). 그러나 경험상 일반적으로 다음 단계를 수행합니다.

  1. 객체를 인스턴스화하기 위해 새 COM 객체 (일반적으로 클래스)에 대한 변수를 만듭니다.
  2. CType을 사용하여 COM 개체를 인터페이스로 캐스팅하여 메서드 및 속성에 액세스 할 수 있습니다. CType은 또한 QueryInterface ()를 통해 comtypes 인터페이스 포인터를 반환합니다. 포인터가 반환되면 해당 속성 및 메서드와 상호 작용할 수 있습니다.

내가 적절한 용어를 사용하고 있는지 잘 모르겠다 ... 나는 주로 일부 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]

유용한 예를 주셔서 감사합니다! Q의 추력은 특정 작업 레시피에 대해서는 적고 처음에는 레시피를 구축하기 위해 정보를 어떻게 작성하고 작성하는지에 관한 것입니다. 예를 들어, 어떻게 알고 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를 오랫동안 알고 있었다. 이와 같은 게시물 덕분에 파이썬의 쉬운 스크립팅에 중요한 ArcObject를 포함시킬 수있다 (예를 들어이 게시물 을 참조하십시오 ). 상속, 메소드 및 속성을 이해하려는 노력이 좌절되었다는 것을 기억합니다. 딜레마 같은 X는 Y와 관련이 있습니다. 그래서 X에서 Y.Method ()로 어떻게 가나 요?

대답은 인터페이스를 구현하는 CoClass를 살펴 보는 것입니다 ( 여기에 전체 텍스트 참조 ). 레이어에 정의 쿼리가 있는지 여부를 확인하려는 경우 기본 예는 다음과 같습니다.

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

대신에 ctypeC # 1 사용 (VB에 띄는 임) ()또는 as주조 예 IObject x = (IObject)y;와 동일한 (기본적) 인 IObject x = y as IObject;것이되는 dim x as IObject = ctype(y,IObject)VB이다.

IFeatureLayerDefinition 에 도달하려면 IFeatureLayer 가 필요하다고 말할 수 있습니다 . 여기에 이미지 설명을 입력하십시오

IFeatureLayer에 대한 도움말 문서를 읽으면 다음을 볼 수 있습니다. 여기에 이미지 설명을 입력하십시오

ILayer가 FeatureLayer (또는 다른 CoClass) 유형 인 경우 ILayer-> IFeatureLayer-> IFeatureLayerDef로 이동하는 것이 안전하다는 것을 나타냅니다.

그래서 나는 무슨 일이야? I는 인터페이스를 의미합니다 .I는 CoClass ( 유형 ) 가 없으면 작업을 수행하는 비트 이므로 실제로 사용하려는 모든 것은 I로 시작해야하며 새로운 것을 작성하거나 유형을 확인하는 경우 인터페이스는 많은 CoClass를 가질 수 있고 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보다 약간 더합니다. 파이썬 창 또는 추가 기능에서만 사용할 수 있습니다. 명령 줄에서 실행하려고하면 응용 프로그램은 Null이고 스크립트는 null 참조 예외와 충돌


와우, 이것을 게시 해 주셔서 감사합니다! ArcObject Diagrams를 이해하는 데 어려움을 겪었습니다. 울타리 반대편에서 온 자신과 같은 누군가의 의견을 얻는 것이 좋습니다 (많은 .NET ArcObjects 경험). 내가 어려움을 겪었던 한 가지는 comtypes 및 python을 통해 기능 데이터 세트에있는 기능 클래스에 액세스하는 것입니다. 나는 과거에 피쳐 데이터 세트를 먼저 열고 피쳐 클래스를 열려고했지만 운이 없었습니다 (널 포인터를 얻음). 그에 대한 파이썬 샘플이 있습니까?
crmackey

1
그리 많지 않지만 실제로 파이썬에서 comtypes로 시작하고 있지만 작업 공간 (IFeatueWorkspace) 객체에서 기능 클래스를 여는 경우 이름 만 사용하고 기능 데이터 세트를 전혀 포함하지 마십시오. 기능 데이터 세트에 있으며 모든 이름이 고유합니다 ... help.arcgis.com/en/sdk/10.0/arcobjects_net/componenthelp/… 코드를 사용하여 새 질문을 열 수 있습니까? 피처 데이터 세트는 반복되는 데이터 세트 (IFeatureDataset.Subsets)와 함께 사용할 수 있지만 이름으로 여는 것이 더 깔끔합니다.
Michael Stimson

1
@Michael Miles-Stimson에게 감사드립니다. 나는 또 다른 기회를 줄 것이다. 알아낼 수 없으면 현재 코드로 새 질문을 게시합니다.
crmackey

@MichaelStimson comtypes를 사용하여 파이썬에서 arcobjects를 사용할 수 있음을 이해합니다. 나는 arcobjects를 사용한 적이 없다. comtypes와 arcpy를 사용하여 네트워크 데이터 세트를 구축하는 등 작업을 수행하기위한 샘플이없는 경우 comtypes를 사용하기 전에 먼저 arcobject를 이해해야합니까? 아니면 arcpy와 comtypes를 사용하기 위해 스스로 comtypes을 배울 수 있습니까?
ketar

1
@ketar, 파이썬에서 ArcObject를 사용하기 전에 ArcObject에 대해 조금 아는 것이 좋습니다. 파이썬에는 아직 많은 ArcObject 샘플이 없지만 (아직) ArcObjects 도움말에는 resources.arcgis.com/en/help/arcobjects-net/conceptualhelp/… 와 같은 샘플이 있습니다. 네트워크 데이터 세트의 경우 (빌드가 마지막 항목입니다) 페이지). ArcObjects 코드는 파이썬 (arcpy)보다 훨씬 더 장황합니다. 개인적으로 VB 또는 C #으로 코딩 한 다음 결과에 만족하면 파이썬에 복사 / 붙여 넣기하십시오.
Michael Stimson
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.