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: 

Get BendRadius center of Cable Tray Fittings

10 REPLIES 10
Reply
Message 1 of 11
SONA-ARCHITECTURE
656 Views, 10 Replies

Get BendRadius center of Cable Tray Fittings

Hi

I need to get the lenght of a cable tray fittings.

I could get lenght betwen connector A and B but this is not a correct method.

I'd like to get length of an arc between passing by A and B with center of BendRadius...

But how to get the center with API?

 

SONAARCHITECTURE_1-1715007195147.png

 

 

SONAARCHITECTURE_0-1715007185351.png

 

Pierre NAVARRA
SONA-Architecture.
http://www.sona-architecture.com
https://fr.linkedin.com/in/pierre-navarra-62032a107
10 REPLIES 10
Message 2 of 11

This may be somewhat tricky due to the fact that every content creator is free to set up the elbow fitting family definition as she pleases. So, it is hard to know what parameters are available and what they might mean. My off-hand suggestion to approach this would be the following: 

   

  • Determine the two connector origins and orientations for C1 and C2
  • They will give you the two connection points P1 and P2, and the connection orientation vectors Z1 and Z2 pointing into the fitting at C1 and C2
  • From these four points and vectors, you can calculate an arc that implements a fillet between the two neighbouring conduit straight line segments

  

That is the best approximation I can think of offhand. If you have the bend width, radius, straight line extensions at the two ends of the bend, and/or other additional data, you can improve the calculation taking those into account.

  

Jeremy Tammik, Developer Advocacy and Support, The Building Coder, Autodesk Developer Network, ADN Open
Message 3 of 11

Hi Jeremy
and thanks for replying

Thanks for the hint
Indeed, I think the idea would be to find the center of a circle from the two connectors. I'd need to get the vectors at these points and take the perpendicular to these vectors. Then I could find their intersection and draw an arc between the two connectors.
But how do I get the vectors? By using the Transform object and then BasisXYZ?

 

SONAARCHITECTURE_0-1715065580592.png

 

Pierre NAVARRA
SONA-Architecture.
http://www.sona-architecture.com
https://fr.linkedin.com/in/pierre-navarra-62032a107
Message 4 of 11

Yes, exactly. In the CoordinateSystem property, the coordinate system origin is the location of the connector and the Z-axis is normal to the connector, and thus also to the fitting face hosting it, and thus also collinear with the neighbouring conduit location line:

  

  

Jeremy Tammik, Developer Advocacy and Support, The Building Coder, Autodesk Developer Network, ADN Open
Message 5 of 11

Hi,

I found this post from Cyril Poupin in Python ...

The code said :

 

 

pair_sys_origin = [[con.CoordinateSystem, con.Origin] for con in conSet]
			pta = pair_sys_origin[0][1].ToPoint()
			ptb = pair_sys_origin[1][1].ToPoint()
			vector = pair_sys_origin[0][0].BasisZ.Negate().ToVector()
			arc = DS.Arc.ByStartPointEndPointStartTangent(pta, ptb, vector)
			return arc, arc.Length

 

 

I've tried to translate it in C#

But I don't have good result because Dynamo API got this function called ByStartPointEndPointStartTangent and I must creat my own .... mmm...this is a geometric problem..

 

 

 

//méthode à partir de deux connecteurs
if (connectors.Size == 2) 
{
    //Transforme le Set en liste
    var castConnectors = connectors.Cast<Connector>();
    List<Connector> connectorList = castConnectors.ToList();
    //get first point
    Transform transformPtA = connectorList[0].CoordinateSystem;
    XYZ originPtA = transformPtA.Origin;  

    //get Vector from this point
    XYZ vector = transformPtA.BasisZ.Negate();
    //get second point
    Transform transformPtB = connectorList[1].CoordinateSystem;
    XYZ originPtB = transformPtB.Origin;
   
    //Get arc from those points
    Arc arc = Arc.Create(originPtA, originPtB, vector);

    length = arc.Length;

}

 

 

Pierre NAVARRA
SONA-Architecture.
http://www.sona-architecture.com
https://fr.linkedin.com/in/pierre-navarra-62032a107
Message 6 of 11

I thing you need to do it manually but but of course programmatically 🙂 . I mean there is no direct way to get it. So you need to identify the two connectors for which you want to determine the outer radius. From these 2 connectors we extract the origin points. The points are crucial for finding the center point of the arc.

 

Getting the center point can be reached by drawing a perpendicular line to the cable tray curve direction and projecting the second point onto this line, by which we can locate the center.

 

Next, draw an arc connecting the two points with the radius. The radius can be measured by getting the distance between any of the connectors to the center point we evaluated.  This approach will establish the centerline connection between the two MEP curves. Finally, by using the CreateOffset function with a distance equal to half the cable tray width, we can achieve our desired outcome.

 

Below is a sample code that summarizes the process, you need to take care of the angles needed to draw the arc. The start angle has to be less than the end angle. Another thing I noticed in most of MEP Fittings, specially the elbow kind, the path that is used to sweep the profile, is composed of two lines and one arc. the two lines gives a smooth connection like when used. so you need also to take care of the such thing, in order to get an accurate result.

 

