Split beam at multiple indexes using beam.Split(index) method

Hi,
Is there any way to split beam using list of floats (from 0 to 1 excluded) to split beam at multiple points?
Im trying to loop through the list but each subsequent iteration divides the already divided beam.

Here is the piece of code im trying to use

TransactionManager.Instance.EnsureInTransaction(doc)
for index in list:
if beam.CanSplit and 0 < index < 1:
    beam.Split(index)
TransactionManager.Instance.TransactionTaskDone()

Hi Adam,

Would you be able to provide the rest of your code for some additional context?

I’m using element.Split(float) method whitch takes an float parameter, e.g. 0.5 will divide beam in half.
The issue here is that when I try to iterate with a list of indexes,
e.g - I want to divide beam into three beams, so my list will be [0.3 , 0.6].
But after first iteration I have two new beams and second iteration divides one of them - not the original one.
Is there any other API method that splits element by points maybe?

    doc = DocumentManager.Instance.CurrentDBDocument
    beam = UnwrapElement(IN[0])
    list = IN[1]

    TransactionManager.Instance.EnsureInTransaction(doc)
    for index in lista:

        if beam.CanSplit and 0 < index < 1:
            beam.Split(index)

    TransactionManager.Instance.TransactionTaskDone()

There doesn’t seem to be a straightforward solution to this, although I don’t think it’s impossible. FamilyInstance.Split() returns the ElementId of the new element, so you should be able to get the new element from the document and split it separately. I assume that splitting a beam at 0.3 will leave the 0.7 part as the new element, but you should confirm this. A recursive function is probably the best approach here as it should continue to split the newly generated beams until there are no parameters left. What complicates this even further is that the document may have to be regenerated after the new elements are created and that the new beams have a normalized curve domain as well. For example, if you want to divide a beam into 4 equal sections, the first beam is split at 1/4, the second is split at 1/3, and the third is split at 1/2.

1 Like

Hello
a solution with the creation of new FamilyInstance (s) and removal of the old beam

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

clr.AddReference('RevitAPI')
import Autodesk
from Autodesk.Revit.DB import *
from Autodesk.Revit.DB.Structure 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

def splitBeam(elem, lstParaPt):
    def getPts():
        #create list of point
        curvB = elem.Location.Curve
        ptCurv = [curvB.Evaluate(x, True) for x in lstParaPt]
        ptCurv.extend([curvB.GetEndPoint(x) for x in range(0,2)])
        ptCurv.sort(key = lambda x : curvB.GetEndPoint(0).DistanceTo(x))
        return ptCurv
    #main function  
    lstPt = getPts()
    outBeam = []
    famSymb = elem.Symbol 
    lvl = elem.Host
    TransactionManager.Instance.EnsureInTransaction(doc)
    for idx, pt in enumerate(lstPt):
        if idx > 0:
            curv = Line.CreateBound(lstPt[idx -1], pt)
            newbeam = doc.Create.NewFamilyInstance(curv, famSymb, lvl, StructuralType.Beam)
            outBeam.append(newbeam)
    doc.Delete(elem.Id)     
    TransactionManager.Instance.TransactionTaskDone()   
    return  outBeam, lstPt
    
beam = UnwrapElement(IN[0])
lstParam = IN[1]
loc = beam.Location
if isinstance(loc, LocationCurve):
    outBeam , lstPt = splitBeam(beam, lstParam)
OUT = outBeam 

2 Likes

Thanks! Could you show your refrences? Cause I seem to miss a refrence using your code.

Generally I was avoiding any “replacement” solution cause I wanted to keep original parameteres and FamilyInstance.Split() method seems to keep them.

I came up with idea to convert indexes to a target ones - e.g. Division to 4 parts indexes are [0.75, 0.5, 0.25]. After conversion [0.75, 0.666, 0.5].

And it works fine.

code updated with “imports”

Hi @c.poupin and @cgartland , it’s possible to split multiple beams at multiple index or multiple intersection points without deleting and create a new family? Split recursively to keep the properties from the originals beams like C#?

Hi @paris. It is possible, as I said above - I came with idea to split beams recursively while keeping parameters from the original (not deleting original and creating new objects like @c.poupin proposed).
Try using my code below - it takes intersection indexes of original beam and the beam you want to split. (Try also filtering indexes that are very close to 1 or 0)

