Joining Elements in one nested List

Hi Everyone. Currently I am working on a project where I need to join all elements in one group together. If I do it manually through Revit it works perfectly but It seems It is not working with Dynamo. the script doesn’t give any error but the elements are not joining. I was wondering if there is a problem with only having one list. So there is no List A and B. because I want to join only the elements in that specific list together. can someone help me with that. Thank you

Hi Aween,

Can you paste the python script here so we dont all need to type it out to test it.

Sure, here is the script.

import clr
clr.AddReference('RevitAPI')
from Autodesk.Revit.DB import *
clr.AddReference('RevitServices')
from RevitServices.Persistence import DocumentManager

# Get the current document
doc = DocumentManager.Instance.CurrentDBDocument


elements_groups = IN[0]


def join_elements(group_elements):
    print("Group Elements Count:", len(group_elements))
    if len(group_elements) > 1:
        try:
          
         
            if all(revit_elements[0].Category.Id == elem.Category.Id for elem in revit_elements):
            
                # Join all elements with each other in the group
                first_element_id = revit_elements[0].Id
                joined_element_id = None
                for element in revit_elements[1:]:
                    joined_element_id = ElementTransformUtils.JoinElementGeometry(doc, first_element_id, element.Id)
                    if joined_element_id == ElementId.InvalidElementId:
                        print("Error: Elements could not be joined.")
                        return group_elements

                if joined_element_id != ElementId.InvalidElementId:
                    return doc.GetElement(joined_element_id).ToDSType(False)
            else:
                print("Error: Elements in the group are not of the same category.")
        except Exception as ex:
            # Handle any potential errors during the join process
            print("Error while joining elements:", str(ex))
            return group_elements
    else:
        return group_elements


joined_elements = [join_elements(group) for group in elements_groups]

# Output the joined elements
OUT = joined_elements

It might be a minor thing but I created the Elements in Revit through Grasshopper/Rhino.Inside. but they are Native Revit Elements.

What type of element? Directshape? Generic Model family instances? Mass? Imports?

Hi Jacob. They are Generic Models.

In this section

if all(revit_elements[0].Category.Id == elem.Category.Id for elem in revit_elements):

Did you mean to write
if all(group_elements[0].Category.Id == elem.Category.Id for elem in group_elements):

1 Like

yes. But even if I use group_elements Instead of revit_elements it doesn’t affect the result.

Not sure what it is up here, but i’ve a sneaking suspicion that you voxelized the entire model, and are now trying to union them… why not union them and send the union instead? The rendering complexity (and therefore view display time) goes up exponentially when you build like this as cube 1 doesn’t get displayed until cub n is also calculated, and joined to it.

Does the code work with say 3 adjacent cuboids?

If so, my guess is the order of operations is what’s killing you. that or your have something selected for automation which you don’t have selected manually. Either way we’d need the model to review the root cause.

the script is working in Dynamo environment. But if I plug-in the Revit elements directly to the Python script, It seems not working. Is there a way to bring back those elements from Dynamo to Revit ?

Or it is actually only a visual thing because I didn’t even plug-in the Dynamo List in to the Python script.

Hello, I am not qualified as competent
I don’t see your method used in the ElementTransformUtils class
maybe on this side to dig

Cordially
christian.stan

1 Like

What is the list input into the List.GroupByKey node?

IO think we need a sample Revit model and your DYN to best help.

1 Like

Searching a bit and looking at your code, you need UnwrapElement Element
It seems that you send a string in your IN

You have to use the JoinGeometryUtils class
and pass this in a transaction because you are modifying the elements
here is an example with 2 elements if it can help

code + pictures
import clr
import System

from System.Collections.Generic import *
clr.AddReference('ProtoGeometry')
from Autodesk.DesignScript.Geometry import *
clr.AddReference("RevitNodes")
import Revit
clr.ImportExtensions(Revit.Elements)
clr.ImportExtensions(Revit.GeometryConversion)
clr.AddReference("RevitServices")
import RevitServices
from RevitServices.Persistence import DocumentManager 
from RevitServices.Transactions import TransactionManager 

