Assemblies types

Hello,
I try to make 3 scripts that deals with assemblies but fortunately i failed. First script suppose to tag all assemblies of same type (Wall Assembles, Structural Column Assemblies, etc.), second script should select all assemblies of same type and third scrip to disassemble all assemblies of same type. I can’t find a way to determine correctly witch is witch type of assemblies. I can’t find all this types on Revit API, only assemblies as general. Can someone tell me a way i can deal with this?

Examples of what you already have would help.
in the meantime, have a look at all the methods available for

assembly instances

ApiDocs.co · Revit · AssemblyInstance Members

and

assembly types

ApiDocs.co · Revit · AssemblyType Members

usually when you have an instance of an element in hand you can get its type doing so

type_id = elem.GetTypeId()
element_type = doc.GetElement(type_id)

ref: ApiDocs.co · Revit · GetElement Method (ElementId)

Hello,
This is the code for script that should select assemblies based on their types

from pyrevit import script
from pyrevit import revit, DB
from pyrevit import forms
from Autodesk.Revit.UI import TaskDialog
from System.Collections.Generic import List  # Import List for .NET conversion

# Category options for user to select, including Structural Framing, Structural Foundation, Generic Model
CATEGORY_OPTIONS = sorted([
    "Wall Assemblies", 
    "Structural Column Assemblies", 
    "Structural Framing Assemblies",
    "Structural Foundation Assemblies", 
    "Generic Model Assemblies"
])

# Function to get selected categories from user
def get_selected_categories():
    return forms.SelectFromList.show(CATEGORY_OPTIONS, multiselect=True, title='Select Categories to Select Elements')

# Function to check if an assembly contains elements from the selected category
def is_valid_assembly(assembly, category_name):
    member_ids = assembly.GetMemberIds()
    if not member_ids:
        return False

    category_map = {
        "Wall Assemblies": DB.BuiltInCategory.OST_Walls,
        "Structural Column Assemblies": DB.BuiltInCategory.OST_StructuralColumns,
        "Structural Framing Assemblies": DB.BuiltInCategory.OST_StructuralFraming,
        "Structural Foundation Assemblies": DB.BuiltInCategory.OST_StructuralFoundation,
        "Generic Model Assemblies": DB.BuiltInCategory.OST_GenericModel
    }
    
    target_category_id = DB.Category.GetCategory(revit.doc, category_map.get(category_name)).Id
    return any(doc.GetElement(id).Category.Id == target_category_id for id in member_ids)

# Function to collect elements from assemblies that match selected categories
def collect_elements_from_assemblies(assemblies, valid_categories):
    selected_elements = []
    
    for assembly in assemblies:
        # Check if the assembly contains elements from any valid category
        for category in valid_categories:
            if is_valid_assembly(assembly, category):
                member_ids = assembly.GetMemberIds()
                for element_id in member_ids:
                    element = doc.GetElement(element_id)
                    selected_elements.append(element)
    
    return selected_elements

# Main process starts here
doc = revit.doc
uidoc = revit.uidoc
active_view = doc.ActiveView

# Get all assemblies visible in the current view
assemblies = DB.FilteredElementCollector(doc).OfCategory(DB.BuiltInCategory.OST_Assemblies).WhereElementIsNotElementType().ToElements()
if not assemblies:
    TaskDialog.Show("Error", "No assemblies are visible in the current view. Script canceled.")
    script.exit()

# Get selected categories and check for valid assemblies
selected_categories = get_selected_categories()
if not selected_categories:
    TaskDialog.Show("Cancelled", "No categories selected. Script canceled.")
    script.exit()

valid_categories = [category for category in selected_categories if any(is_valid_assembly(assembly, category) for assembly in assemblies)]
if not valid_categories:
    TaskDialog.Show("No Valid Categories", "No valid categories to select.")
    script.exit()

# Collect elements from all assemblies that match the selected categories
selected_elements = collect_elements_from_assemblies(assemblies, valid_categories)

# If no elements were found, notify the user
if not selected_elements:
    TaskDialog.Show("No Elements Found", "No elements from the selected assemblies were found.")
    script.exit()

