Translating coordinates to site coordinates

Hi,

I’d like some advise on translating coordinates from the project basepoint to site (Survey coordinates).

In python I’ve a routine which draws some linework at coordinates, but I need these to be related to the survey coordinates and not the project basepoint.

Reading the API docs I found the ProjectLocation class and if I run this I can access the Project locations within the document:

info = doc.ProjectLocations

I can’t see any methods for translating coordinates, but there is one called ‘Location’ which returns an ‘Autodesk.Revit.DB.Location’ object.

The problem I have is that when I look at the Location Class I can’t see any method of getting or translating its coordinates or even return if its the current one in use.

I’d appreciate some pointers on what I should be looking for - thanks.

You need to get the ProjectLocation. ProjectLocations returns an enumerable, so you’ll need to get its enumerator first, then iterate the list to get the ProjectLocation object.

Then it gets easy: once you have the ProjectLocation you can extract the NorthSouth and EastWest property and use these values to create a vector (a Revit XYZ). Negate it (thats actually the name of the method - it reverses the vector). Then use this vector to translate your elements using ElementTransformUtils.MoveElements and it will move all objects to the project Survey Point relative to the Project Base Point!

I tried that, but am unable to work with the list which it returns.

Dynamo / Python states that its a list, but if I try to select one of the items:

getprojlocs = doc.ProjectLocations
pltouse = getprojlocs[0]

I get an error stating that its unsubscriptable.

Its confusing that Dynamo states that a list is returned, I guess its not a list and requires some other method of selecting the items from it…?

It’s not a list so you can’t access it like one. First thing that comes back is Enumerable which means you can call a “for” loop on it:

for i in doc.ProjectLocations

or more pythonic:

[x for x in doc.ProjectLocations]

Now, what you will get back is a list of ProjectLocation objects. If you need their offsets like EastWest or NorthSouth you need to actually query their SiteLocation and since that is an indexer, it will need a point value as input called like this:

position = location.GetProjectPosition[XYZ(0,0,0)]`

Then you have an object that you can call for Angle, NorthSouth etc. Here’s a full code:

# Import RevitAPI
import clr
clr.AddReference("RevitAPI")
import Autodesk
from Autodesk.Revit.DB import *

# Import DocumentManager and TransactionManager
clr.AddReference("RevitServices")
import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager
doc = DocumentManager.Instance.CurrentDBDocument

def GetValues(loc):
	pos = loc.ProjectPosition[XYZ(0,0,0)]
	angle = pos.Angle
	ew = pos.EastWest
	e = pos.Elevation
	ns = pos.NorthSouth
	return [angle, ew, ns, e]
	
locations = doc.ProjectLocations

#Assign your output to the OUT variable.
OUT = [GetValues(x) for x in locations]
6 Likes

Konrad - that’s great, thanks.

Its confusing why Dynamo reports that the data is a list, when its a Enumberable as you day…

One last question which you might be able to help me with, the project can have several site locations - is there a method for determining which one is set to ‘Current’?

I can’t see which Property in the ProjectLocation class reports this?

Cheers.

I would guess it’s a document property, take a look at the ActiveProjectLocation Property:

Edit: ProjectLocation and SiteLocation are probably different things. I have not looked much into this before, so I don’t know it this is of any help at all.

Thanks Einar.

Regarding the ProjectPosition property, what tells you that you cannot simply get the position by loc.ProjectPosition, how in the API docs you can tell its an indexer that needs calling.

OK, I’ve answered my own question - the API docs state:

When getting this property, the North/South, East/West, and Elevation values report the coordinates of the point similar to the Revit command “Report Shared Coordinates”. To get the values of the transformations applied by this project location, pass XYZ.Zero.

I’ve not come across this type of thing before…

This is in reference to the SiteLocation object mentioned by @Konrad_K_Sobon. You need to pass an XYZ to the GetProjectPosition property to get the project location:

position = location.GetProjectPosition[XYZ(0,0,0)]

If you only have a single coordinate system, then you can assign the first item from the ProjectLocations enumerable (as only one item will exist), then create the XYZ needed to perform the transform.

This works great for 2018 Revit, but it is failing on 2019 Revit. Any ideas?

Looks like the ProjectPosition property has been deprecated in favor of the GetProjectPosition() and SetProjectPosition() methods.

So, instead of this:
pos = loc.ProjectPosition[XYZ(0,0,0)]

It should be this:
pos = loc.GetProjectPosition(XYZ(0,0,0))

I tried that, but it seems to be the line

locations = doc.ProjectLocations

that is throwing the error.

What is the exact error?

Warning: IronPythonEvaluator.EvaluateIronPythonScript operation failed.
Traceback (most recent call last):
File “”, line 26, in
File “”, line 15, in GetValues
AttributeError: ‘ProjectLocation’ object has no attribute ‘ProjectPosition’

Yes, the ProjectPosition property doesn’t exist in the Revit 2019 API. Here is an edited version of Konrad’s script:

# Import RevitAPI
import clr
clr.AddReference("RevitAPI")
import Autodesk
from Autodesk.Revit.DB import *

# Import DocumentManager and TransactionManager
clr.AddReference("RevitServices")
import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager
doc = DocumentManager.Instance.CurrentDBDocument

def GetValues(loc):
	pos = loc.GetProjectPosition(XYZ(0,0,0))
	angle = pos.Angle
	ew = pos.EastWest
	e = pos.Elevation
	ns = pos.NorthSouth
	return [angle, ew, ns, e]
	
locations = doc.ProjectLocations

#Assign your output to the OUT variable.
OUT = [GetValues(x) for x in locations]
2 Likes

Thanks! Works like a charm.

1 Like