Revit API Forum
Welcome to Autodesk’s Revit API Forums. Share your knowledge, ask questions, and explore popular Revit API topics.
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Trouble of my own implementation of BreakCurve on Conduit

8 REPLIES 8
SOLVED
Reply
Message 1 of 9
jlpgy
2127 Views, 8 Replies

Trouble of my own implementation of BreakCurve on Conduit

Hi developers:

Let me brief my demand first:

  • There is an API named BreakCurve, in both MechanicalUtils and PlumbingUtils.

It is a very safe and convenient way to split a duct or a pipe programmatically.

But I could not find a way to easily split a cable tray or a conduit.

 

So I did the following job:

  1. Implement a method to "deep copy" and mep curve element, especially cable trays and conduits. This method genrates a Line which is same as another existing mep curve element. Then a new element is created, along the copied Line. Considering the rotation of the element it self (Considering onlt the self rotation), I inspect the original self-rotation of the original element (even it is round, I can still get it's self rotation by it's connector coordinate system), then rotate the new element. I will also create the same insulation and lining if the original element has them (not important, we are talking about conduit).
  2. I "shrink" the old element as well as the new element. Suppose I picked a point, and project it into the element Location Line, then this point will be the new end point of both old and new element. I use the API Connector.Origin property to set a new XYZ point (which I described above).
  3. I inspect the old connection of the old element. Notice that I only move the connector at the end point (instead of the start point), so I get another connector (not belong to the old mep curve), reconnect it to the new mep curve element (new connecto of the new element is located at the same point of the original connector)

So far, everything goes well. I tested it on ducts, pipes, cable trays. But when I do it again on conduits, Revit throws a generation error 😞

Let me share my codes first:

//! *** My codes contain some extention methods. Ther are very easy to understand by their literal names. ***

-------------------- Copy a mep curve element -----------------------

            Document doc = elem.Document;
            Line l = elem.GetLine();
            XYZ refRight = elem.GetSelfRight();
            XYZ p0 = l.GetEndPoint(0), p1 = l.GetEndPoint(1);
            Level refLevel = elem.ReferenceLevel;
            ElementId typeId = elem.GetTypeId();

            MEPCurve toReturn;

            if (elem is Duct || elem is Pipe)
            {
                ElementId sysTypeId = elem.MEPSystem.GetTypeId();

                if (elem is Duct)
                // 风管
                {
                    var newDuct = Duct.Create(doc, sysTypeId, typeId, refLevel.Id, p0, p1);
                    var newInsulation = newDuct.CopySameInsulationAs(elem as Duct);
                    var newLining = newDuct.CopySameLiningAs(elem as Duct);

                    toReturn = newDuct;
                }
                else
                // 管道
                {
                    var newPipe = Pipe.Create(doc, sysTypeId, typeId, refLevel.Id, p0, p1);
                    var newInsulation = newPipe.CopySameInsulationAs(elem as Pipe);

                    toReturn = newPipe;
                }
            }
            else
            {
                if (elem is CableTray)
                // 电缆桥架
                {
                    var newCableTray = CableTray.Create(doc, typeId, p0, p1, refLevel.Id);
                    newCableTray.SetWidth(elem.Width);
                    newCableTray.SetHeight(elem.Height);

                    toReturn = newCableTray;
                }
                else if (elem is Conduit)
                // 线管
                {
                    var newConduit = Conduit.Create(doc, typeId, p0, p1, refLevel.Id);
                    newConduit.SetDiameter(SizeType.Nominal, elem.Diameter);

                    toReturn = newConduit;
                }
                else
                {
                    throw new NotSupportedException();
                }
            }

