Splitting ducts correctly with unions

Splitting ducts correctly with unions

Andrej.Licanin
Advocate Advocate
1,016 Views
4 Replies
Message 1 of 5

Splitting ducts correctly with unions

Andrej.Licanin
Advocate
Advocate

Hello, I made a command that splits ducts into chunks of maximum lengths 1500mm and 300 mm.
The problem I am faced with is that breaking the curve makes a  new curve that has the  correct length but when I add a union fitting between 2 ducts, the fitting width "eats a bit" out of my 1500mm duct and turns it into 1497 mm or something. I know this is because the union fitting has its own physical width, I am unsure how to tackle compensating for this width. Seeing as there can be may different families of unions with different widths.

I hard coded a value that have in the test project and used it  to compensate  , but that wont be the case in all projects...

 

Any ideas on how to resolve this issue without asking the user for the union width or hardcoding it?

 

Here is my code for the entire command (its called with one duct selected).

 

 [Transaction(TransactionMode.Manual)]
    class DuctSplitter : IExternalCommand

    {
        public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)
        {
            UIDocument uiDoc = commandData.Application.ActiveUIDocument;
            Document doc = uiDoc.Document;



            using (Transaction trans = new Transaction(doc, "Trans1"))
            {
                trans.Start();

                Split1DuctMutlipleTimes(uiDoc, doc);

                trans.Commit();
            }

            return Result.Succeeded;
        }


        private void Split1DuctMutlipleTimes(UIDocument uiDoc, Document doc)
        {
            ICollection<ElementId> selectedIds = uiDoc.Selection.GetElementIds();
            Element duct = doc.GetElement((selectedIds.ToList())[0]);
            Element newDuct = null;
            LocationCurve lCurve = duct.Location as LocationCurve;
            Curve curve = lCurve.Curve;


            double totalLength = curve.Length;
            //convert length to mm
            double realLen = UnitUtils.ConvertFromInternalUnits(totalLength, DisplayUnitType.DUT_MILLIMETERS);

            double minLen = 300;
            double maxLen = 1500;
            //need to acount for union fitting width
            double unionSize = 7;
            //double internalLength = UnitUtils.ConvertToInternalUnits(maxLen, DisplayUnitType.DUT_MILLIMETERS);

            //calculate the number of splits
            int numOfSplits = (int)Math.Truncate(realLen / maxLen);

            // the length of the final piece, if this is 0, then it still needs to reduce the number of splits because unions have their own lengths
            double finalPiece = realLen - maxLen * numOfSplits;
            bool needsFinalPiece = false;
            //compensate for possible outcomes for final piece
            double maxLenWithUnion = maxLen + unionSize / 2;
            double minLenWithUnion = minLen + unionSize / 2;

            if (finalPiece < minLenWithUnion)
            {
                numOfSplits -= 1;
                needsFinalPiece = true;
            }

            for (int i = 0; i < numOfSplits; i++)
            {
                newDuct = SplitDuct(uiDoc, doc, duct, maxLenWithUnion);
            }

            placeFinalPiece(uiDoc, doc, duct, minLenWithUnion, maxLen, finalPiece, needsFinalPiece);

        }

        private void placeFinalPiece(UIDocument uiDoc, Document doc, Element duct, double minLen, double maxLen, double finalPiece, bool needsFinalPiece)
        {
            if (needsFinalPiece)
            {
                double len = (duct.Location as LocationCurve).Curve.Length;
                double extLen = UnitUtils.ConvertFromInternalUnits(len, DisplayUnitType.DUT_MILLIMETERS);
                // to cover for case when finalpiece = 0
                if (extLen < maxLen) return;

                finalPiece = extLen - minLen;
                SplitDuct(uiDoc, doc, duct, finalPiece);
            }
            return;
        }

        Element  SplitDuct(UIDocument uiDoc, Document doc, Element duct, double splitLen)
        {
            // get curve
            LocationCurve lCurve = duct.Location as LocationCurve;
            Curve curve = lCurve.Curve;

            // get endpoins and a vector betwen them
            XYZ pt0 = curve.GetEndPoint(0);
            XYZ pt1 = curve.GetEndPoint(1);
            XYZ vec = pt1.Subtract(pt0).Normalize();

            double lenght = UnitUtils.ConvertToInternalUnits(splitLen, DisplayUnitType.DUT_MILLIMETERS);
            // scale normalized vector
            XYZ breakPt = pt0.Add(vec.Multiply(lenght));
            // make new duct and get it
            ElementId newDuctId = Autodesk.Revit.DB.Mechanical.MechanicalUtils.BreakCurve(doc, duct.Id, breakPt);
            Element newDuct = doc.GetElement(newDuctId);

            //create a union
            Connector con1 = (duct as Autodesk.Revit.DB.Mechanical.Duct).ConnectorManager.Lookup(0);
            Connector con2 = (newDuct as Autodesk.Revit.DB.Mechanical.Duct).ConnectorManager.Lookup(1);

            doc.Create.NewUnionFitting(con1, con2);

            return newDuct;
        }

    }

 

Accepted solutions (1)
1,017 Views
4 Replies
Replies (4)
Message 2 of 5

jeremy_tammik
Alumni
Alumni

It sounds to me as if the task is impossible to solve unless you can somehow determine in advance how much of the duct will be replaced by the fitting. For that, you need to know which fitting will be used, or at least how long it is. I would assume that can be determined from the Revit routing preferences, and ultimately by you yourself and the end user. So, this boils down to a different question: which union fitting type do the Revit routing preferences specify for your specific duct?

Jeremy Tammik Developer Advocacy and Support + The Building Coder + Autodesk Developer Network + ADN Open
0 Likes
Message 3 of 5

Andrej.Licanin
Advocate
Advocate

I ended up asking the user for the length (with 10mm default value in nothing is provided by the user). Could not find a way to determine it programmatically. I went over a few active models in the company and the union fitting differs from project to project.

0 Likes
Message 4 of 5

MarryTookMyCoffe
Collaborator
Collaborator
Accepted solution

why can't you move Union after you create it?

-------------------------------------------------------------
--------------------------------|\/\/|------------------------
do not worry it only gonna take Autodesk 5 years to fix bug
0 Likes
Message 5 of 5

Andrej.Licanin
Advocate
Advocate

ONE DOES NOT SIMPLY MOVE A DUCT UNI....or does it. 😄
that was it, dont know why i didnt think of it. Thank you.

Added this function after the creation of the union duct to move it.

 

       private void moveDuctUnion(Element newduct, Element ductUnion, XYZ vec, XYZ breakPt, XYZ pt0)
        {
            
            double newLength = (newduct.Location as LocationCurve).Curve.Length;
            // moving the duct with the length of the original duct lenght and the created one with the combined duct union
            XYZ newVec = pt0.Add(vec.Multiply(newLength)); // created duct vecotr
            XYZ offsetVector = breakPt - newVec;// original duct -current duct
            ElementTransformUtils.MoveElement(doc,ductUnion.Id, offsetVector);

        }

 

0 Likes