# Convert Python list of ElementIds to .NET List[ElementId]
element_ids = [element.Id for element in selected_elements]
element_ids_net = List[DB.ElementId](element_ids)

# Allow user to select these elements in Revit
uidoc.Selection.SetElementIds(element_ids_net)

# Notify user of selection
TaskDialog.Show("Elements Selected", "{0} elements from the selected assemblies have been selected.".format(len(selected_elements)))

If a method work for this it should work for all 3 scripts. At the moment script select all element present in an assemblies based in a type categories. I tried to make it identify assemblies types based on elements inside assemblies, if it an assemblies contain walls it is a Wall Assemblies. I’m in a look for a simpler and more corect way to determine assemblies types

If there is a random element from a different category included when assembly is created, it could use that other category for the assembly type. I completely disregard the assembly category types for this reason.

Since you are trying to get the assembly members and not the assemblies themselves, another approach might be to collect elements of the specified categories if element.AssemblyInstanceId is not null or ElementId.InvalidElementId

So its valid if it is a member of any type of assembly, even if the assembly type is something different

1 Like

Hello,
After a few failed attempts I manage to make all 3 scripts work. Here are the code for all 3 scripts.

Tag assemblies

from pyrevit import revit, DB, forms
from Autodesk.Revit.UI import TaskDialog

# Get the active document and active view
doc = revit.doc
active_view = doc.ActiveView

# Create a dictionary to store assembly instance IDs and their types
assembly_data = {}

# Collect all assembly instances visible in the active view
visible_assemblies = (
    DB.FilteredElementCollector(doc, active_view.Id)
    .OfCategory(DB.BuiltInCategory.OST_Assemblies)
    .WhereElementIsNotElementType()
    .ToElements()
)

# Extract assembly types and store in dictionary
for assembly in visible_assemblies:
    # Get the type ID of the assembly
    type_id = assembly.GetTypeId()

    # Ensure that the type ID is valid
    if type_id and type_id.IntegerValue != -1:
        # Retrieve the element type using the type ID
        element_type = doc.GetElement(type_id)

        # Check if the element type is valid
        if element_type:
            try:
                # Attempt to access the Name property (this is the usual property for types)
                assembly_type_name = element_type.Name
            except AttributeError:
                # If Name is not available, try other properties
                assembly_type_name = "Name property not available"
                if hasattr(element_type, "FamilyName"):
                    assembly_type_name = element_type.FamilyName  # If FamilyName is available
                elif hasattr(element_type, "TypeName"):
                    assembly_type_name = element_type.TypeName  # If TypeName is available
        else:
            assembly_type_name = "Invalid TypeElement"
    else:
        assembly_type_name = "Invalid TypeId"

    # Add the assembly instance ID and its type name to the dictionary
    assembly_data[assembly.Id] = assembly_type_name

# Allow user to select assembly types from the extracted data
def get_assembly_type_from_user():
    # Generate a list of assembly type names for user selection
    assembly_type_names = list(set(assembly_data.values()))  # Remove duplicates

    # Let the user select assembly types
    assembly_selection = forms.SelectFromList.show(
        assembly_type_names, 
        multiselect=True, 
        title='Select Assembly Types'
    )

    if assembly_selection:
        # Filter the assemblies based on user selection
        selected_assemblies = [
            assembly_id for assembly_id, assembly_type in assembly_data.items() 
            if assembly_type in assembly_selection
        ]
        return selected_assemblies
    return None

# Get the selected assembly types from the user
selected_assemblies = get_assembly_type_from_user()