--------------------- Self-rotate the new element -----------------------

            double ang = refRight.AngleTo(toReturn.GetSelfRight());

            using (SubTransaction subTrans = new SubTransaction(doc))
            {
                subTrans.Start();

                // 先尝试向一个方向自旋转
// First try rotating in a direction toReturn.Location.Rotate(l, ang); doc.Regenerate(); // 如果新图元自旋转之后与旧图元的自旋转方向不一致,则回滚子事务,并且尝试反向旋转
// Sometimes the rotation is in opposite direction other than we need,
// so I roll it back, and rotate it is another direction. if (toReturn.GetSelfRight().IsSameDirectionAs(refRight)) subTrans.Commit(); else { subTrans.RollBack(); subTrans.Start(); toReturn.Location.Rotate(l, -ang); subTrans.Commit(); } } doc.Regenerate();

------------------ Shrink a straight mep curve element (by setting the end connector)-----------

// shrink is XYZ
SubTransaction subt = new SubTransaction(elem.Document); try { subt.Start();
// IsOppositeDirection(XYZ) is my own ext method, it's easy to understand it :) if (l.Direction.IsOppositeDirection(shrink)) { var conn1 = elem.GetConnectorAt(l.GetEndPoint(1)); conn1.Origin = conn1.Origin + shrink; } else { var conn0 = elem.GetConnectorAt(l.GetEndPoint(0)); // 注意此时的延伸向量与管线的行进方向是反向的 conn0.Origin = conn0.Origin + shrink; } subt.Commit(); return true; } catch { subt.RollBack(); return false; } finally { l.Dispose(); subt.Dispose(); }

Thank you for your patience of reading towards here 🙂

 

The above mentioned methods work well for ducts, pipes, cable trays, but not conduits.

No I will show some screen shots if the result.

图像 1.png

If conduit is a free one (no connection at both ends), it works fine.

If either of it's ends is connected, here comes the trouble:

图像 2.png

The error message reads like that there is no available family symbols in the .rvt document.

But my implementation does not require any family instance creation.

I tested it in Revit 2019.

 

Can anyone help me???? Thanks a lot.

单身狗;代码狗;健身狗;jolinpiggy@hotmail.com
8 REPLIES 8
Message 2 of 9
MarryTookMyCoffe
in reply to: jlpgy

Welcome to Revit Api Where nothing work the same, every thing is exception and Rob can eat a S***.
Therese gonna be a problem like that, a lots of it. I feel your frustration.

I look on it and I see some clues worth trying:
1)try and to conduit a fittings and see what will happen, it is possible that it work like that just for conduit(it woudn't be the first time, they have so much mess with this appie)

2) in my project I have a conduit with Fittings and conduits without Fittings(why they did it like that just puzzle me), maybe it will work for one and not for other.(and I just read about it and it is dead end:

https://forums.autodesk.com/t5/revit-mep-forum/conduit-types/td-p/3412887)

3) I understood that you try to connect them with ConnectTo method, check if .CoordinateSystem.BasisZ are opposite.
4) the most likely reason is that Revit try to make calculation and meanwhile fix all wrong connection.

 

It can be depressing but my suggestion is to give up and just input fitting, because if you looking for answer why this work like that, you probably not gonna get it, in best case you will get answer that you should connect it with fitting.

 

-------------------------------------------------------------
--------------------------------|\/\/|------------------------
do not worry it only gonna take Autodesk 5 years to fix bug
Message 3 of 9
jlpgy
in reply to: MarryTookMyCoffe

Hi @MarryTookMyCoffe:

First appologize for replying so late. 🙂 I was slowly trying your suggestions.

Actually at first I didn't put your suggesions into my working tasks.

But last night I was trying to debug a new function of our product, which requires breaking an existing mep curve element, as well keep it's original connection.

So the logic, as I posted before, is like the following:

  1. Copy a new mep curve, as well copy their insulations, linings, keep their Line direction, keep their self rotation.
  2. Inspect the connection at the original element GetEndPoint(0), if it's connected, note the opposite connector(belonging to another element, maybe an elbow, etc.) in a variable.
  3. Replace the connector on the original element by the one on the newly copied element.(I will share my code later)
  4. Shrink both the original and the new element to the breaking point.(Which I have already shared in thr former post)

Let's see my code:

Snippet

public static bool ReplaceBy(this Connector oldConn, Connector newConn)
{
    Check.CheckArgumentNull(oldConn);
    if (newConn == null || !newConn.IsValidObject)
        return false;
 
    if (!oldConn.Origin.IsAlmostEqualTo(newConn.Origin))
        return false;
    if (!oldConn.GetBasisZ().IsSameDirectionAs(newConn.GetBasisZ()))
        return false;
    if (!oldConn.IsConnected)
        return false;
 
    var doc = oldConn.Owner.Document;
 
    Connector other = oldConn.GetConnected();
    other.DisconnectFrom(oldConn);
    doc.Regenerate();
    other.ConnectTo(newConn);
    doc.Regenerate();
 
    return true;
}

========= These were old implementations, which lead to the Conduit bug.

I have already abandoned this old one, and am using the following code:

Snippet

var connAt1ofElem = elem.GetConnectorAt(p1);
var connAt1ofNewElem = newElem.GetConnectorAt(p1);
if (connAt1ofElem.IsConnected)
{
    var conn = connAt1ofElem.GetConnected();
    connAt1ofElem.DisconnectFrom(conn);
    elem.Document.Create.NewTransitionFitting(connAt1ofNewElem, conn);
}

 

I actually at first just wanted to try my luck by using NewTransitionFitting. Because if the 1st and 2nd connectors share the same dimensions and the same self-rotaion, Revit DOES NOT create a transition, but connect them directly (which makes my programming life a little bit easierSmiley Tongue)

@MarryTookMyCoffe You told me that "NOTHING WORK THE SAME", so I was thinking that the most unsafe point is ConnectoTo() method. And I kept thinking: how about replacing it with a much safer way NewTransitionFitting()