doc = DocumentManager.Instance.CurrentDBDocument
beam = UnwrapElement(IN[0])
list = IN[1]
list = filter(None, lista)
list.sort(reverse = True)
list_new = [] 
count = 1
while len(list) > count:
    list_new.append((list[count]/list[count-1]))
    count += 1
list_new.insert(0, lista[0])
TransactionManager.Instance.EnsureInTransaction(doc)
for index in list_new:
    if beam.CanSplit and 0 < index < 1:
        beam.Split(index)
TransactionManager.Instance.TransactionTaskDone()

It works for single selection but you could also add few lines to loop through all selected beams.
To find indexes at which beam is intersected you can use this for example:

and thanks for your efforts

Hi @AdamOs , yes,I have the same problem with python to split pipes and ducts on multiple intersection points (of multiple floors), I can split multiple pipes and ducts on multiple points ( intersection points between pipes or ducts and one floor) or with only one pipe (or duct) with multiple floors, but it doesn’t work properly with multiple pipes, ducts and intersection points on floors.
For ducts I used:
https://www.revitapidocs.com/2017/baeec9be-b43d-d378-31b9-453432d44bfb.htm
and for pipes:
https://www.revitapidocs.com/2017/3c302b80-d1f8-0e17-154a-b809cad2e545.htm
Tank you

Hi @AdamOs, nice, I will try your method and give you a feedback, thank you

a recursive split version…without deletion :smiley:

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

clr.AddReference('RevitAPI')
import Autodesk
from Autodesk.Revit.DB 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

def splitBeam(elem, lstParaPt):
	def getPts(curvB):
		#create list of point
		ptCurv = [curvB.Evaluate(x, True) for x in lstParaPt]
		#sort by distance with end point of Curve
		ptCurv.sort(key = lambda x : curvB.GetEndPoint(1).DistanceTo(x))
		return ptCurv 
	#main function  
	curvB = elem.Location.Curve
	lstPt = getPts(curvB)
	outBeam = []
	TransactionManager.Instance.EnsureInTransaction(doc)
	for pt in lstPt:
		lenBeam = curvB.Length 
		param = (curvB.GetEndPoint(0).DistanceTo(pt)) / lenBeam
		newBeam = elem.Split(param)
		outBeam.append(newBeam)
		doc.Regenerate()
	TransactionManager.Instance.TransactionTaskDone()   
	return  outBeam, lstPt, curvB.GetEndPoint(0).ToPoint()
	
beam = UnwrapElement(IN[0])
lstParam = IN[1]
loc = beam.Location
if isinstance(loc, LocationCurve):
	outBeam , lstPt, startPt = splitBeam(beam, lstParam)
OUT = outBeam, startPt 

Great @c.poupin well done ! thank you.
Can also work with points instead using a list of floats?
I have to modify your code to work with break method for split pipes and ducts at points (intersection with floors).
Have a nice day !

hello @paris
try this

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

clr.AddReference('RevitAPI')
import Autodesk
from Autodesk.Revit.DB 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

def splitBeam(elem, lstPt):
	curvB = elem.Location.Curve
	#sort by distance with end point of Curve
	lstPt.sort(key = lambda x : curvB.GetEndPoint(1).DistanceTo(x))
	outBeam = []
	TransactionManager.Instance.EnsureInTransaction(doc)
	for pt in lstPt:
		lenBeam = curvB.Length 
		param = (curvB.GetEndPoint(0).DistanceTo(pt)) / lenBeam
		newBeam = elem.Split(param)
		outBeam.append(newBeam)
		doc.Regenerate()
	TransactionManager.Instance.TransactionTaskDone()   
	return  outBeam, lstPt, curvB.GetEndPoint(0).ToPoint()
	
beam = UnwrapElement(IN[0])
lstDynPt = IN[1]
#convert dynamo points to Revit Point
lstPt = [x.ToXyz() if isinstance(x, Autodesk.DesignScript.Geometry.Point) else x for x in lstDynPt]
loc = beam.Location
if isinstance(loc, LocationCurve):
	outBeam , lstPt, startPt = splitBeam(beam, lstPt)
OUT = outBeam, startPt
1 Like

Hello @c.poupin
great, your code work perfectly, like a charm for split one beam at multiple points !
Thank you !
Now I’m looking to resolve the issue with multiple beams…
Cheers, have a nice day !