if selected_assemblies:
    # Allow user to select orientation (horizontal or vertical) with a default value
    selected_orientation = forms.ask_for_one_item(
        ["Horizontal", "Vertical"], 
        title='Select Tag Orientation', 
        default="Horizontal"
    )

    if selected_orientation:
        # Allow user to select if they want to add a leader to the tag
        add_leader = forms.ask_for_one_item(
            ["Yes", "No"], 
            title="Leader line",  # Changed the title to "Leader line"
            default="Yes"
        )

        if add_leader:
            # Start a transaction to tag the selected assemblies
            t = DB.Transaction(doc, "Tag Assemblies")
            t.Start()

            try:
                # Create a tag for each selected assembly
                for assembly_id in selected_assemblies:
                    assembly = doc.GetElement(assembly_id)
                    if isinstance(assembly, DB.AssemblyInstance):
                        # Get the assembly's location for tag placement
                        location = assembly.Location
                        if isinstance(location, DB.LocationPoint):
                            # For point location, use the location as the tag position
                            tag_position = location.Point
                        elif isinstance(location, DB.LocationCurve):
                            # For line location, use the midpoint of the curve
                            curve = location.Curve
                            tag_position = curve.Evaluate(0.5, True)  # Midpoint of the curve

                        # Determine tag orientation (Horizontal or Vertical)
                        if selected_orientation == "Vertical":
                            tag_orientation = DB.TagOrientation.Vertical
                            # Offset the tag position by 90 degrees (rotation)
                            tag_position = tag_position + DB.XYZ(0, 0, 1)  # This creates a vertical offset
                        else:
                            tag_orientation = DB.TagOrientation.Horizontal

                        # Create the tag at the selected position
                        tag = DB.IndependentTag.Create(
                            doc, active_view.Id, DB.Reference(assembly), False,
                            DB.TagMode.TM_ADDBY_CATEGORY, tag_orientation, tag_position
                        )

                        # Add leader if the user selected "Yes"
                        if add_leader == "Yes":
                            tag.HasLeader = True  # Adds the leader to the tag

                # Commit the transaction after tagging
                t.Commit()

                TaskDialog.Show("Tagging Complete", "{} assemblies have been tagged.".format(len(selected_assemblies)))

            except Exception as e:
                # Rollback the transaction if an error occurs
                t.RollBack()
                TaskDialog.Show("Error", "An error occurred while tagging assemblies: {}".format(str(e)))

        else:
            TaskDialog.Show("Error", "No selection made for leader. Script canceled.")

    else:
        TaskDialog.Show("Error", "No orientation selected. Script canceled.")

else:
    TaskDialog.Show("Error", "No assembly types selected. Script canceled.")

Select assemblies

from pyrevit import revit, DB, forms
from Autodesk.Revit.UI import TaskDialog

# Get the active document and active view
doc = revit.doc
active_view = doc.ActiveView

# Create a dictionary to store assembly instance IDs and their types
assembly_data = {}

# Collect all assembly instances visible in the active view
visible_assemblies = (
    DB.FilteredElementCollector(doc, active_view.Id)
    .OfCategory(DB.BuiltInCategory.OST_Assemblies)
    .WhereElementIsNotElementType()
    .ToElements()
)

# Extract assembly types and store in dictionary
for assembly in visible_assemblies:
    # Get the type ID of the assembly
    type_id = assembly.GetTypeId()

    # Ensure that the type ID is valid
    if type_id and type_id.IntegerValue != -1:
        # Retrieve the element type using the type ID
        element_type = doc.GetElement(type_id)

        # Check if the element type is valid
        if element_type:
            try:
                # Attempt to access the Name property (this is the usual property for types)
                assembly_type_name = element_type.Name
            except AttributeError:
                # If Name is not available, try other properties
                assembly_type_name = "Name property not available"
                if hasattr(element_type, "FamilyName"):
                    assembly_type_name = element_type.FamilyName  # If FamilyName is available
                elif hasattr(element_type, "TypeName"):
                    assembly_type_name = element_type.TypeName  # If TypeName is available
        else:
            assembly_type_name = "Invalid TypeElement"
    else:
        assembly_type_name = "Invalid TypeId"

    # Add the assembly instance ID and its type name to the dictionary
    assembly_data[assembly.Id] = assembly_type_name

# Allow user to select assembly types from the extracted data
def get_assembly_type_from_user():
    # Generate a list of assembly type names for user selection
    assembly_type_names = list(set(assembly_data.values()))  # Remove duplicates

    # Let the user select assembly types
    assembly_selection = forms.SelectFromList.show(
        assembly_type_names, 
        multiselect=True, 
        title='Select Assembly Types'
    )

    if assembly_selection:
        # Filter the assemblies based on user selection
        selected_assemblies = [
            assembly_id for assembly_id, assembly_type in assembly_data.items() 
            if assembly_type in assembly_selection
        ]
        return selected_assemblies
    return None

