Convert annotation to polygon features - Python Script...

4907
2
01-08-2012 01:09 PM
IgorKaruza
New Contributor
Hi!

Is there a Python Script for Converting Annotation FeatureClass to Polygon FeatureClass?

There is VBA Script (http://help.arcgis.com/en/sdk/10.0/vba_desktop/conceptualhelp/index.html#//0001000000r4000000) that seems to be working fine (more or less).
It might have some problems with Multipart Annotations, but I haven't tried that (http://forums.esri.com/thread.asp?c=93&f=993&t=292545).

Br,

Igor Karuza
GISDATA Croatia
0 Kudos
2 Replies
BryanPrice1
New Contributor II
Hi Igor,

Hopefully someone will come up with a better answer than this but you can use ArcObjects in python so I converted the VBA script you mentioned to python. You will have to install the comtype modules for python and then load the ArcMap Modules. Luckily Mark Cederholm shows you how to do this see ArcMap and Python
i.e.

In C:\Python27\ArcGIS10.1\Lib\site-packages\comtypes
Delete automation.pyc, automation.pyo, safearray.pyc, safearray.pyo
Edit automation.py
Add the following entry to the _ctype_to_vartype dictionary (line 794):
POINTER(BSTR): VT_BYREF|VT_BSTR,

At the Python prompt:
>>> from comtypes.client import GetModule
>>> GetModule("c:/program files/arcgis/desktop10.1/com/esriArcMapUI.olb")
TIP: If loading one or modules fails, delete all files in the comtypes/gen folder before trying again.

Then you're set for using ArcObjects in Python. Create a new script with the following in it
Open a new ArcMap session. Add an annotation layer and polygon layer and you're good to go.
# ConvertAnnotationToPoygons.py
# Updated for python ArcGIS 10.1 using comtypes
 
# Import Modules
import arcpy
from arcpy import env
import os
import sys
 
import comtypes.client
import comtypes.gen.esriSystem as esriSystem
import comtypes.gen.esriGeometry as esriGeometry
import comtypes.gen.esriGeoDatabase as esriGeoDatabase
import comtypes.gen.esriGeoprocessing as esriGeoprocessing
import comtypes.gen.esriArcMapUI as esriArcMapUI
import comtypes.gen.esriCarto as esriCarto
import comtypes.gen.esriDisplay as esriDisplay
import comtypes.gen.esriFramework as esriFramework
import comtypes.gen.esriDataSourcesFile as esriDataSourcesGDB
 
def NewObj(MyClass, MyInterface):
    from comtypes.client import CreateObject
    try:
        ptr = CreateObject(MyClass, interface=MyInterface)
        return ptr
    except:
        return None
 
def CType(obj, interface):
    try:
        newobj = obj.QueryInterface(interface)
        return newobj
    except:
        return None
   
def GetApp():
    """Get a hook into the current session of ArcMap"""
    pAppROT = NewObj(esriFramework.AppROT, esriFramework.IAppROT)
    if pAppROT is not None:
        iCount = pAppROT.Count
        if iCount == 0:
            print 'No ArcGIS application currently running.  Terminating ...'
            return None
        for i in range(iCount):
            pApp = pAppROT.Item(i)  #returns IApplication on AppRef
            print pApp.Name
            if pApp.Name == 'ArcMap':
                print "ArcMap found"
                pDoc = pApp.Document
                print pDoc.Title
                if pDoc.Title == "untitled.mxd" or pDoc.Title == "Untitled":
                    return pApp
    print 'No ArcMap session is running at this time.'
    print "No AppROT found"
    print "Failed"
    return None
 
def AnnotoPoly():
    #USER SETTINGS
    #SET these variables for your individual case
   
    FDOLayerNum = 0 #Set annotation layer here (zero-based: 0 is first layer in TOC)
    FLayerNum = 1 #Set empty feature layer here (zero-based: 1 is second layer in TOC)
    OutputDPI = 1200 #Highest DPI of your final output device(s)
    ScreenResolution = 96 #Resolution of your monitor
    FinalOutputScale = 24000 #Final scale that your map will be printed with  
   
    pApp = GetApp()
    pDoc = pApp.Document
    pMxDoc = CType(pDoc, esriArcMapUI.IMxDocument)
    pMap = pMxDoc.FocusMap
 
    pActiveView = CType(pMap, esriCarto.IActiveView)
    pActiveView.Refresh()
   
    pScreenDisplay = pActiveView.ScreenDisplay
    pDisplayTransform = pScreenDisplay.DisplayTransformation
 
    pFLayer = pMap.Layer(FLayerNum)
    pFL = CType(pFLayer, esriCarto.IFeatureLayer)
    pFClass = CType(pFL.FeatureClass, esriGeoDatabase.IFeatureClass)
 
    pClass = pMap.Layer(FDOLayerNum)
    pAnnoClass = CType(pClass,esriCarto.IFeatureLayer)
    pAnnoClass = pAnnoClass.FeatureClass
    pAnnoClass = CType(pAnnoClass.Extension,esriCarto.IAnnoClass)
   
    ReferenceScale = pMap.ReferenceScale
    MapScale = pMap.MapScale
    OptimumScale = float(ScreenResolution) / OutputDPI * FinalOutputScale / 2
    AnnoScaleFactor = float(pAnnoClass.ReferenceScale / OptimumScale)
   
    pFDOGraphicsLayer = pMap.Layer(FDOLayerNum)
 
    pFDOGraphicsRead = CType(pFDOGraphicsLayer, esriCarto.IFDOGraphicsLayerRead)
 
    pMap.ReferenceScale = 0
    pMap.MapScale = OptimumScale
 
    # Generate Annotation Graphics
    pFDOGraphicsRead.StartGeneratingGraphics(None, pScreenDisplay, True, True, False)
 
    pAnnoElement = pFDOGraphicsRead.NextGraphic
    while pAnnoElement:
 
        pTextElement = CType(pAnnoElement, esriCarto.ITextElement)
        pTextSymbol = pTextElement.Symbol
 
        #Temporarily change text symbol's size
        TempTextSize = pTextSymbol.Size
        pTextSymbol.Size = float(TempTextSize) * AnnoScaleFactor
       
        pTextQuery = CType(pTextSymbol, esriDisplay.IQueryGeometry)
        pTextPointGeo = CType(pAnnoElement.Geometry, esriGeometry.IGeometry)
 
        pScreenDisplay.StartDrawing(pScreenDisplay.WindowDC, pScreenDisplay.ActiveCache)
        pPolygon = CType(pTextQuery.GetGeometry(pScreenDisplay.WindowDC, pDisplayTransform, pTextPointGeo), esriGeometry.IPolygon)
 
        #Ensure geometry is suitable for a feature (sorts inner/outter rings)
        pTopoOperator2 = CType(pPolygon, esriGeometry.ITopologicalOperator2)
        pTopoOperator2.IsKnowSimple_2 = False
 
        pPolygon.SimplifyPreserveFromTo()
 
        pScreenDisplay.FinishDrawing
       
        #Restore textsymbol size
        pTextSymbol.Size = TempTextSize
 
        pFeature = CType(pFClass.CreateFeature(), esriGeoDatabase.IFeature)
        pFeature.Shape = pPolygon
        pFeature.Store()
       
        pAnnoElement = pFDOGraphicsRead.NextGraphic
 
    #Restore dataframe's previous extent
    pMap.ReferenceScale = ReferenceScale
    pMap.MapScale = MapScale
    pActiveView.Refresh
       
 
if __name__ == '__main__':
    AnnotoPoly()
WilliamMcInnes
New Contributor III

Thanks for converting this script. Any idea why the new polygons are being created in a different location than the original annotation layer?