Apr 8, 2024

Convert Coordinates in Revit API [Internal, Project, Survey]

Learn how to convert Coordinates in Revit API.

Coordinate Systems in Revit

🚧 Written Post coming later! 🚧
But you can get the code now ;)


⌨️ Point Converter

# -*- coding: utf-8 -*-
__title__ = 'CoordSystems'

# Imports
from Autodesk.Revit.DB import *

# ╦  ╦╔═╗╦═╗╦╔═╗╔╗ ╦  ╔═╗╔═╗
# ╚╗╔╝╠═╣╠╦╝║╠═╣╠╩╗║  ║╣ ╚═╗
#  ╚╝ ╩ ╩╩╚═╩╩ ╩╚═╝╩═╝╚═╝╚═╝ VARIABLES
#--------------------------------------------------
uidoc     = __revit__.ActiveUIDocument
doc       = __revit__.ActiveUIDocument.Document  #type: Document

# ╔═╗╦ ╦╔╗╔╔═╗╔╦╗╦╔═╗╔╗╔╔═╗
# ╠╣ ║ ║║║║║   ║ ║║ ║║║║╚═╗
# ╚  ╚═╝╝╚╝╚═╝ ╩ ╩╚═╝╝╚╝╚═╝ Functions
#--------------------------------------------------
def convert_internal_units(value, get_internal=True):
    # type: (float, bool) -> float
    """Function to convert Internal units to meters or vice versa.
    :param value:        Value to convert
    :param get_internal: True - Convert TO Internal / Flase - Convert FROM Internal
    :return:             Length in Internal units or Meters."""
    if get_internal:
        return UnitUtils.ConvertToInternalUnits(value, UnitTypeId.Meters)
    return UnitUtils.ConvertFromInternalUnits(value, UnitTypeId.Meters)


# ╔═╗╦  ╔═╗╔═╗╔═╗
# ║  ║  ╠═╣╚═╗╚═╗
# ╚═╝╩═╝╩ ╩╚═╝╚═╝ CLASS
#--------------------------------------------------
class PointConverter:
    pt_internal = None
    pt_survey   = None
    pt_project  = None

    def __init__(self, x, y, z, coord_sys='internal', input_units = 'm'):
        # type:( float, float, float, str, str)
        """ PointConverter - Convert coordinate into desired coordinate system.
        Args:
            x : Float in meters representing the x-coordinate.
            y : Float in meters representing the y-coordinate.
            z : Float in meters representing the z-coordinate.
            coord_sys : Coordinate System of provided coordinates.
                        Possible values: 'internal'/'project'/'survey'
            input_units : Float in meters representing the z-coordinate.
                          Possible Values: 'm' / 'ft' """

        # Get Systems Transform
        srvTrans  = self.GetSurveyTransform()
        projTrans = self.GetProjectTransform()


        # Convert to Internal Units
        if input_units == 'm':
            x = convert_internal_units(x, get_internal=True) # Convert Units to Internal
            y = convert_internal_units(y, get_internal=True) # Convert Units to Internal
            z = convert_internal_units(z, get_internal=True) # Convert Units to Internal

        # 1️⃣INTERNAL COORDINATE SYSTEM
        if coord_sys.lower() == 'internal':
            self.pt_internal = XYZ(x, y, z)
            self.pt_survey   = self.ApplyInverseTransformation(srvTrans , self.pt_internal)
            self.pt_project  = self.ApplyInverseTransformation(projTrans, self.pt_internal)

        # 2️⃣PROJECT COORDINATE SYSTEM
        elif coord_sys.lower() == 'project':
            self.pt_project    = XYZ(x, y, z)
            self.pt_internal   = self.ApplyTransformation(projTrans, self.pt_project)
            self.pt_survey     = self.ApplyInverseTransformation(srvTrans, self.pt_internal)

        # 3️⃣SURVEY COORDINATE SYSTEM
        elif coord_sys.lower() == 'survey':
            self.pt_survey     = XYZ(x, y, z)
            self.pt_internal   = self.ApplyTransformation(srvTrans, self.pt_survey)
            self.pt_project     = self.ApplyInverseTransformation(projTrans, self.pt_internal)

        else: raise Exception("Wrong argument value for 'coord_sys' in PointConverter class.")

    #⛑ HELPING METHODS
    def GetSurveyTransform(self):
        """Gets the Active Project Locations Transform (Survey)."""
        return doc.ActiveProjectLocation.GetTotalTransform()

    def GetProjectTransform(self):
        """Get the Project Base Points Transform."""
        basePtLoc = next((l for l in FilteredElementCollector(doc) \
                         .OfClass(ProjectLocation) \
                         .WhereElementIsNotElementType() \
                         .ToElements() if l.Name in ['Project', 'Projekt']), None)
        return basePtLoc.GetTotalTransform()

    def ApplyInverseTransformation(self, t, pt):
        """Applies the inverse transformation of
        the given Transform to the given point."""
        return t.Inverse.OfPoint(pt)

    def ApplyTransformation(self, t, pt):
        """Applies the transformation of
        the given Transform to the given point."""
        return t.OfPoint(pt)


Author = 'Erik Frits'


How to use it?

# ╔╦╗╔═╗╦╔╗╔
# ║║║╠═╣║║║║
# ╩ ╩╩ ╩╩╝╚╝
# EXAMPLE ON HOW TO USE:

# 😉 Helper Function
def print_coord_in_m(pt, prefix=""):
    #type: (XYZ, str)
    """Helper Function to display Point Coordinates
    in Meters to compare to Coordinates displayed in Revit."""
    x = round(convert_internal_units(pt.X, get_internal=False), 4)
    y = round(convert_internal_units(pt.Y, get_internal=False), 4)
    z = round(convert_internal_units(pt.Z, get_internal=False), 4)
    # print(prefix, 'N/S:{}'.format(y), 'E/W:{}'.format(x), 'Elev:{}'.format(z))
    print(prefix, 'X:{}'.format(x), 'Y:{}'.format(y), 'Z:{}'.format(z))
# --------------------------------------------------------------

# 1️⃣ Define Coordinates Manually
# X = 0    # EW Coordinate
# Y = 0    # NS Coordinate
# Z = 0    # Elevation

# 1️⃣ Pick Point
picked_point = uidoc.Selection.PickPoint()
X = picked_point.X
Y = picked_point.Y
Z = picked_point.Z

# 2️⃣ Create PointConverter instance
converter = PointConverter(X, Y, Z, coord_sys='internal', input_units='ft')

# 3️⃣ Converted Points
pt_internal = converter.pt_internal
pt_project  = converter.pt_project
pt_survey   = converter.pt_survey

# 👀 Display Results
print_coord_in_m(pt_internal, prefix='Internal: ')
print_coord_in_m(pt_project,  prefix='Project: ')
print_coord_in_m(pt_survey,   prefix='Survey: ')

Want to Learn More?

🔥 Amazing Revit API Resources!

Join Revit API

Newsletter Today!

Join Us!

which is already read by 4500+ people!

Get short Revit API Lessons and Tips directly in your mail!