Finally, I quickly written the sample below for the 90 degrees case. I think in the other angle cases, you need to take care of the projection of the second point. probably you need to create another perpendicular line and find the intersection between the two lines.

 

Let us know your findings.

 

// assuming you already have the two connectors.
// we get the curves lines from its owner.
var horizontalLine = ((LocationCurve)connectorA.Owner.Location).Curve as Line;
var verticalLine = ((LocationCurve)connectorB.Owner.Location).Curve as Line;

// catch the distance and location of the 2 connectors and the distance between
var originA = connectorA.Origin;
var originB = connectorB.Origin;
var diagonalDistance = originA.DistanceTo(originB);

// get the sketchplan used to draw such cable trays
var sketchPlan = SketchPlane.Create(Doc, ((MEPCurve)connectorA.Owner).ReferenceLevel.Id).GetPlane();

// now we need draw a perpendicular line to any of the mep curves.
var perDirection = horizontalLine.Direction.CrossProduct(sketchPlan.Normal);
var perpL1 = Line.CreateBound(originA - perDirection * diagonalDistance, originA + perDirection * diagonalDistance);

// then project the second point over this perpendicular curve to get the center point
var centerPoint = perpL1.Project(originB).XYZPoint;

// arc requires 2 angles start and end
double angleX = sketchPlan.XVec.AngleTo((originA - centerPoint).Normalize());
double angleY = sketchPlan.XVec.AngleTo((originB - centerPoint).Normalize());

// draw the arc <= this is in the zero position "sketchplan origin point"
Curve arc = Arc.Create(sketchPlan, originB.DistanceTo(centerPoint), angleX, angleY);

// move the arc to the center point
arc = arc.CreateTransformed(Transform.CreateTranslation(centerPoint));

// create the offset needed to get the outer Radius
arc = arc.CreateOffset(((MEPCurve)connectorA.Owner).Width / 2, sketchPlan.Normal);

 

Moustafa Khalil
Cropped-Sharp-Bim-500x125-Autodesk-1
Message 7 of 11

Hi @Moustafa_K 

thx for your answer

I’ll test it soon

It’s a shame because I’m sure the solution is in the api Dynamo function called ByStartPointEndPointStartTangent but no way to find source code

 

Pierre NAVARRA
SONA-Architecture.
http://www.sona-architecture.com
https://fr.linkedin.com/in/pierre-navarra-62032a107
Message 8 of 11

Pipe elbow fittings often have a straight segment on each side before the arc begins, for connecting them to the neighbour parts. Do the conduit elbows always connect immediately to the arc, with no straight segment before and after?

   

Jeremy Tammik, Developer Advocacy and Support, The Building Coder, Autodesk Developer Network, ADN Open
Message 9 of 11

I'm getting ahead of myself
I reach the center of my arc.
However, I'm stuck on creating the arc.
My bow doesn't always go in the right direction and it doesn't go between my two connector points...

 

 

//Transforme le Set en liste
var castConnectors = connectors.Cast<Connector>();
List<Connector> connectorList = castConnectors.ToList();

Connector connectorA = connectorList[0];
Connector connectorB = connectorList[1];

#region connectorA_Perpendicular
//get Transform
Transform transformPtA = connectorA.CoordinateSystem;                           
//get origin
XYZ originPtA = transformPtA.Origin;
//get direction
XYZ directionA = (connectorA.Owner.Location as LocationPoint).Point;
//set line between origin and direction of owner
Line lineA = Line.CreateBound(originPtA, directionA);

//get perpendicular
XYZ normalA = lineA.Direction.Normalize();
XYZ dirA = new XYZ(0, 0, 1);
XYZ crossA = normalA.CrossProduct(dirA);
XYZ endA = originPtA + crossA.Multiply(4);
XYZ endAMirror = originPtA + crossA.Multiply(-4);
Line linePerpendicularA = Line.CreateBound(endA, endAMirror);

#endregion

#region connectorB_Perpendicular
//get Transform 
Transform transformPtB = connectorB.CoordinateSystem;
//get origin
XYZ originPtB = transformPtB.Origin;
//get direction
XYZ directionB = (connectorB.Owner.Location as LocationPoint).Point;
//set line between origin and direction of owner
Line lineB = Line.CreateBound(originPtB, directionB);

//get perpendicular
XYZ normalB = lineB.Direction.Normalize();
XYZ dirB = new XYZ(0, 0, 1);
XYZ crossB = normalB.CrossProduct(dirB);
XYZ endB = originPtB + crossB.Multiply(4);
XYZ endBMirror = originPtB + crossB.Multiply(-4);
Line linePerpendicularB = Line.CreateBound(endB, endBMirror);

#endregion

//get intersection between perpendiculars
XYZ centerOfArc = null;
IntersectionResultArray intersectionResults = new IntersectionResultArray();
SetComparisonResult setCR = linePerpendicularA.Intersect(linePerpendicularB, out intersectionResults);

