How to programmatically create a .prj file for a CAD drawing

9867
28
Jump to solution
11-30-2015 02:08 PM
AdrianWelsh
MVP Honored Contributor

I think there must be an ‘easy’ way to do this but I can’t seem to find a comprehensive set of answers for this question.

I am given CAD files from Bentley MicroStation (.dgn files) that are projected in a local coordinate system. I then open a blank ArcMap and create a new Projected Coordinate System (they usually are in a Lambert Conformal Conic system, US Survey Feet, have a Geographic Coordinate System of NAD83, and have a series of inputs for the parallels, easting/northing, scale factor, etc). After that, I load the .dgn file and see if it lines up where it is supposed to.

Some code snippets I have seen show how to get to the false easting/northing, 1st and 2nd standard parallel, and such, but I have not found all of the places to enter in all of the values.

I hope what I am asking makes sense. I am guessing you use the SpatialReference library within arcpy in Python (after I figure out how to program the inputs, I plan on making a form where the user types in certain values, etc). Please show me the direction I need to go for this!

Thanks in advance!

0 Kudos
28 Replies
DanPatterson_Retired
MVP Emeritus

The prj file is just a text file....edit it as such.  It doesn't matter.  You can do what you want with the text string just as long as the numeric parameters are valid.  Esri no longer produces a series of files *.prj for example, but now generates the projection description from the details.  Since you are working with cad files, you need the *.prj so copying and changing the name doesn't affect anything.  For example, a shapefile and all its fiddly bits ( shp, dbf, shx, etc etc ) associates a file name to a whole bunch of extensions...one of those is the *.prj file, as long is the naming is consistent you can copy one file to another, renaming it as I did.  As you will notice, there is nothing in the file itself that identifies what it is...except a whole bunch of numbers.  This is cloning...as long is the functionality is the same...who cares what it is called! (Dolly.prj might take exception)

0 Kudos
AdrianWelsh
MVP Honored Contributor

Dan, I liked the nod to Dolly the clone. I get what you are saying about all the rip rap of the former shapefile and, you're right, the *.prj file is important with CAD files (why can't we all just get along and all use GIS??).

The naming isn't really my concern; I just want to be able to get into the SpatialReference class of the .prj file that I created and change the values of certain properties (like false Easting, etc) based on user input. When I try to change these kind of values with the sad code snippet I placed above, the values do not change. How do I change these values and make them stick?

0 Kudos
DanPatterson_Retired
MVP Emeritus

Well...I have done this in the past with no problem, ... assuming you data in the file are within acceptable range of the values!  Changing the prj central meridian DOES NOT move the file objects to a new location.  You have to change the geometry to do this and this means that you have to project it from one coordinate system to another.

I live in a classic area where this is issue arises all the time.  Our local files are often given in MTM and UTM

now MTM is a Modified Transverse Mercator vs a Universal Transverse Mercator.  In short, the Easting values differ by about 100,000-ish or so and the Northings are relatively the same.  One might be tempted just to switch and rename *.prj files to automagically move the coordinates to a new location. Not! I can't make MTM line up with UTM just by switching the prj file...the coordinates have to be projected and a new file created.  Dolly cannot be made into anything other than her genes allowed for.

0 Kudos
AdrianWelsh
MVP Honored Contributor

Dan, I understand what you are saying about how this can go wrong quickly. I just need to input values into my .prj file from a specified user input based on the survey of the CAD drawing. These are known values from the surveyor so they are more than likely correct and will fit within the bounds of the projection.

When looking at the SpatialReference class library, I see that most of the properties are read and write. But, why is it that I cannot write to change certain values like "name" or "falseEasting" or other ones that are indicated as read/write? Are these really not read/write but read only?

Is the only way to change properties to go into the "set" properties towards the bottom of that page (like setDomain and such)?

Thanks again.

0 Kudos
DanPatterson_Retired
MVP Emeritus

the read only parameters are your clue that you have to use the Project tool...which you can use its code snippet, you can only create so much within arcpy BECAUSE they don't want you to do what you want to do

