Raybouncing in Pyrevit & unit conversion

hi all,

i’m trying to make a script to calculated the room heights in a linked model using raybounce technique.
The raytracing seems to work but something is off with how the points are being recalculated to internal units and back so that it gives completly wrong info.

i’m using a simple generic block family to indicate the calculation points:
before the units convertion and after


here is my Code where i’m at:

import sys
sys.path.append(r'H:\\_GROEPEN\\CAD\\DEV\\Tools\\CMRP')

from pyrevit import script
from pyrevit import UI
from pyrevit import revit
from Autodesk.Revit.UI import *
from Autodesk.Revit.UI.Selection import *
from Autodesk.Revit.DB import *
from Autodesk.Revit.DB.Structure import StructuralType

from CMRPGUI import *
from CMRP import *

# Doc & App
# -----------------------------------------------------------------------
doc = revit.doc
uidoc = revit.uidoc

links = link_selection(doc)

room_points = []
room_Id = []

for link in links:
        link = link.GetLinkDocument()
        rooms = FilteredElementCollector(link).OfCategory(BuiltInCategory.OST_Rooms).ToElements()
        # Get rooms information from linked model
        # -----------------------------------------------------------------------
        for room in rooms:
                if isinstance(room.Location, LocationPoint):
                        room_points.append(room.Location.Point)
                        room_Id.append(room.UniqueId)


def get_type_by_name(type_name):
    param_type = ElementId(BuiltInParameter.ALL_MODEL_TYPE_NAME)
    f_param = ParameterValueProvider(param_type)
    evaluator = FilterStringEquals()
    f_rule = FilterStringRule(f_param, evaluator, type_name, True)
    
    filter_type_name = ElementParameterFilter(f_rule)
    
    return FilteredElementCollector(doc).WherePasses(filter_type_name).WhereElementIsElementType().FirstElement()


with Transaction(doc, "Place Generic Model Instances") as t:
    t.Start()
    symbol = get_type_by_name('test-Type1')

    if not symbol.IsActive:
        symbol.Activate()

    for p in room_points:
        doc.Create.NewFamilyInstance(p, symbol, StructuralType.NonStructural)
    t.Commit()


views = FilteredElementCollector(doc).OfClass(View).WhereElementIsNotElementType().ToElements()
for x in views:
    if x.Name == "ray3D":
        view = x
        break

#Document UI Units
try:
	UIunit = Document.GetUnits(doc).GetFormatOptions(UnitType.UT_Length).DisplayUnits
except:
	UIunit = Document.GetUnits(doc).GetFormatOptions(SpecTypeId.Length).GetUnitTypeId()

# translation_vector = XYZ(0, 0, 1000)

# # Translate each point in room_points so that it is above the floor
# for i in room_points:
#     i = i.Add(translation_vector)

# #Inputs : Points, Direction, 3D View
if isinstance(room_points,list):
	points = [XYZ(UnitUtils.ConvertToInternalUnits(i.X,UIunit),UnitUtils.ConvertToInternalUnits(i.Y,UIunit),UnitUtils.ConvertToInternalUnits(i.Z,UIunit)) for i in room_points]
else:
	points = [XYZ(UnitUtils.ConvertToInternalUnits(room_points.X,UIunit),UnitUtils.ConvertToInternalUnits(room_points.Y,UIunit),UnitUtils.ConvertToInternalUnits(room_points.Z,UIunit))]

direction = XYZ(0,0,1)

ex = []
pts = []
elems = []

ri = ReferenceIntersector(view)
ri.FindReferencesInRevitLinks = True

# # Find nearest reference for each point and compute height
heights = []

# Find nearest reference for each point and compute height
with Transaction(doc, "Place Generic Model Instances") as t:
    t.Start()

    for p in points:
        # Place a family instance at the original point
        instance1 = doc.Create.NewFamilyInstance(p, symbol, StructuralType.NonStructural)

        ref = ri.FindNearest(p, direction)
        if ref is not None:
            refel = ref.GetReference()
            link_instance = doc.GetElement(refel.ElementId)
            try:
                elem = link_instance.GetLinkDocument().GetElement(refel.LinkedElementId)
                print(elem.Id)
                refp = ref.GetReference().GlobalPoint

                # Place a family instance at the detected reference point
                instance2 = doc.Create.NewFamilyInstance(refp, symbol, StructuralType.NonStructural)

                height = UnitUtils.ConvertFromInternalUnits(refp.Z, UIunit) - UnitUtils.ConvertFromInternalUnits(p.Z, UIunit)
                heights.append(height)
                print("Element: {}, Height: {}".format(elem.Name, height))
            except:
                pass
        else:
            heights.append(None)
            print("No reference found")

    t.Commit()

print(heights)

Hey there,

I see in your code that your converting the units of the points you get from the rooms, but I don’t think that transforms the locations to the correct coordinate system. I believe that only changes the units, i.e. mm to in.

I’ve done something similar where I find intersections in a linked structural model using the IntersectWithCurve method that solids have. One thing I had to do, that you can try, is transforming all your points. Try using the transform from the linked file to translate the points to the correct locations.

Here is some pieces of my code for reference.
I transform a curve in the model to the linked documents coordinate system then find the intersection with the slabs. Then I do the inverse transform to convert the intersection curve back to correct coordinate system.

def get_linked_file(doc):
    # type: (Document) -> (RevitLinkInstance, Document)
    l_doc = None
    l_instance = None
    link_instances = tuple(FilteredElementCollector(doc).OfClass(RevitLinkInstance))  # type: [RevitLinkInstance]
    for link in link_instances:
        link_name = link.Name.lower()
        if 'struct' in link_name:
            l_instance = link
            l_doc = link.GetLinkDocument()
    if l_doc is None:
        print('Ensure Linked Structural Model Contains "STRUCT" (Case Is Ignored)')
        raise SystemExit
    else:
        return l_instance, l_doc

linked_instance, linked_document = get_linked_file(DOC)
link_transform = linked_instance.GetTotalTransform()
intersect_curve = Curve.CreateTransformed(curve, transform.Inverse)
curve_intersection = tuple(solid.IntersectWithCurve(intersect_curve, solid_opt))
intersect_curve = SlabIntersection(Curve.CreateTransformed(curve_intersection[0], transform))

I cut out a lot of the code to highlight only the relevant parts, but I hope this helps you out.