Getting max curve Length from geometry edges using API

Hi everyone, @Mike.Buttery

I can by using the code below obtain the max radius of all arcs in the geometry as shown in this image

I can output the entire lines in the geometry as shown below, but I can’t using the same approach as above obtain the max length, which is located at the max radius?

Here my code

import clr
from math import pi

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

clr.AddReference("RevitNodes")
import Revit
from Revit.GeometryConversion import *
clr.ImportExtensions(Revit.GeometryConversion)

clr.AddReference("RevitAPI")
from Autodesk.Revit.DB import Arc, UnitUtils, UnitTypeId, Options, Transform, XYZ

# Helper functions
metres = lambda iu: UnitUtils.ConvertFromInternalUnits(iu, UnitTypeId.Meters)
degrees = lambda rad: UnitUtils.Convert(rad, UnitTypeId.Radians, UnitTypeId.Degrees)

# Inputs
pipe = UnwrapElement(IN[0])
rebar = UnwrapElement(IN[1])

# Get geometry (Largest circle at lowest point)
geom = pipe.get_Geometry(Options())
solids = list(geom.GetTransformed(Transform.Identity))[1]
curves = [e.AsCurve() for e in solids.Edges]
arcs = [c for c in curves if "Arc" in c.ToString()]
lines= [c for c in curves if "Line" in c.ToString()]
max_r_arc = max(arcs, key=lambda c: c.Radius).Radius
max_L_Line = max(lines, key=lambda c: c.Length).Length

OUT = max_r_arc, lines, max_L_Line

Any help would be apreciated

Thanks.

Hello,
you can get the height with a boundingbox (Zmax-Zmin)

cordially
christian.stan

1 Like

@christian.stan
I’m not looking for the height value, I’m looking for this particular line at that specific location which I can use later in my code

Thanks

Try this line so we can look into what is going on.

dbg = [[c, c.ToProtoType(), c.Length] for c in lines]
OUT = dbg

at the same time a height, you can easily transform it into a line
I don’t know if it’s more resource-intensive to exploit existing geometry. (your object is well centered in a bb) reflection can arise, it only remains an opinion.

edit: after reflection you do not obtain a 4m line (remain logical it is a surface which joins your arcs)
the 0.80m is good, it’s your hopper I think

cordially
christian.stan

1 Like

@jacob.small

I followed your suggestion and generated an output as shown below, but none of the lengths correspond to what I’m looking for! (I only obtained lengths of the shape mentioned in the image!)

I then attempted to track the line using its corresponding coordinates as shown below, but once again, it does not exist in the output list?

I wonder if I can obtain this line without exploding the geometry!?

Thanks.

@christian.stan
Your suggestion is a last resort option. :wink:

1 Like

Looks like an issue with the geometry as you are pulling it. We will need an RVT and your current dyn to diagnose.

1 Like

@jacob.small

Be kind to check my Revit and dyn files below

curve_shaft.rvt (7.4 MB)

curve_API.dyn (7.5 KB)

Thanks.

1 Like

I’ll have a look in the AM if someone else hasn’t found the issue before then - already shut down the CPU for the night.

1 Like

The Length parameter is in internal units so needs to be converted with the helper function
map(metres, [c.get_Length() for c in curves if "Line" in c.ToString()])

The shaft object is a FreeFormElement type and does not have a geometric line element that joins the upper and lower arcs, so in this instance the bounding box of the geometry makes some sense, access height as follows

bbox = geom.GetBoundingBox()
height = metres(bbox.Max.Subtract(bbox.Min).Z)

If you need the height line work from the Dynamo geometry - however there are 3 lines that are the maximum Z length

dynamo_geom = IN[0].Geometry()[0]
lines = [e.CurveGeometry for e in dynamo_geom.Edges if "Line" in e.CurveGeometry.ToString()]
max_line_length = max(lines, key=lambda l: l.Length).Length

OUT = [l for l in lines if l.Length == max_line_length]

In this case I think it would be better to build a Revit family for the structure if that is possible so that the required parameters for the rebar placement are easier to access

3 Likes

@Mike.Buttery

something is missing in the 3 lines you have put that desalow us getting the max_line_length ( as shown below the lines list is empty, so maybe it might be necessary to explode dynamo_geom before appending elements to lines , which would make the code work?)

I remember that I previously obtained that line in the same geometry using the GetIsoline node from surfaces that I acquired after exploding the geometry, as I mentioned earlier (see the code below)

element = IN[0]

geo = element.Geometry()
surfaces = geo[0].Explode()

s_area = []

for i in surfaces:
    s_area.append(i.Area)
    