if (setCR == SetComparisonResult.Overlap)
{
    if (intersectionResults != null && intersectionResults.Size == 1)
    {
        //there is one point interesction
        IntersectionResult iResult = intersectionResults.get_Item(0);
        centerOfArc = iResult.XYZPoint;
        _geometries.Add(Point.Create(centerOfArc));
    }
}

if (centerOfArc != null)
{
    //Set arc from point A and B
    double radius = centerOfArc.DistanceTo(originPtA);
    
    XYZ xAxis = new XYZ(1, 0, 0);   // The x axis to define the arc plane. Must be normalized
    XYZ yAxis = new XYZ(0, 1, 0);   // The y axis to define the arc plane. Must be normalized
    Arc arc = Arc.Create(centerOfArc, radius, 0, Math.PI / 2.0, xAxis, yAxis);
    _geometries.Add(arc);
}

 

 

SONAARCHITECTURE_0-1715693536268.png

 

And what about Cable Tray Fittings which are vertical or visible in section like this?

SONAARCHITECTURE_1-1715693717886.png

 

 

Pierre NAVARRA
SONA-Architecture.
http://www.sona-architecture.com
https://fr.linkedin.com/in/pierre-navarra-62032a107
Message 10 of 11

HI @Moustafa_K  @SONA-ARCHITECTURE  @jeremy_tammik 

        I found a new workaround to get the center curve of the duct, I don't whether anybody document it or not. I have use the complete Revit API library to create Arc. Kindly check the below code for additional reference.

 

Reference Code

ElementId id = uidoc.Selection.PickObject(Autodesk.Revit.UI.Selection.ObjectType.Element).ElementId;

            FamilyInstance inst = doc.GetElement(id) as FamilyInstance;

            Options opt = new Options();
            opt.ComputeReferences = true;
            opt.DetailLevel = ViewDetailLevel.Coarse;

            GeometryElement geoElement = inst.get_Geometry(opt);

            using (Transaction createArc = new Transaction(doc, "Create Arc"))
            {
                createArc.Start();

                foreach (GeometryInstance geoInst in geoElement)
                {
                    if(geoInst != null)
                    {
                        foreach (GeometryObject obj in geoInst.GetInstanceGeometry())
                        {
                            if (obj is Arc)
                            {
                                doc.Create.NewModelCurve(obj as Curve, SketchPlane.
                                    Create(
                                    doc, 
                                    Plane.CreateByNormalAndOrigin((obj as Arc).Normal, 
                                    (obj as Arc).GetEndPoint(0))));
                            }
                        }
                    }
                }

                createArc.Commit();
            }

 

Reference GIF

Duct_Arc.gif

 

Hope this will Helps 🙂

Thanks & Regards,
Mohamed Arshad K
Message 11 of 11

Hi @Mohamed_Arshad 

YouHou!!! It works!!

So yes, depending on the level of view detail, the instances returned by GetInstanceGeometry are not the same.

Secret is changing the ViewDetailLevel to Coarse!
The good surprise is that Arc or Line have an ApproximateLength property, so I don't have to run a transaction.

SONAARCHITECTURE_0-1715775847331.png

SONAARCHITECTURE_1-1715775853971.png

 

SONAARCHITECTURE_2-1715775858848.png

 


The code looks like this

Options opt = new Options();
				opt.ComputeReferences = true;
				opt.DetailLevel = ViewDetailLevel.Coarse;
						
	            foreach (ElementId elemId in _uidoc.Selection.GetElementIds())
	            {
	                // normalement, un seul
	                Element element = _uidoc.Document.GetElement(elemId);
	                
	                if (element.GetType() == typeof(FamilyInstance))
	                {
	                	double approximateLength = 0;
	                	FamilyInstance famInst = element as FamilyInstance;	                	
						
						GeometryElement geoElement = famInst.get_Geometry(opt);
						
						foreach (GeometryInstance geoInst in geoElement)
						{
							if (geoInst != null)
							{
								foreach(GeometryObject geoObj in geoInst.GetInstanceGeometry())
								{									
									if (geoObj is Arc)
									{
										Arc arc = geoObj as Arc;										
										approximateLength += arc.ApproximateLength;	                           	
									}
									
									if (geoObj is Line)
									{
										Line line = geoObj as Line;
										approximateLength += line.ApproximateLength;
									}
								}
							}
						}

						TaskDialog.Show("Message from dev", "Approximate length of instance is " +
						                UnitUtils.ConvertFromInternalUnits(approximateLength, UnitTypeId.Centimeters));
						
	                }
	            }


Thanks to all
On the other hand, I'm very disappointed that I wasn't able to calculate all this using vectors... Maybe another time.

Thanks @jeremy_tammik  and @Moustafa_K for your help!

And thanks to Mariyan for his tutos about vectors!

https://youtu.be/FrFSPTRO9wY?si=i3HvK-IT908ST8QO

 

 

Pierre NAVARRA
SONA-Architecture.
http://www.sona-architecture.com
https://fr.linkedin.com/in/pierre-navarra-62032a107

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

Post to forums  

Forma Design Contest


Rail Community