Getting solid from columns in Revit API

Hi all,

I’m trying to understand an issue related to retrieving solid geometry from structural columns.
As shown in the image below, when dealing with isolated columns, the code below does not return any solid geometry. However, when the same code is executed on columns connected to beams, the solids are successfully retrieved.

Please check my code here:

import clr
import sys
import System
from System.Collections.Generic import IList, List

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

clr.AddReference('RevitAPI')
import Autodesk.Revit.DB as DB
from Autodesk.Revit.DB import *
from Autodesk.Revit.DB.Structure import *

clr.AddReference('RevitNodes')
import Revit
clr.ImportExtensions(Revit.GeometryConversion)

clr.AddReference('RevitServices')
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager

doc = DocumentManager.Instance.CurrentDBDocument


clr.AddReference("System.Core")
clr.ImportExtensions(System.Linq)


    
def get_solid(column):
    options = Options()
    options.IncludeNonVisibleObjects = False
    options.DetailLevel = ViewDetailLevel.Fine
    geoElement = column.get_Geometry(options)
    
    return next((g for g in geoElement if isinstance(g, Solid) and g.Volume > 0), None)    
    

columns = list(FilteredElementCollector(doc)\
    .OfCategory(BuiltInCategory.OST_StructuralColumns)\
    .WhereElementIsNotElementType()\
    .ToElements())

    
OUT = [get_solid(col) for col in columns]

Could anyone please clarify why this difference occurs or what might cause isolated columns to return no solids?

Thanks.

Got a model to test on? I can’t recreate the issue on my end with the out of the box tools for geometry conversion.

1 Like

Hi,

try to also process GeometryInstance(s)

an example

def getSolidfromGeo(elem):
	opt = Options()
	opt.ComputeReferences = True
	opt.IncludeNonVisibleObjects = True
	geoSet = elem.get_Geometry(opt)
	#
	for geo in geoSet:
		if isinstance(geo,Solid) and geo.Volume > 0 :	
			return geo, "Geometry"
	for geo in geoSet:
		if isinstance(geo, GeometryInstance):	
			outSolid = []
			geoSetInst = geo.GetInstanceGeometry()
			for geoI in geoSetInst:
				if isinstance(geoI,Solid) and geoI.Volume > 0:
					outSolid.append(geoI)
			outSolid.sort(key = lambda x : x.Volume )		
			print(len(outSolid))
			return outSolid[-1], "GeometryInstance"
	return None, None
3 Likes

@c.poupin
I was wondering if it’s possible to return the solid geometry as an instance directly from the main GeometryInstance itself (I mean, getting the solid geometry from the main transformed GeometryInstance)…for that I refactored your code for testing, and it gives the response for my question, as shown in the image below:

refactored code:

import clr
import sys
import System
from System.Collections.Generic import IList, List

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

clr.AddReference('RevitAPI')
import Autodesk.Revit.DB as DB
from Autodesk.Revit.DB import *
from Autodesk.Revit.DB.Structure import *

clr.AddReference('RevitNodes')
import Revit
clr.ImportExtensions(Revit.GeometryConversion)

clr.AddReference('RevitServices')
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager

doc = DocumentManager.Instance.CurrentDBDocument


clr.AddReference("System.Core")
clr.ImportExtensions(System.Linq)


    
def getSolidfromGeo(elem):
	opt = Options()
	opt.ComputeReferences = True
	opt.IncludeNonVisibleObjects = True
	geoSet = elem.get_Geometry(opt)
	#
	for geo in geoSet:
		if isinstance(geo,Solid) and geo.Volume > 0 :	
			return geo, "Geometry"
	for geo in geoSet:
		if isinstance(geo, GeometryInstance):	
			outSolid = []
			geoSetInst = geo.GetInstanceGeometry()
			for geoI in geoSetInst:
				if isinstance(geoI,Solid) and geoI.Volume > 0:
					outSolid.append(geoI)
			outSolid.sort(key = lambda x : x.Volume )		
			print(len(outSolid))
			return outSolid[-1], "GeometryInstance"
	return None, None
	
def column_edge(column, solid):
    
    curveloops = [face.GetEdgesAsCurveLoops() for face in solid.Faces][2]
    
    edges = list(curveloops[0])
    plane = curveloops[0].GetPlane()
    skp = SketchPlane.Create(doc, plane)
    curves = [doc.Create.NewModelCurve(e, skp) for e in edges]

    return curves
	
columns = list(FilteredElementCollector(doc)\
    .OfCategory(BuiltInCategory.OST_StructuralColumns)\
    .WhereElementIsNotElementType()\
    .ToElements())

Curves = []

with Transaction(doc, 'create ModelLines') as t:
    t.Start()
    for col in columns:
        solid = getSolidfromGeo(col)[0]
        crv = column_edge(col, solid)
        Curves .append(crv)
    t.Commit()


OUT = [c.GeometryCurve.ToProtoType() for list in Curves for c in list]

Thanks.

1 Like