[GIS] In ArcObjects, how to change the spatial reference of a Map (Data Frame) in an existing MXD

arcobjectscoordinate systemparameters

I need to change the spatial reference of an existing MXD programmatically. In ArcMap UI, I would take the following steps: 1) Open the data frame properties and go to the Coordinate System tab; 2) click on little globe button (Add Coordinate System) and choose New Projected Coordinate System; 3) choose Mercator; 4) enter custom name for the coordinate system; 5) change the Standard_Parallel_1 parameter to the appropriate value; and 6) Save/PressOK. Ultimately, I need to automate this process over hundreds of MXDs.

I am really very confused about where even to start. My research has turned up a lot of references to IProjectedCoordinateSystemEdit and related classes and interfaces and to reading/writing parameters to arrays with IParamter and related, but I am finding a lot of the information confusing. So, which Interfaces/Classes should I start with, and what is the most concise way of accomplishing automation of the process I describe above?

My code currently opens the MXD to be processed in an IMapDocument and changes a suite of PageLayout and Map settings. What is left is the changing of the spatial reference. Thanks for any guidance you can offer.

UPDATE (@Hornbydd) Here is the Python main body code. (BTW, when accessing ArcObjects from Python, one thing that Python can't do is implement interfaces, so responding to events and extending ArcGIS isn't possible. I have yet to find any com objects that it can't access, though.)

f = open(chartprops, 'r')

i = 0
for chrt in f:
    if i == 0:  #skip the header
        i = i + 1
        continue
    props = chrt.split(',')
    chartnm = props[0]
    scale = float(props[1])
    latorig = props[2]
    pixwidth = float(props[3])
    pixheight = float(props[4])
    if len(props) > 5:
        pprwidth = float(props[5])
        pprheight = float(props[6])
        pprorienttxt = props[7]
    else:
        pprwidth = pixwidth / 254.0
        pprheight = pixheight / 254.0
        if pprwidth > pprheight:
            pprorienttxt = 'LANDSCAPE'
        else:
            pprorienttxt = 'PORTRAIT'
    if pprorienttxt == 'PORTRAIT':
        pprorient = 1
    else:
        pprorient = 2

    #copy template chart MXD to chart output location
    #==== WARNING! ====
    # If the mxd already exists in the detination folder,
    # it will be overwritten
    #==================
    destmxd = outloc + os.path.sep + chartnm + '.mxd'
    shutil.copy(templt, destmxd)

    pMapDoc = NewObj(esriCarto.MapDocument, esriCarto.IMapDocument)
    pMapDoc.Open(destmxd)
    pPgLayout = pMapDoc.PageLayout
    pPgLayout3 = CType(pPgLayout, esriCarto.IPageLayout3)
    pPage = pPageLayout3.Page
    pPage.Units(esriInches)
    pPage.PutCustomSize(pprwidth, pprheight)
    pPage.Orientation(pprorient)
    pMap = pMapDoc.Map
    pMap.MapUnits(esriInches)
    pMap.SetPageSize(pprwidth, pprheight)
    pMap.ReferenceScale(1.0/scale)
    pMap.MapScale(1.0/scale)

    pMapDoc.Close()
    i = i + 1
f.close()

Best Answer

I'm not sure if you are over engineering this? Or I have simplified it in my head! I was able to go through a set of MXD's changing the spatial reference of the first dataframe with some relatively simple python code, so no ArcObjects required. Below is the code I used.

import arcpy

def main():
    try:
        # Get desired spatial reference from an existing shapefile
        fc = r"C:\temp\myData.shp"
        sr = arcpy.Describe(fc).spatialReference

        # Create a list of MXD's
        arcpy.env.workspace = r"C:\temp"
        mxdlist = arcpy.ListFiles("*.mxd")

        # Main update loop
        for m in mxdlist:
            # Create MapDocument object
            fullpath = arcpy.env.workspace + "\\" + m
            print "processing " + fullpath
            mxd = arcpy.mapping.MapDocument(fullpath)

            # Get first dataframe in map document and set spatialreference
            df = arcpy.mapping.ListDataFrames(mxd)[0]
            df.spatialReference = sr

            # Overwrite mxd
            mxd.save()
    except:
        print "A critical error occurred during the execution of this Script, cannot continue!"

if __name__ == '__main__':
    arcpy.env.overwriteOutput=True
    main()