clr.AddReference("RevitAPI")
clr.AddReference("RevitAPIUI")

import Autodesk 
from Autodesk.Revit.DB import *
from Autodesk.Revit.UI import *

doc = DocumentManager.Instance.CurrentDBDocument
uiapp = DocumentManager.Instance.CurrentUIApplication 
app = uiapp.Application 
uidoc = uiapp.ActiveUIDocument

el_A=UnwrapElement(IN[0])
el_B=UnwrapElement(IN[1])

TransactionManager.Instance.EnsureInTransaction(doc)

elJ=JoinGeometryUtils.JoinGeometry(doc,el_A,el_B)

TransactionManager.Instance.TransactionTaskDone()

OUT = elJ


Cordially
christian.stan

2 Likes

thank you Christian for that. In my case there is only one list that I try to join elements in that list together. I tried something similar with having two different lists. it works better. I think the problem is with having only one list. @jacob.small here is also a sample of Revit and my script.
Joining_Boxes.rvt (588 KB)
Joining_Geofoams.dyn (31.7 KB)

1 Like


the code must be reworked, result not perfect, at the beginning your id 4632 is already joined to another
here is a change to the code previously sent

el_lst=UnwrapElement(IN[0])

TransactionManager.Instance.EnsureInTransaction(doc)
a=JoinGeometryUtils.JoinGeometry(doc,el_lst[0],el_lst[1])
for i in range(1,len(el_lst)-1):
    b=JoinGeometryUtils.JoinGeometry(doc,el_lst[i],el_lst[i+1])
    doc.Regenerate()

TransactionManager.Instance.TransactionTaskDone()

OUT = el_lst

Cordially.
christian.stan

edit:
I thought of a possibility but I don’t know how to write it at all, I post the idea
I think it must be resource intensive.
There will be much better ideas (in my opinion, there is no shortage of brains here)
1st scan all the cubes, I turn these (if no face of them is in contact) I put them in another receptacle (no longer bother to take care of them)
2nd scan I take one I look at the common faces I join it with its neighboring friends (then I transfer it to the receptacle no longer needed) and so on until exhaustion

it’s clear when I write it but it must be less easy to understand
sorry for not being able to do better

That said taking all the geometries under dynamo and union then creating a monolithic family does not correspond to your expectations maybe but hey it should do the trick

Cordially
christian.stan

2 Likes

hi,

a solution with itertools.product()


import clr
import sys
import System

#
clr.AddReference('ProtoGeometry')
from Autodesk.DesignScript.Geometry import *
import Autodesk.DesignScript.Geometry as DS

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

#import net library
from System import Array
from System.Collections.Generic import List, IList, Dictionary

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

#import transactionManager and DocumentManager (RevitServices is specific to Dynamo)
clr.AddReference('RevitServices')
import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager

doc = DocumentManager.Instance.CurrentDBDocument

import itertools


def join_elements(group_elements):
    if all(group_elements[0].Category.Id == elem.Category.Id for elem in group_elements):
        for i, j in itertools.product(list(group_elements)[:], list(group_elements)[:]):
            if i.Id != j.Id and not DB.JoinGeometryUtils.AreElementsJoined(doc, i, j):
                DB.JoinGeometryUtils.JoinGeometry(doc, i, j)
                
    return group_elements

#Preparing input from dynamo to revit
elements_groups = UnwrapElement(IN[0])

#Do some action in a Transaction
TransactionManager.Instance.EnsureInTransaction(doc)

joined_elements = [join_elements(group) for group in elements_groups]

TransactionManager.Instance.TransactionTaskDone()

OUT = joined_elements
1 Like

Thank you guys. It is working now perfectly. Itertools.product() was the solution.

2 Likes

the Problem with that script is I can not add any costume components to Dynamo. because It gives this warning. The script works perfectly without costume packages that I use for totally different purposes. :frowning:
Snag_1cce580

I can’t reproduce this error, can you detail the context (python egine, etc.) ?

Are all packages on the local disc, or are some on a network or cloud location?

Also, is this a physical desktop or virtual environment?

1 Like