Select Linked Elements

While working with linked models you will realize that selecting elements will be a bit trickier than usual. But don't worry, we will cover it in this lesson!

Select Linked Elements

While working with linked models you will realize that selecting elements will be a bit trickier than usual. But don't worry, we will cover it in this lesson!

Summary

Select Elements from Linked Models?

We covered selection for our regular projects.

But when we work with linked model we need to make a few things differently. And while it's not a rocket science, there are a few things I wanted to show you to save you from another headache!

Let's look at how to pick objects from linked models.

PickObjects for Linked Elements

Firstly, let's remember how do we PickObjects.
As you remember this method has a few variations with or without ISelectionFilter, but all of them require ObjectType Enumeration.

And one of the Members is LinkedElement. That's exactly what we will need.

So let's write a short snippet to PickObjects and provide ObjectType.LinkedElement.

#🔷 PickObjects
from Autodesk.Revit.UI.Selection import ObjectType

ref_picked_objects = uidoc.Selection.PickObjects(ObjectType.LinkedElement)
picked_objects     = [doc.GetElement(ref) for ref in ref_picked_objects]

for el in picked_objects:
    print(el)

💡 Keep in mind that it returns a List[Reference], so you need to convert to elements with GetElement.

👀Now let's look at what is being printed in the console.

We got a bunch of RevitLinkInstances.
That's not exactly what we expected…

Get Element from RevitLinkInstances

So how do we convert RevitLinkInstance to an actual element?

First of all the elements that we have selected are located in another Linked Project. So we need to use Document instance of that specific project instead when we use doc.GetElement !

And here is how we do that.

1️⃣ PickObjects
2️⃣ Get RevitLinkInstance with doc.GetElement
3️⃣ Get Linked Doc by using GetLinkDocument
4️⃣ Get Linked Element by using GetElementwith ref.LinkedElementId

👇 So here is the code snippet to do all that!

#🔷 PickObjects
from Autodesk.Revit.UI.Selection import ObjectType
ref_picked_objects = uidoc.Selection.PickObjects(ObjectType.LinkedElement)

# Read Picked Elements
for ref in ref_picked_objects:
    revit_link_instance = doc.GetElement(ref)
    linked_doc          = revit_link_instance.GetLinkDocument()
    linked_elem         = linked_doc.GetElement(ref.LinkedElementId)
    print(linked_elem.Name)

And when we use it, that's the results we can get.

So that's what you need to Pick Linked Elements.

But what about using ISelectionFilter for that?

ISelectionFilter for Linked Elements

Now let's have a quick reminder of ISelectionFilter.

We need to create a custom class and inherit this Interface. There are 2 methods we can override to control what is allowed to be selected:

Last time we only used AllowElement, because we worked with the main Document. This time we will have to use AllowReference as well, because Linked Elements are references to the linked document.

Here is a template of ISelectionFilter, we will break down AllowReference in a moment.

# ISelectionFilter - Syntax
class ISelectionFilter_Example(ISelectionFilter):

    def AllowElement(self, element):
        # Add Conditional Statement here using arguments
        return True

    def AllowReference(self, reference, position):
        # Add Conditional Statement Here
        return True

💡 As you remember these methods have to return True/False to filter out elements which are allowed to be selected. And remember how we got Linked Elements just a moment ago, because we will have to do the same thing here as well.

💡 Also, notice that AllowReference has different arguments!.

Let's make a snippet to only pick linked rooms. Here is how we would do that:

Learn by Doing: Pick Linked Rooms

We will start by creating an ISelectionFilter for Linked Rooms.

We will set AllowElements to True, and then configure AllowReference

Inside, we will need to access our linked elements similar as I showed you earlier.
And then by getting actual elements in linked model we can start making our tests and see if these elements are Rooms or anything else you would like to check.

Here is the Snippet for ISelectionFilter to Pick Linked Rooms.

from Autodesk.Revit.DB.Architecture import Room
from Autodesk.Revit.UI.Selection    import ISelectionFilter, ObjectType

class LinkedRoomSelectionFilter(ISelectionFilter):
    def AllowElement(self, element):
        return True

    def AllowReference(self, reference, position):
        revit_link_instance = doc.GetElement(reference.ElementId)
        linked_doc          = revit_link_instance.GetLinkDocument()
        linked_elem         = linked_doc.GetElement(reference.LinkedElementId)

        if type(linked_elem) == Room:
            return True

Now let's use that filter together with PickObjects.

#🔷 PickObjects + ISelectionFilter
ref_picked_objects = uidoc.Selection.PickObjects(ObjectType.LinkedElement,
                      LinkedRoomSelectionFilter()) #type: List[Reference]

# Read Picked Elements
for ref in ref_picked_objects:
    revit_link_instance = doc.GetElement(ref)
    linked_doc          = revit_link_instance.GetLinkDocument()
    linked_elem         = linked_doc.GetElement(ref.LinkedElementId)
    print(linked_elem.Name)

And that's how we can Pick Linked Objects with Revit API !

You will see that we can't select anything except for rooms in the Linked Project.

Final Snippet

Happy Coding!
I hope you find it useful in your future tools.

Here is the Final snippet, together!

from Autodesk.Revit.DB.Architecture import Room
from Autodesk.Revit.UI.Selection    import ISelectionFilter, ObjectType