DarrenWiens2
MVP Honored Contributor

Buuuuuut, the help says 'name' (at least) is read/write, which I guess is a mistake judging by Adrian's example.

DanPatterson_Retired
MVP Emeritus

the important ones that you shouldn't touch are read only, which is what we are trying to clarify, but just in case the help isn't reference enough...SpatialReference—Help | ArcGIS for Desktop in case people don't read the previous threads.

AdrianWelsh
MVP Honored Contributor

It seems that Darren is right that there is a mistake in the properties. All the read/write options are really read only.

In any case, I have conceded to just using the projection string that Dan pointed out and have successfully recreated my own string based on some variables. But, I still am stuck with making the string file stick!

import arcpy

#User defined variables (to be actually defined later)
#Project name related
PIN = 12345
ProjName = "New_Project"

#Projection related
ProjectionName = "Lambert_Conformal_Conic"
FalseEasting = 640811.6365
FalseNorthing = -436753.4539
CentralMeridian = -111.5
StandardParallel1 = 40.65
StandardParallel2 = 39
ScaleFactor = 1.000240774
LatOfOrigin = 38.3333
LinearUnit = "Foot_US"
MetersPerFoot = 0.3048006096
#Geographic Coordinate System
GeoCS = '"GCS_NAD_1983_2011",DATUM["D_NAD_1983_2011",SPHEROID["GRS_1980",6378137.0,298.257222101]],PRIMEM["Greenwich",0.0],UNIT["egree",0.0174532925199433]'


#The string for the projection with user inputted variables
 projString = ('PROJCS["' + str(PIN) + '_' + ProjName +
            '",GEOGCS[' + GeoCS +
            '],PROJECTION["' + ProjectionName +
            '"],PARAMETER["False_Easting",' + str(FalseEasting) +
            '],PARAMETER["False_Northing",' + str(FalseNorthing) +
            '],PARAMETER["Central_Meridian",' + str(CentralMeridian) +
            '],PARAMETER["Standard_Parallel_1",' + str(StandardParallel1) +
            '],PARAMETER["Standard_Parallel_2",' + str(StandardParallel2) +
            '],PARAMETER["Scale_Factor",' + str(ScaleFactor) +
            '],PARAMETER["Latitude_Of_Origin",' + str(LatOfOrigin) +
            '],UNIT["' + LinearUnit + '",' + str(MetersPerFoot) + ']]')

outputPrj = r"C:\Temp\TempPlaceHolder.prj"
spaRef = arcpy.SpatialReference()
spaRef.createFromFile(outputPrj)
spaRef.loadFromString(projString)
print spaRef.exportToString() #edited to fix code...

From looking at the print out, the string looks as it is intended. But, how do I make it stick? When I look at the actual .prj file, it still has the old projection info. I think I am only changing the "object" in Python but I want to save changes to the .prj file....

0 Kudos
DarrenWiens2
MVP Honored Contributor

You appear to be back to this method, so just open and write the file, without an arcpy SpatialReference whatsoever. To reiterate:

prj = open(r"C:\junk\my_new_prj_file.prj", "w"
crs_string = 'PROJCS["NAD_1983_UTM_Zone_10N",GEOGCS["GCS_North_American_1983",DATUM["D_North_American_1983",SPHEROID["GRS_1980",6378137,298.257222101]],PRIMEM["Greenwich",0],UNIT["Degree",0.017453292519943295]],PROJECTION["Transverse_Mercator"],PARAMETER["latitude_of_origin",0],PARAMETER["central_meridian",-123],PARAMETER["scale_factor",0.9996],PARAMETER["false_easting",500000],PARAMETER["false_northing",0],UNIT["Meter",1]]'  
prj.write(crs_string)  
prj.close() 

AdrianWelsh
MVP Honored Contributor

Cheating! Oh well, you win. I agree though. This worked. (I even double checked it with arcpy.SpatialReference.exportToString() and it checked out correctly).

Thanks for your help, Darren Wiens​ and Dan Patterson​!

0 Kudos