Best efficient way to get the bottom closed loop edges of a mass solid geometry made by vertical extrusion

I am looking how to resolve this in ironpython2.7 script, the best efficient way to get the bottom closed loop edges of a revit mass element, its solid geometry made by vertical extrusion.

I was thinking a process of getting things like this: element mass ==> solid geometry ==> solid surfaces ==> get bottom surface ==> get surface perimeter curves, but maybe it is too expensive high time consuming, I wonder if there is a intelligent wat to do it, I was thinking element mass ==> solid ==> vertexes ==> rebuild bottom curves byjoining clockwise vertex points. I was just hinking intersect a plane through the geometry and get edges directly but not sure what is best faster to compute, i have no idea. the mass element can be a loadable family or a family in-place, I just say will be always like a vertical extrusion of a bottom boundary, but let say other day can be a more complex geometry not extrusion vertical, so I am thinking in projection of edges into a plane

Hi @rrvivancosWTL

I don’t think you’ll save much time between the two methods.

This lacks a bit of context.

  • How much mass do you need to extract from the geometry?
  • Can you filter out unnecessary elements beforehand?
  • Have you releases the resources from the object geometry with Dispose() ?
  • Do you have an simple example file to share?
1 Like

let say the mass elements are made of vertical extrusion of a close loop boundary, I have not done anything like Dispose(), I do not have an example yet, I am trying to figure out which is fastest way for computer to achieve results before i even try

Designscript maybe

I’ve never seen a comparison to any other method, can’t tell

If you are open to Python I would try this:

  1. Get the solid
  2. Extract the faces
  3. Get the faces which have a normal with a Z component less than 0.5 or get the faces who have a point at parameter 0.5,0.5 which have a Z component equal to the Z component of the solid’s min point (the later is slower but more robust into the future.
  4. For each face, extract the curve loops
  5. For each curve loop, extract the curves and union to a polycurve.

I would not recommend using the vertex method you proposed as curved edges are a thing you lose entirely and you won’t want to find out they had to be accounted for well after the fact.

The perimeter curves of the surface will also work well but curve loops and faces will be faster and more readily account for donut faces.

3 Likes

something direct like project to XY plane all the mass geometry? anything straight forward that could help?

The Python method I outlined above will be faster, but you could project the solid onto a plane as well.

1 Like

what function does this “project the solid onto a plane” using Revit API or python libraries?, I know in AutoCAD there is just a function to do that, in spanish is called GEOPLANA, in english maybe is something like 2D shot

Python would be my direction, but again you’ll get significantly better performance with the method I noted above.

something like tessellation function maybe?

Why are you going the harder and non-performative route instead of the one above?

because i want to test against million elements

So you have more than one element… why would you want taht to run even slower?

Topology.Faces > Filter to base face > Faces.Loops > Loops.CoEdges > CoEdge.Edges > Edge.CurveGeometry

The work is multiple orders of magnitude faster than what you’ll get with any geometry modification which is what you’re describing, and the larger the dataset the slower the modifications will be.

1 Like

Had 10 minutes to spare so I whipped this up:

import clr #add the common language runtime (CLR) to the Python environment 
clr.AddReference('ProtoGeometry') #add the Dynamo geometry namespace to the CLR
from Autodesk.DesignScript.Geometry import * #import the entirety of the Dynamo geometry namespace to the Python environment 

slds = IN[0] #the solids from the Dynamo environment
if not slds.__class__ == list: slds = [slds] #if a list wasn't provided as the input convert it to one
results = [] #set results
outlineOnly = false #boolean variable to control if you want to extract only exterior edges

for sld in slds: #for each solid
    result = [] #empty list for the result of the processed solid
    faces = [i for i in sld.Faces if i.SurfaceGeometry().NormalAtParameter(0.5,0.5).Z == -1] #as you indicated you have extruded sketches there can only be one downward pointing face, but this will get it and others to account for separated curve loops in the sketch
    for face in faces: #for each face
        loops = face.Loops #get the loops
        if outlineOnly: loops = [i for i in loops if i.IsExternal] #removes any interior loops if outlineOnly is set to true
        for loop in loops: #for each loop 
            coEdges = loop.CoEdges #get the coeges
            crvs = [coEdge.Edge.CurveGeometry for coEdge in coEdges] #convert the coedges to curves 
            loop = PolyCurve.ByJoinedCurves(crvs,0,0,0) #build a polycurve from the curv es
            result.append(loop) #append the curve to the result list
    results.append(result) #append the result to the results

OUT = results #return the results
1 Like

I am thinking the way to take the boundary sketch that originates the solid geometry, like for example room/space of revit is made from closed loop curves sketch in a horizontal plane level, then it extrudes vertically or fills the forms of the elements that create boundaries, so i suppose in revit api there is a function to take directly those curve loops without having to get the element geometry, the solid, the faces, the edges or points and rebuild a close loop from points unnecessarily. maybe is something like this? SpatialElementBoundaryLocation Property;

so I am thinking how to go to a mass family made in place in the same way that room/space is created with a sketch in a horizontal plane and extruded vertically so I could take the original sketch directly which originates that solid, let say the mass is made of one solid made of extrusion

It has been awhile since I have looked at it so I may be wrong, but the minute you said “in place family” the ability to access the sketch data programmatically is lost as there is no access to the in place family editor in the API. If you had loadable families you can:

  1. Open the document
  2. Get the form(s)
  3. Extract the sketch from the forms
  4. Pull the curve loops from the sketch

If my memory is correct, with in place all you can do is start to interrogate the element. So that workflow would look something like this:

  1. Query the geometry of the instance
  2. Convert to solids
  3. Extract the faces
  4. Extract the loops

All 4 of those steps are doable but in a much more difficult way then I showed with the Python above.

someone told me this, which matches somehow with your answer:

Mass (in-place “Mass” family, vertical extrusion case)

  • There’s no single universal API that returns the “original sketch profile” for every kind of mass form.
  • What you can do depends on how the mass was built:

A) Traditional sketch-based solids (Extrusion/Blend/Revolve/Sweep/SweptBlend) inside a family

  • If your mass were one of those (common in many non-mass family templates), you can open the family doc and read the Sketch:
famDoc = doc.EditFamily(fi.Symbol.Family)        # fi = FamilyInstance in project
exts = FilteredElementCollector(famDoc).OfClass(Extrusion)
for ex in exts:
    sk = ex.Sketch                                # Autodesk.Revit.DB.Sketch
    for loop in sk.Profile:                       # CurveArrayArray
        for c in loop:                            # CurveArray
            # c is a Curve from the original profile
            pass

Then transform those curves into project coordinates using the family instance’s transform.

B) Conceptual Mass Form (what “In-Place Mass” usually creates)

  • Most in-place mass geometry is stored as Form / GenericForm (lofts, extrusions, voids). These do not expose their generating profiles via a Sketch property. The original ModelCurves may still exist, but the API doesn’t give a reliable 1:1 mapping from those curves back to a particular Form.
  • Practical workaround (fast and robust):
    1. Read the mass Solid once.
    2. Grab a horizontal planar face (bottom/top) and read its edge loops (these are the profile rings as built).
      You can use face.EdgeLoops (EdgeArrayArray) and edge.AsCurve() to recover loops directly.
    3. Cache those loops; you now have the “sketch” rings you wanted, without recomputing from scattered vertices.

Right - and as noted above each step including ‘get geometry’ of type B will be more difficult in Revit. If you don’t have a good reason for staying in Revit you’re likely best suited to take the Python above, run it, and move on with the day as the project would be done by now.