class LinkedRoomSelectionFilter(ISelectionFilter):
    def AllowElement(self, element):
        return True

    def AllowReference(self, reference, position):
        revit_link_instance = doc.GetElement(reference.ElementId)
        linked_doc          = revit_link_instance.GetLinkDocument()
        linked_elem         = linked_doc.GetElement(reference.LinkedElementId)

        if type(linked_elem) == Room:
            return True

#🔷 PickObjects + ISelectionFilter
ref_picked_objects = uidoc.Selection.PickObjects(ObjectType.LinkedElement,
                      LinkedRoomSelectionFilter()) #type: List[Reference]

# Read Picked Elements
for ref in ref_picked_objects:
    revit_link_instance = doc.GetElement(ref)
    linked_doc          = revit_link_instance.GetLinkDocument()
    linked_elem         = linked_doc.GetElement(ref.LinkedElementId)
    print(linked_elem.Name)
💟 Credits to Early-Birds

I want to say huge thanks to a few Early-Birds in the course for this lesson:

  • Mohamed Bedair

  • Andreas Draxl

  • Nikita

They started discussing this topic in the community and shared the code that we all can use now. Thanks guys, you are the reason we have this lesson now!

⌨️Happy Coding!

⭐Bonus Snippet

Now let's have a look at a really cool tool that Mohamed Bedair has started after the lesson.

This script has a cool functionality, it will ask user:

  • Which Linked Revit Project can be selected?

  • What Categories of Elements can be selected?

💡Imagine working on a project with many linked Revit files, and you need to select certain categories from a certain Revit project. That tool will be a game changer.

If you are excited about this modification, tell thanks to Mohamed Bedair for sharing it with everyone!

P.S. I've refactored it a little to my style, but the main code is from Mohamed!

# -*- coding: utf-8 -*-
__title__     = "Link Inspector"
__author__    = "Mohamed Bedair"
__doc__       = """Version = 1.0
Date    = 21.12.2023
_____________________________________________________________________
Description:
Select Linked Elements based on selected in UI:
- Revit Linked Project
- Element Categories 
_____________________________________________________________________
How-to:
-> Run the script
-> Select Linked Revit Project
-> Select Revit Categories
-> Pick Linked Elements matching selected criteria
_____________________________________________________________________
Last update:
- [21.12.2023] - 1.0 RELEASE
_____________________________________________________________________
Author: Mohamed Bedair"""
#--------------------------------------------------------------------
#⬇️ IMPORTS
from Autodesk.Revit.DB import *
from Autodesk.Revit.UI.Selection import *
from pyrevit import forms


#--------------------------------------------------------------------
#📦VARIABLES
doc         = __revit__.ActiveUIDocument.Document   #type: Document
uidoc       = __revit__.ActiveUIDocument
selection   = uidoc.Selection                       #type: Selection


# MAIN
#--------------------------------------------------------------------
#👉 Get All Linked Documents
all_rvt_links  = FilteredElementCollector(doc)\
                    .OfCategory(BuiltInCategory.OST_RvtLinks)\
                    .WhereElementIsNotElementType()\
                    .ToElements()       #type: List[RevitLinkInstance]

# Prepare Dict {doc.Title: RvtLinkInstance}
dict_rvt_links = {lnk.GetLinkDocument().Title : lnk for lnk in all_rvt_links}
link_names     = dict_rvt_links.keys()

#📰 UI - Select Linked Revit Project
selected_lnk_name = forms.ask_for_one_item(link_names,
                                    default=link_names[0],
                                    prompt="Select Link",
                                    title="Link Selection")
selected_lnk = dict_rvt_links[selected_lnk_name]
#--------------------------------------------------------------------
#  UI - Select Categories
all_cats    = sorted([cat.Name for cat in doc.Settings.Categories])
chosen_cats = forms.SelectFromList.show(all_cats, title="Choose Categories",
                                                  width=300,
                                                  button_name="Select Categories",
                                                  multiselect=True)

#--------------------------------------------------------------------
#🔎 Create ISelectionFilter
class LinkedElemSelectionFilter(ISelectionFilter):
    def AllowElement(self, element):
        return True

    def AllowReference(self, reference, position):
        linked_doc          = selected_lnk.GetLinkDocument()
        linked_elem         = linked_doc.GetElement(reference.LinkedElementId)
        if linked_elem.Category.Name in chosen_cats:
            return True


#--------------------------------------------------------------------
#👉 Pick Linked Objects
ref_picked_objects = selection.PickObjects(ObjectType.LinkedElement,LinkedElemSelectionFilter())

for ref in ref_picked_objects:
    linked_doc          = selected_lnk.GetLinkDocument()
    linked_elem         = linked_doc.GetElement(ref.LinkedElementId)
    print(linked_elem.Name)

#--------------------------------------------------------------------
# Keep improving this code!

HomeWork

Give these snippet a try.

Additionally, try to modify it a little to select different kind of linked elements and see how it works.

💪 Theory is great, but nothing beats practice to learn something!

⌨️ Happy Coding!

Questions:

How can I limit it to certain LinkedModel only based on Name?

How can I limit it to certain LinkedModel only based on Name?

Discuss the lesson:

P.S. Sometimes this chat might experience connection issues.
Please be patient or join via Discord app so you can get the most out of this community and get access to even more chats.

P.S. Sometimes this chat might experience connection issues.
Please be patient or join via Discord app so you can get the most out of this community and get access to even more chats.

© 2023-2024 EF Learn Revit API

© 2023-2024 EF Learn Revit API

© 2023-2024 EF Learn Revit API