Select linked element faces

Hey people ! It’s good to be back to the forums !
I have an issue with linked elements i’m using a user interface with datashapes i have managed to select the linked element i want to use but i can’t seem to get its faces i’ve tried to get the geometry too but i keep getting the same error message ! Any help would be appreciated !

@deejaypein

workaround are bimorphnodes

# links
linked_docs = FilteredElementCollector(doc).OfCategory(BuiltInCategory.OST_RvtLinks).WhereElementIsNotElementType().ToElements()


# linked file
link_document = []

for link in linked_docs:
    link_doc = link.GetLinkDocument()
    link_document.append(link_doc)

link = link_document[0]

# walls
linked_walls = FilteredElementCollector(link).OfCategory(BuiltInCategory.OST_Walls).WhereElementIsNotElementType().ToElements()


faces_of_walls = []

for elem in linked_walls: #for every element
    edges = [] #an empty list for the edges to process
    processed = [] #the list of processed edges which we want to keep
    geos = elem.get_Geometry(Options()) #the geometry
    for geo in geos: #for every geometry found
        if geo.__class__ == DB.Solid: #if the geomtry is a solid
            faces = geo.Faces #get the faces
            for f in faces:
                faces_of_walls.append(f)

OUT = faces_of_walls

i think that code can also be a starting point. It return all faces of a wall, from walls in a linked file.

3 Likes

The Bimorph nodes worke just fine ! Thanks for your help !

1 Like

Is there a way to select the face i need from a linked element without a collector it would be so helpful

you can use pickobject methode

selection = uidoc.Selection #type: Selection
# links
linked_docs = FilteredElementCollector(doc).OfCategory(BuiltInCategory.OST_RvtLinks).WhereElementIsNotElementType().ToElements()


# linked file
link_document = []

for link in linked_docs:
    link_doc = link.GetLinkDocument()
    link_document.append(link_doc)

link = link_document[0]

# get linked wall
#Prompt user to Select a Linked Element
ref_selected_elements = selection.PickObjects(ObjectType.LinkedElement,"Select Linked Element") #type: Reference

#Get Linked Element ID from Resulting Reference
ref_lnk_id = [ref_selected_element.LinkedElementId for ref_selected_element in ref_selected_elements]

#Get RevitLinkInstance from Selection using ElementID
selected_elements = [doc.GetElement(ref) for ref in ref_selected_elements]

faces_of_walls = []

for elem in selected_elements: #for every element
    edges = [] #an empty list for the edges to process
    processed = [] #the list of processed edges which we want to keep
    geos = elem.get_Geometry(Options()) #the geometry
    for geo in geos: #for every geometry found
        if geo.__class__ == DB.Solid: #if the geomtry is a solid
            faces = geo.Faces #get the faces
            for f in faces:
                faces_of_walls.append(f)

OUT = faces_of_walls

you have to refactor it, i choose multi-selection.

1 Like

Hi,

Another solution is to directly select the faces of the linked model.

select_linked_faces

code Python (compatible with IronPython3 or CPython3, except CPython3 in Revit 2024)

import clr
import sys
import System
from System.Collections.Generic import List
clr.AddReference('ProtoGeometry')
from Autodesk.DesignScript.Geometry import *
import Autodesk.DesignScript.Geometry as DS

clr.AddReference('RevitAPI')
import Autodesk
from Autodesk.Revit.DB import *
import Autodesk.Revit.DB as DB

clr.AddReference('RevitAPIUI')
from Autodesk.Revit.UI import *
from Autodesk.Revit.UI.Selection import *

clr.AddReference('RevitNodes')
import Revit
clr.ImportExtensions(Revit.GeometryConversion)

clr.AddReference('RevitServices')
import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager
doc = DocumentManager.Instance.CurrentDBDocument
uiapp = DocumentManager.Instance.CurrentUIApplication
uidoc = uiapp.ActiveUIDocument


class FaceSelection:
    def __new__(cls, *args, **kwargs):
        cls.args = args
        # name of namespace : "CustomNameSpace" + "_" + shortUUID (8 characters)
        # IMPORTANT NOTE Each time you modify this class, you must change the namesapce name.
        cls.__namespace__ = "FaceSelection_tEfYX0DHE"
        try:
            # 1. Try to import the module and class. If it already exists, you've probably already created it once, so you can use it.
            module_type = __import__(cls.__namespace__)
            return module_type._InnerClassInterface(*cls.args)
        except ImportError as ex:
            class _InnerClassInterface(ISelectionFilter) :
                __namespace__ = cls.__namespace__

                def __init__(self):
                    super().__init__() 

                def AllowElement(self, e):
                    return True

                def AllowReference(self, ref, point):
                    if ref.ElementReferenceType == ElementReferenceType.REFERENCE_TYPE_SURFACE:
                        return True
                    else:
                        return False
                    
            return _InnerClassInterface(*cls.args)
        
