As you will probably know, Revit has a bunch of coordinate systems. You will certainly of heard of Project and Shared coordinates and maybe you may have heard of this illusive Project Internal Coordinate System at some point in passing conversation (yes, it does exist, it is primarily used for calculations in Revit e.g. graphics, imports, transformations and some other functions, it is also known as the “Relative Origin” inside the Spot Coordinate Type Properties). You can read a great article (probably the best I have read) all about Revit’s Origin/Basepoints here. Kudos to these guys, very thorough!

Each one of these coordinate systems has its benefits depending on how you are scheduling or calling out the coordinates of your Elements. In my discipline – Structures, we tend to document in the Shared Coordinate System. But you may use Project or Relative coordinates, whatever floats your boat.

There are a few tools out there that let you add coordinate data to parameters. The very popular Excitech toolkit let you do this for free until Revit 2017, sadly this is now a paid for Add-In. But, why pay for something that in my mind should be a Built-In feature of Revit itself? (Hint, Hint Autodesk! :))

Well, fortunately for us, Autodesk have a public API for Revit which gives us mortals the tools to be gods (well, I may exaggerate just a little, but it does mean we can make the features for Revit they didn’t get around to, or our own completely crazy add-ins).

Using the API, we can make our own tools for converting the location of Elements to whatever coordinate system we want and this is how it is done…

The Graph

CoordinateGraph.JPG

Note: I am using Clockwork’s awesome Element.Location node to get the location of the Elements. This is very stable and I use this all the time, plus, I am very lazy and I don’t fancy writing one if there’s a really good one just sitting there!

Also Note: Dynamo uses Revit’s Internal Origin. All points will be in this Coordinate System and as mentioned earlier, this is the same as the Relative Coordinates…as they are “Relative” to the Internal Origin Point.

The Code – Point.ToRevitCoordinates (Py)

Here is the full code I used. Bear in mind that all dimensions in Revit are in Imperial feet by default (this includes point values). So, if you need this in metric, then you need to multiply accordingly. I am converting ft to mm in the code below by multiplying by 304.8.

 import clr
 import math
 clr.AddReference('ProtoGeometry')
 from Autodesk.DesignScript import Geometry as geom
 clr.AddReference("RevitServices")
 import RevitServices 
 from RevitServices.Persistence import DocumentManager
 doc = DocumentManager.Instance.CurrentDBDocument
 clr.AddReference("RevitNodes")
 import Revit
 clr.ImportExtensions(Revit.Elements)
 clr.ImportExtensions(Revit.GeometryConversion)
 clr.AddReference("RevitAPI")
 from Autodesk.Revit.DB import *
 
 # Create a list object from singleton...
 def tolist(obj1):
     if hasattr(obj1,"__iter__"): return obj1
     else: return [obj1]
 
 ################# Definitions ###################
 # Convert Point from Relative to Shared Coordinates...
 def ToSharedCoordinates(pt,iop,pbp,rot):
     # First we need to translate the point by adding the Internal Origin to the Point we're converting...
     pt = geom.Point.ByCoordinates(pt.X+iop.X, pt.Y+iop.Y, pt.Z+iop.Z)
     # Then we need to rotate this point about the Internal Origin in the opposite direction as the Project Rotation...
     pt = geom.Geometry.Rotate(pt,iop,geom.Vector.ZAxis(),rot*-1)
     return pt
 
 # Convert Point from Relative to Project Coordinates...
 def ToProjectCoordinates(pt,iop,pbp,rot):
     # First we need to Rotate the Project Base Point about the Internal Origin Point by the Project Rotation...
     pbp = geom.Geometry.Rotate(pbp,iop,geom.Vector.ZAxis(),rot)
     # Then we need to Translate the point we're converting by subtracting the Project Base Point and then adding the Internal Origin Point...
     pt = geom.Point.ByCoordinates(pt.X-pbp.X+iop.X,pt.Y-pbp.Y+iop.Y,pt.Z-pbp.Z+iop.Z)
     return pt
 
 ################# Variables ###################
 # Input Variables...
 pts = tolist(IN[0])
 
 # Internal Variables...
 pbp = None
 iop = None
 rot = 0
 # Conversion to mm...
 ft2mm = 304.8
 
 # Output Variables...
 shared = []
 project = []
 relative = []
 
 ################# Main ###################
 # Collect Project Basepoint...
 basePt = FilteredElementCollector(doc).OfCategory(BuiltInCategory.OST_ProjectBasePoint).ToElements()
 
 # Convert Project Basepoint (pbp) to DS Point...
 for e in basePt:
     # Get Project Base Points Parameter Values...
     ew = e.get_Parameter(BuiltInParameter.BASEPOINT_EASTWEST_PARAM).AsDouble()*ft2mm
     ns = e.get_Parameter(BuiltInParameter.BASEPOINT_NORTHSOUTH_PARAM).AsDouble()*ft2mm
     ele = e.get_Parameter(BuiltInParameter.BASEPOINT_ELEVATION_PARAM).AsDouble()*ft2mm
     rot = e.get_Parameter(BuiltInParameter.BASEPOINT_ANGLETON_PARAM).AsDouble()*180/math.pi    
     # Create Point from Project Base Point Values...
     pbp = geom.Point.ByCoordinates(ew,ns,ele)
 
 # Convert Internal Origin Point (iop) as DS Point...
 projPos = doc.ActiveProjectLocation.get_ProjectPosition(XYZ(0,0,0))
 iop = geom.Point.ByCoordinates(projPos.EastWest*ft2mm,projPos.NorthSouth*ft2mm,0)
 
 # Transform Input points to Shared/Project Coordinate System...
 for pt in pts:
     # Convert point to Shared Coordinates...
     shared.append(ToSharedCoordinates(pt,iop,pbp,rot))
     # Convert point to Project Coordinates...
     project.append(ToProjectCoordinates(pt,iop,pbp,rot))
     # Point is already Relative to the Internal Origin...
     relative.append(pt)
     
 OUT = shared, project, relative

 

That’s it! Looks simple, eh? Well, coordinate systems really confuse peoples brains (mine included). So, you are not alone if you are not sure what is going on in the definitions where we are adding and subtracting and rotating, it took me a few tries to get it right! There are methods to make the code simpler by adding/subtracting points without calling out their X,Y,Z values directly, but, I think this is easier to follow.

Anyway, as usual, I hope you found this useful and that it may help you out should you need to convert to Shared or Project coordinates or create your own Coordinate Parameter Writer.

Advertisement