Join Forms (JoinGeometry) in Family Document [RevitAPI]

Hello everyone,

Does anyone know if it is possible to join geometries in a Family Document with Revit API?

I have hundreds of forms created between two profiles and I would like to join them in a specific order that I will set previously. Now I am just testing the workflow for two inputs only (elementA, elementB).

I have tested several nodes from different packages so far; Hot Gear, Clockwork… and not only packages but also the OOTB Dynamo node called Element.JoinGeometry and my own Python script. For the OOTB node and my Python node, a warning shows up saying “Warning: Element.JoinGeometry operation failed. document is not a project document.”. Therefore, I assume that the JoinGeometry method can only be used in a Revit project (.rvt) file with Revit API instead of a Revit family document (.rfa).

So, is there any chance I can use the join geometry button in the Revit family document to join forms created from lofting two profiles? If I try to join two consecutive forms in the Revit family environment the software allows me to do it but as I have hundreds of forms these handy tasks are impossible to carry out.

1 Like

I looked for any Class in the Revit API related to the “Form” geometries and within that drop down I could see that there are many Methods but none of them make reference to any “JoinForms” functionality. :smiling_face_with_tear:

I believe that this should help set you on the right path: CombineElements Method

Hi @jacob.small ,

Is that method supposed to work in a Family Document (.rfa)? Bear in mind that I have all my forms in a Family Document (.rfa) instead of in a Project Document (.rvt).

Moreover, I am getting the following error from my Python script and I cannot find any issue in the spelling of the libraries or in line 36 :thinking:

It´s my first time dealing with Revit API so my apologies if I made any noob mistake.

Thank-you,

Try doc.CombineElements(A,B), though I believe you’ll need them in a .net list (not to be confused with a Dynamo list or a Python list).

What is input A and B?

I highlighted the inputs with watch nodes as you can see in the following image. I have also converted the inputs into .NET lists (I think I did ok as I copied it the lines from one reply marked as the solution in the forum) and lastly, I inserted the .doc.CombineElements.

In this case the error message clues you into your next step. You’re feeding it two lists, but it want an object from the CombinableElementArray class.

So we head to the API docs to find a CombinableElementArray constructor, and find this: CombinableElementArray Constructor

Which should be called as variableNameHere = CombinableElementArray().

Now we need to add your combinable elements to the array. Checking for methods of the CombinableElementArray class, and we find this: Append Method, which allows appending combinable elements to the array. So since we have a list of items we’d want to iterate over so that all the elements are in the array, we either need a for loop or to utilize some list comprehension. Personally I prefer the list comprehension method, which goes something like this:

initialElementsList = [A,B]
[ variableNameHere.Append(i) for i in initialElementsList ]

And now that we have our combinable element array object, we can feed that into the combine elements method and see if that solves this for us.
doc.CombineElements(variableNameHere)

Hi @jacob.small ,

I think we are quite close but not yet. I tried to follow your clues and this is the warning I am getting:

I think I am doing something wrong with the order of the variables…

@JMCiller
What is happend when you give rule 42 a tab?

@jw.vanasselt it says the same…

Okay, is it possible to share the script and the rfa file?

@JMCiller

You didn’t do exacly what @jacob.small told you to do :wink:

import clr

clr.AddReference('RevitAPI')
import Autodesk
from Autodesk.Revit.DB import *
from System.Collections.Generic import *

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

clr.AddReference('System')
from System.Collections.Generic import List

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

clr.AddReference("RevitServices")
import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager

doc = DocumentManager.Instance.CurrentDBDocument
uiapp = DocumentManager.Instance.CurrentUIApplication

A = UnwrapElement(IN[0])
B = UnwrapElement(IN[1])
elA = List[Revit.Elements.Element]()
elB = List[Revit.Elements.Element]()

elA.Add(IN[0])
elB.Add(IN[1])
variableNameHere = CombinableElementArray()

initialElementsList = [A,B]
[variableNameHere.Append(i) for i in initialElementsList]

lst = []
TransactionManager.Instance.EnsureInTransaction(doc)

lst.append(doc.CombineElements(variableNameHere))

TransactionManager.Instance.TransactionTaskDone()

OUT = lst

3 Likes

Man, it is working! super!

Now I am going to test it for each component of my road (subilists).

As you can see in the following screenshot, within each sublist I have all the form per each component and I need to get just one GeomCombination element per each sublist.

Good luck!
I guess you need to play around with the for loop something like this:

s = 0
for f in forms[forms is a example]:
	lst.append(doc.CombineElements(f[s]))
	s+= 1
		

I tried it this Monday morning and after some warnings, I got it :grin:

I post the solution… it may help someone in the future…

import clr

clr.AddReference('RevitAPI')
import Autodesk
from Autodesk.Revit.DB import *
from System.Collections.Generic import *

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

clr.AddReference('System')
from System.Collections.Generic import List

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

clr.AddReference("RevitServices")
import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager

doc = DocumentManager.Instance.CurrentDBDocument
uiapp = DocumentManager.Instance.CurrentUIApplication

A = UnwrapElement(IN[0])

elementsComb = []

initialElementsList = A

for i in initialElementsList:
	elementsCombb = CombinableElementArray()
	for ii in i:
		elementsCombb.Append(ii)
	elementsComb.append(elementsCombb)

lst = []
TransactionManager.Instance.EnsureInTransaction(doc)

for x in elementsComb:
	lst.append(doc.CombineElements(x))

TransactionManager.Instance.TransactionTaskDone()

OUT = lst
4 Likes

@JMCiller , Well done! :slight_smile:

2 Likes

Hello @JMCiller,

Great work, thanks for this topic.
I just used your PythonScript to join between around 70 forms and it worked almost fine.

Somehow there is a problem connecting between a handful of forms (4). Revit or Dynamo then hides the form that cannot be joined. Did you experience the same? And maybe came up with a a solution to detect the ErroJoined Forms or leave them out of the Join?

Gladly here from you.
Cheers for your work.
Patrick

Hi @patrick.weis ,

Yes, I had the same issue. In fact, the closer the profiles were the more forms were not joined. I had to leave this approach because of this problem as I needed to place the profiles quite close to each other. To sum up, Revit can join some forms but for no reason (I spent some hours trying to find out the issue) Revit is not able no join some of them.

@patrick.weis , could you fix it? did you find out where the issue may be coming from?

Regards,

Juan.

Hard to fix a problem without the data to reproduce. Can you build up a small sample dataset which causes the issue and post that so the larger community can help resolve?