Hello everyone,
I really need to know can we split a duct programmatically ? Is there any API available to do so?
I searched in some old articles and it seems Revit doesn't provide any API for the split function. But I am hoping if they have added this in 2017 edition.
Any other ideas to achieve this will be highly appreciated.
Thanks
Saurabh
Solved! Go to Solution.
Solved by FAIR59. Go to Solution.
Hello @saurav_dhir,
See my comment in this post: https://forums.autodesk.com/t5/revit-api-forum/duct-splitting/m-p/6784012/highlight/true#M20243
Thanks Matthew for replying.
I tried using the BreakCurve method for splitting a duct but it throws error at the time of execution.
can you please guide me on how to pass the third parameter i.e. XYZ ptBreak ?
Thanks
Saurabh
Hi @saurav_dhir,
No problem.
Well, I think the error says it all! The point isn't on the duct curve.
Here's a simple example that breaks a duct 2 feet along its length.
<Transaction(TransactionMode.Manual)> _ <Regeneration(RegenerationOption.Manual)> _ <Journaling(JournalingMode.UsingCommandData)> _ Public Class TransactionCommand Implements UI.IExternalCommand Public Function Execute(ByVal commandData As UI.ExternalCommandData, ByRef message As String, ByVal elements As DB.ElementSet) As UI.Result Implements UI.IExternalCommand.Execute Dim app As ApplicationServices.Application = commandData.Application.Application Dim doc As DB.Document = commandData.Application.ActiveUIDocument.Document Dim docUi As UI.UIDocument = commandData.Application.ActiveUIDocument Execute = UI.Result.Failed Using transaction As New DB.Transaction(doc, "Break Duct") transaction.Start() Dim duct As DB.Mechanical.Duct = TryCast(doc.GetElement(New DB.ElementId(1789723)), DB.Mechanical.Duct) Dim curve As DB.Curve = TryCast(duct.Location, DB.LocationCurve).Curve Dim pt0 As DB.XYZ = curve.GetEndPoint(0) Dim pt1 As DB.XYZ = curve.GetEndPoint(1) Dim vector As DB.XYZ = pt1.Subtract(pt0).Normalize Dim breakPt As DB.XYZ = pt0.Add(vector.Multiply(2.0)) Dim newDuctId As DB.ElementId = DB.Mechanical.MechanicalUtils.BreakCurve(doc, duct.Id, breakPt) transaction.Commit() ' change our result to successful Execute = UI.Result.Succeeded End Using Return Execute End Function End Class
Thank you so much Matthew.
It worked pleasantly.
It will be great favor if you can help me in achieving my requirement.
Normally, if we split an duct from UI itself, then it adds an family instance i.e. duct between the two separated elements.
But by using the BreakCurve method it breaks the element into two parts at specified length which is really good, But I also need a specific family instance i.e. duct to be added between the two elements, just like we do from UI in Revit application.
Thanks
Saurabh
Hi @saurav_dhir,
You're welcome.
Well, you probably need to break the duct in two places.
You have the elementIds of the two ducts after one break, you just need to use one of those in your second break.
The second break would have to be enclosed in a second transaction.
Once you have the 3rd elementId, you can get its duct element and use duct.ChangeTypeId to change the type should you desire it.
Hi Matthew,
I am doubtful if you are understanding my requirement or not..
The screenshot which i sent in the previous reply was what i need to achieve as final output. that was done manually from Revit Application.
and, below is what the BreakCurve method does:
Can I add a duct between the two child elements, which will act as a separation point?
Thanks
Saurabh Dhir
You have not enlightened me.
Perhaps a before and after shot (in 3D?) would be beneficial.
Hi Matthew,
Sorry for the confusion. I am not good at explaining. But still trying
Below are some screenshots for before and after case when splinting an element via application and via api, both:
BEFORE:
AFTER
1. WHEN SPLITTING MANUALLY VIA APPLICATION UI:
a. Here you can see 3 elements. two are child elements that was created after splitting the parent element and 3rd one is the duct which act as a separation point between those two.
b. Here you can see the duct which was added when split occurred:
2. WHEN SPLITTING USING API (Via BreakCurve() method):
So, here i need a duct to be added between those two elements, just like i did using the split button from application.
I hope I am going in the right direction to explain my requirement.
Thanks
Saurabh Dhir
Hi @saurav_dhir,
Riiiiiiiight. You need to add a union fitting. That's not a duct; it's a duct fitting, and a familyInstance.
All else fails, describe the elements using the Revit descriptions, or the RevitLookup (API) names. That way it's obvious. 🙂
I originally used two transactions, but it appears a regen will do the trick:
<Transaction(TransactionMode.Manual)> _ <Regeneration(RegenerationOption.Manual)> _ <Journaling(JournalingMode.UsingCommandData)> _ Public Class TransactionCommand Implements UI.IExternalCommand Public Function Execute(ByVal commandData As UI.ExternalCommandData, ByRef message As String, ByVal elements As DB.ElementSet) As UI.Result Implements UI.IExternalCommand.Execute Dim app As ApplicationServices.Application = commandData.Application.Application Dim doc As DB.Document = commandData.Application.ActiveUIDocument.Document Dim docUi As UI.UIDocument = commandData.Application.ActiveUIDocument Execute = UI.Result.Failed Dim newDuctId As DB.ElementId = Nothing Dim ductOrig As DB.Mechanical.Duct = Nothing Dim duct2 As DB.Mechanical.Duct = Nothing Dim breakPt As DB.XYZ = Nothing Using transaction As New DB.Transaction(doc, "Break Duct + Add Fitting") transaction.Start() ductOrig = TryCast(doc.GetElement(New DB.ElementId(1789660)), DB.Mechanical.Duct) Dim curve As DB.Curve = TryCast(ductOrig.Location, DB.LocationCurve).Curve Dim pt0 As DB.XYZ = curve.GetEndPoint(0) Dim pt1 As DB.XYZ = curve.GetEndPoint(1) Dim vector As DB.XYZ = pt1.Subtract(pt0).Normalize breakPt = pt0.Add(vector.Multiply(2.0)) newDuctId = DB.Mechanical.MechanicalUtils.BreakCurve(doc, ductOrig.Id, breakPt) duct2 = TryCast(doc.GetElement(newDuctId), DB.Mechanical.Duct) doc.Regenerate() Dim connectorOrig As DB.Connector = ductOrig.ConnectorManager.Lookup(0) Dim connector1 As DB.Connector = duct2.ConnectorManager.Lookup(1) Dim familySymbol As DB.FamilySymbol = TryCast(doc.GetElement(New DB.ElementId(755396)), DB.FamilySymbol) Dim famInstance As DB.FamilyInstance = doc.Create.NewFamilyInstance(breakPt, familySymbol, DB.Structure.StructuralType.NonStructural) Dim fitting As DB.MEPModel = famInstance.MEPModel Dim fittingConnector0 As DB.Connector = fitting.ConnectorManager.Lookup(0) Dim fittingConnector1 As DB.Connector = fitting.ConnectorManager.Lookup(1) connectorOrig.ConnectTo(fittingConnector1) connector1.ConnectTo(fittingConnector0) transaction.Commit() ' change our result to successful Return UI.Result.Succeeded End Using Return Execute End Function End Class
Hi Matthew,
Thanks for your assistance.
It works great.
Yet, I have another issue. This method only works well if we are not modifying the element's orientation.
I tested this on a duct. I first added a duct and implemented the method just after placing an instance of that duct and it worked great.
But, If I rotate the element to its opposite direction and then implementing that methods throws multiple errors.
Do you have any idea how to resolve these.
Instructions to reproduce the issue:
Thanks
Saurabh Dhir
Hi @saurav_dhir,
The familyinstance needs rotating in the same orientation as the duct curve.
I'm sure there are plenty of examples of how to rotate family instances on this forum. Report back with how you get on!
Hi Matthew,
I searched but haven't got much on how to adjust(rotate) the duct fitting as per element's direction/shape. I just tried the rotate method that just rotates the new instance(duct fitting) to 180 degree angle. So this case only works if i have rotated the element to 180 degree angle (opposite direction). But not in other cases.
Can you please assist?
Thanks
Saurabh Dhir
Hi @saurav_dhir,
Did you get this sorted out yet?
@aksaks has an example of this in his repo:
Hi Matthew,
I checked the link.
There are lots of methods.
Not sure which one to choose.I tried implementing few of them but there are many undefined/unknown classes.
Can you please show me a precise way to get the resolution ?
Thanks
Saurabh Dhir
no need for the rotation , you can place the duct fitting with the right direction.
Dim famInstance As DB.FamilyInstance = doc.Create.NewFamilyInstance(breakPt, familySymbol, vector, null, DB.Structure.StructuralType.NonStructural)
Ofcourse it can't hurt to learn how to rotate an element.
@FAIR59 @matthew_taylor Thank you very much for this brilliant, very patient and comprehensive tutorial, and for pointing it out again in the recent comment on The Building Coder. Preserved for posterity and better readability now in the blog:
https://thebuildingcoder.typepad.com/blog/2020/03/splitting-a-duct-in-more-depth.html