# Get the selected assembly types from the user
selected_assemblies = get_assembly_type_from_user()

if selected_assemblies:
    # Create a list of ElementIds to be selected
    element_ids = [assembly_id for assembly_id in selected_assemblies]
    
    # Convert to .NET List[ElementId]
    from System.Collections.Generic import List
    element_ids_net = List[DB.ElementId](element_ids)

    # Select the elements in the active view
    revit.uidoc.Selection.SetElementIds(element_ids_net)

    TaskDialog.Show("Selection Complete", "{} elements have been selected.".format(len(selected_assemblies)))
else:
    TaskDialog.Show("Error", "No assembly types selected. Script canceled.")

Disassemble assemblies

from pyrevit import revit, DB, forms
from Autodesk.Revit.UI import TaskDialog

# Get the active document and active view
doc = revit.doc
active_view = doc.ActiveView

# Create a dictionary to store assembly instance IDs and their types
assembly_data = {}

# Collect all assembly instances visible in the active view
visible_assemblies = (
    DB.FilteredElementCollector(doc, active_view.Id)
    .OfCategory(DB.BuiltInCategory.OST_Assemblies)
    .WhereElementIsNotElementType()
    .ToElements()
)

# Extract assembly types and store in dictionary
for assembly in visible_assemblies:
    # Get the type ID of the assembly
    type_id = assembly.GetTypeId()

    # Ensure that the type ID is valid
    if type_id and type_id.IntegerValue != -1:
        # Retrieve the element type using the type ID
        element_type = doc.GetElement(type_id)

        # Check if the element type is valid
        if element_type:
            try:
                # Attempt to access the Name property (this is the usual property for types)
                assembly_type_name = element_type.Name
            except AttributeError:
                # If Name is not available, try other properties
                assembly_type_name = "Name property not available"
                if hasattr(element_type, "FamilyName"):
                    assembly_type_name = element_type.FamilyName  # If FamilyName is available
                elif hasattr(element_type, "TypeName"):
                    assembly_type_name = element_type.TypeName  # If TypeName is available
        else:
            assembly_type_name = "Invalid TypeElement"
    else:
        assembly_type_name = "Invalid TypeId"

    # Add the assembly instance ID and its type name to the dictionary
    assembly_data[assembly.Id] = assembly_type_name

# Allow user to select assembly types from the extracted data
def get_assembly_type_from_user():
    # Generate a list of assembly type names for user selection
    assembly_type_names = list(set(assembly_data.values()))  # Remove duplicates

    # Let the user select assembly types
    assembly_selection = forms.SelectFromList.show(
        assembly_type_names, 
        multiselect=True, 
        title='Select Assembly Types'
    )

    if assembly_selection:
        # Filter the assemblies based on user selection
        selected_assemblies = [
            assembly_id for assembly_id, assembly_type in assembly_data.items() 
            if assembly_type in assembly_selection
        ]
        return selected_assemblies
    return None

# Get the selected assembly types from the user
selected_assemblies = get_assembly_type_from_user()

if selected_assemblies:
    # Start a transaction to disassemble the selected assemblies
    t = DB.Transaction(doc, "Disassemble Assemblies")
    t.Start()

    try:
        # Disassemble the selected assemblies
        for assembly_id in selected_assemblies:
            assembly = doc.GetElement(assembly_id)
            if isinstance(assembly, DB.AssemblyInstance):
                # Disassemble the assembly
                assembly.Disassemble()
        
        # Commit the transaction after disassembling
        t.Commit()

        TaskDialog.Show("Disassembly Complete", "{} assemblies have been disassembled.".format(len(selected_assemblies)))
    
    except Exception as e:
        # Rollback the transaction if an error occurs
        t.RollBack()
        TaskDialog.Show("Error", "An error occurred while disassembling assemblies: {}".format(str(e)))

else:
    TaskDialog.Show("Error", "No assembly types selected. Script canceled.")

1 Like