lst_DSface = []
#
TaskDialog.Show("Selection", "Pick Several Faces")
refs = uidoc.Selection.PickObjects(ObjectType.PointOnElement, FaceSelection(), "Pick Several Faces")
for ref in refs:
    # get Face Geometry
    sel_elem = doc.GetElement(ref)
    if isinstance(sel_elem, RevitLinkInstance):	
        tf1 = sel_elem.GetTotalTransform()
        linkDoc = sel_elem.GetLinkDocument()
        elem = linkDoc.GetElement(ref.LinkedElementId)
        if isinstance(elem, FamilyInstance):
            tf2 = elem.GetTotalTransform()
            tf1 = tf1.Multiply(tf2)
        face_ref2 = ref.CreateReferenceInLink()
        face = elem.GetGeometryObjectFromReference(face_ref2)
        lst_DSface.append(face.ToProtoType()) 
    else:
        elem = sel_elem
        face = elem.GetGeometryObjectFromReference(ref)
        lst_DSface.append(face.ToProtoType()) 

OUT = lst_DSface
4 Likes

Thanks for the reply ! This is for sure helpful but i need to prompt the user to select the face directly on the revit linked model not the element and than collect the faces

This is exactly what i was looking for thank your for the contribution

1 Like

Hello again good sir ! i’m having a bit of a problew with the surface i get from the selected face .
It seems i can’t use it to host a family type. i’m getting this error

Hi @deejaypein PS the only node i know there get the linked surface/reference is that one @Draxl_Andreas show from bimorph…another way could probably be with genius loci…

2 Likes

Here is an update version with 2 lists at the output

  • list Surface
  • list Reference

import clr
import sys
import System
from System.Collections.Generic import List
clr.AddReference('ProtoGeometry')
from Autodesk.DesignScript.Geometry import *
import Autodesk.DesignScript.Geometry as DS

clr.AddReference('RevitAPI')
import Autodesk
from Autodesk.Revit.DB import *
import Autodesk.Revit.DB as DB

clr.AddReference('RevitAPIUI')
from Autodesk.Revit.UI import *
from Autodesk.Revit.UI.Selection import *

clr.AddReference('RevitNodes')
import Revit
clr.ImportExtensions(Revit.GeometryConversion)

clr.AddReference('RevitServices')
import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager
doc = DocumentManager.Instance.CurrentDBDocument
uiapp = DocumentManager.Instance.CurrentUIApplication
uidoc = uiapp.ActiveUIDocument


class FaceSelection:
    def __new__(cls, *args, **kwargs):
        cls.args = args
        # name of namespace : "CustomNameSpace" + "_" + shortUUID (8 characters)
        # IMPORTANT NOTE Each time you modify this class, you must change the namesapce name.
        cls.__namespace__ = "FaceSelection_tEfYX0DHE"
        try:
            # 1. Try to import the module and class. If it already exists, you've probably already created it once, so you can use it.
            module_type = __import__(cls.__namespace__)
            return module_type._InnerClassInterface(*cls.args)
        except ImportError as ex:
            class _InnerClassInterface(ISelectionFilter) :
                __namespace__ = cls.__namespace__

                def __init__(self):
                    super().__init__() 

                def AllowElement(self, e):
                    return True

                def AllowReference(self, ref, point):
                    if ref.ElementReferenceType == ElementReferenceType.REFERENCE_TYPE_SURFACE:
                        return True
                    else:
                        return False
                    
            return _InnerClassInterface(*cls.args)
        
lst_DSface = []
lst_ref_face = []
rvt_link_instance = []
#
TaskDialog.Show("Selection", "Pick Several Faces")
refs = uidoc.Selection.PickObjects(ObjectType.PointOnElement, FaceSelection(), "Pick Several Faces")
for ref in refs:
    # get Face Geometry
    sel_elem = doc.GetElement(ref)
    if isinstance(sel_elem, RevitLinkInstance):    
        tf1 = sel_elem.GetTotalTransform()
        linkDoc = sel_elem.GetLinkDocument()
        elem = linkDoc.GetElement(ref.LinkedElementId)
        if isinstance(elem, FamilyInstance):
            tf2 = elem.GetTotalTransform()
            tf1 = tf1.Multiply(tf2)
        face_ref2 = ref.CreateReferenceInLink()
        face = elem.GetGeometryObjectFromReference(face_ref2)
        lst_DSface.append(face.ToProtoType()[0]) 
        lst_ref_face.append(ref)
        #print(ref.ConvertToStableRepresentation(doc))


OUT = lst_DSface, lst_ref_face

then you can use the ‘FamilyInstance.ByReference’ node as mentioned by @sovitek

3 Likes

awesome as always :wink: thanks Cyril :wink:

and a way with pick points, could probably work as well

Revit_ynaazG18kf

1 Like