method.

 

I tested it in Revit 2019, it worked fine with conduits.

 

Thank you for your suggesions!

They are greating thoughts which helped me further understand Revit API.

Smiley Very Happy

I believe I will still face more little tiny problems in this topic, and I hope we can discuss about it in the future.

单身狗;代码狗;健身狗;jolinpiggy@hotmail.com
Message 4 of 9
jlpgy
in reply to: MarryTookMyCoffe

@MarryTookMyCoffe

One more thing I forgot to share:

 

I have abandoned the official BreakCurve method supplied by Revit API.

public static ElementId BreakCurve(
	Document document,
	ElementId pipeId,
	XYZ ptBreak
)
public static ElementId BreakCurve(
	Document document,
	ElementId ductId,
	XYZ ptBreak
)

They are in MechanicalUtils and PlumbingUtils static class.

These two methods lead to a very serious problems: The new element the create can keep connection, but the MEPSystem property is null.

And I cannot programmatically set MEPSystem, so I finally abandoned them.

 

I am not usre if I understood those two methods correctly, so I posted this question in the forum:

api-breakcurve-method-creates-a-new-duct-pipe-without-mepsystem 

单身狗;代码狗;健身狗;jolinpiggy@hotmail.com
Message 5 of 9
MarryTookMyCoffe
in reply to: jlpgy

I will tell you how it looks, when I was doing similar thing(I made import of pipe installation from other program to Revit).

In beginning I try to use:

NewTransitionFitting,

NewTeeFitting
NewElbowFitting

but there can be a big problem with this in my case NewElbowFitting  don't work if ends of pipes are in the same point.

breaking a pipe in half can make your MEPSystem null, I even made some pipes that never had a pipeSystemType(some how).
ConnectoTo() can be unsafe if you try to connect pipes connectors,  but with element connector and pipe connector  it should be fine (exception is with elementupdater, ConnectoTo() don't work there) .

if you what to make few elbow or transition, command from revit will be fine, but if you what make like 10k of this suckers, it can take a lot of time.



I actually at first just wanted to try my luck by using NewTransitionFitting. Because if the 1st and 2nd connectors share the same dimensions and the same self-rotaion, Revit DOES NOT create a transition, but connect them directly (which makes my programming life a little bit easierSmiley Tongue)

that method shouldn't work like that. If it leave you with one Conduit or two with connectors connected to each other?(dam maybe they fix something in 2019).


They are in MechanicalUtils and PlumbingUtils static class.

These two methods lead to a very serious problems: The new element the create can keep connection, but the MEPSystem property is null.


did you try regenerate document ? some times it helps.

Finial advice, are you using Revit LookUp? it can make your life so much easier.

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

@MarryTookMyCoffe Hi there, is it still the case that splitting a conduit would require either duplicating an existing one, resize them and align them, then connect them, or to create another conduit and do similar things after?

 

Thank you!

 

Jeff Yao

Message 7 of 9

Hard to tell I'm still working on Revit 2017 and only look up on what methods they delete from new versions. I didn't test connecting and split in new API. I basicly made my own method for this, I need to keep it working with all versions from 2017 to 2020, so many happy change in API is not for me. I know thay change something with transition, but I didn't have time to test it .

-------------------------------------------------------------
--------------------------------|\/\/|------------------------
do not worry it only gonna take Autodesk 5 years to fix bug
Message 8 of 9
adam.krug
in reply to: JeffYao28

hey,

 

Today I had to tackle the same task and I wrote this helper method.

 

public static ElementId BreakConduit(Document doc, ElementId conduitId, XYZ breakPoint)
{
	var conduit = doc.GetElement(conduitId);
	//copy mepCurveToOptimize as newPipe and move to brkPoint
	var location = conduit.Location as LocationCurve;
	var start = location.Curve.GetEndPoint(0);
	var end = location.Curve.GetEndPoint(1);
	var copiedEls = ElementTransformUtils.CopyElement(doc, conduit.Id, breakPoint - start);
	var newId = copiedEls.First();

	//shorten mepCurveToOptimize and newPipe (adjust endpoints)
	AdjustMepCurve(conduit, start, breakPoint, false);
	AdjustMepCurve(doc.GetElement(newId), breakPoint, end, false);

	return newId;
}

public static void AdjustMepCurve(Element mepCurve, XYZ p1, XYZ p2, bool disconnect)
{
	if (disconnect)
		Disconnect(mepCurve);

	var location = mepCurve.Location as LocationCurve;

	location.Curve = Line.CreateBound(p1, p2);
}

 

cheers,

Adam

Message 9 of 9
mikukzaz55
in reply to: adam.krug

thanks a lot!

Can't find what you're looking for? Ask the community or share your knowledge.

Post to forums  

Autodesk DevCon in Munich May 28-29th


Rail Community