S_area = ["%0.2f"%(round(i,2)) for i in s_area]
    
surf = []
surf_area = set()

for s, a in zip(surfaces, S_area):
    if a not in surf_area and S_area.count(a) == 2:
        surf.append(s)
        surf_area.add(a)
        

OUT = surf[1].GetIsoline(0, 1).Explode()[0]

Can we use the same approach directly in Revit geometry using the API to retrieve this line, just as we do with the BoundingBox?

edit:

I would like it to facilitate many things, but I cannot find the option to classify my family as a structural element when I initially created it as a generic model. Additionally, I am required to modify its properties and check the “can host a rebar” option each time I want to create my rebars. If you could guide me on how to create a structural family based on a generic model, it would be fantastic and save me a significant amount of time. (I will ask this question in a separate thread.)

Thanks.

Please read my response - this line does not exist in the Revit FreeFormElement geometry, hence using the bounding box to get a proxy for the line you want. The code is working with the shaft previously supplied - so rather than doubting the code - start exploring, ask why is it not working? Try fixing it yourself before jumping back into the comments

I think your time would be better spent exploring Revit yourself and getting to understand the mechanics of Revit, Dynamo, python and the API rather than using the forum at every roadblock

Seek to understand and not just copy

You can change the Family Category by editing the family, using the ‘Family Category and Parameters’ dialogue. This information is available with a search or on the Autodesk Support site. Structural elements Columns/ Foundations/ Framing automatically host rebar

2 Likes

@Mike.Buttery
I appreciate your help, but I don’t appreciate that you’re prejudging me. Who told you that I didn’t try to understand the code and fix it before providing feedback on the forum? I’m not just copying code without understanding it. When I ask a question in the forum, it’s only after exhausting all ways, such as exploring Revit, Python, and trying to understand things. Otherwise, I wouldn’t have asked the question.

Returning to the question, how can you explain that the code was working when I only outputted the list ‘lines’ without making any changes, and I received an empty list?

I know how to change a family’s category and its parameters using the UI, but my question is how we can access a family previously created with Revit nodes inside dynamo via the API and change its property to ‘can host rebar’ without the need to use the UI. Furthermore, I’ve asked this question here."

Thanks.

Friendly reminder to everyone involved here that we are all doing our best to help each other out. Please refrain from engaging in attacks on each other. No one has crossed any lines yet, but I don’t want anything to escalate as we all benefit from everyone participating.

4 Likes

Hi @REDO10 ,

Could you maybe explain from the top what exactly you’re trying to do?
I understand that you’ve written some code that retrieves the biggest arc, and its radius, through your python script. Then following that you want to find a vertical line? Based on what parameters? The shortest line between the 2 curves with the biggest radius?

Perhaps something like this can help you get to what you want: (this at least gives a result of a length 4.)


curve_API.dyn (39.0 KB)

1 Like

@REDO10
Apologies for responding in haste.
The issue is that I am working in Dynamo v.2.18.1 (2024) and you are in v.2.12.0 (2022). Between the versions the Edges attribute of a geometry element has changed - Current Dynamo devolves the elements to their base Dynamo class (Arc, Line etc.) whereas old school Dynamo returns the edges as curve geometry. We can handle this issue with the following code which works on both versions

dynamo_geom = IN[0].Geometry()[0]
lines = [e.CurveGeometry.Explode()[0] for e in dynamo_geom.Edges]
lines = [l for l in lines if "Line" in l.ToString()]
max_line_length = max(lines, key=lambda l: l.Length).Length

OUT = [l for l in lines if l.Length == max_line_length]

This returns two lines which are both located on the largest arc

1 Like

@Mike.Buttery

Your apology is accepted!

I’m currently traveling and don’t have the opportunity to try what you tried. After my return, I will test your proposal and see how it goes.

Thanks.

1 Like

@Mike.Buttery

I tested your code, and it works now. As I mentioned above, we can’t get this line without exploding the geometry as you did (we can do that only with DesignScript ). However In API, we can obtain this line only by using BoundingBox , according to what I understand from you!

Your proposition solve my issue

Edit:
From what I know, it is not recommended to combine ‘DesignScript’ with the ‘API’ in the same script. But if I decide to use ‘DesignScript’ to obtain this line, should I create a separate script for it?

Thanks.

Geometry is different from Revit automation. Utilizing the Dynamo geometry library isn’t really an issue if you are conscious about how you do it (import one of the geometry classes - likely Dynamo - using an alias; limit the conversion count to a one direction action and don’t ‘round trip’ from Revit to Dynamo to Revit) and things should be fine.

1 Like