Revitapi geometry got empty list

hi, I am now practising revitapi on getting the geometry, coz the built-in element.geometry somethings gives me null value
ok here is my script:

import clr
clr.AddReference('ProtoGeometry')
from Autodesk.DesignScript.Geometry import *
clr.AddReference("RevitNodes")
import Revit
clr.ImportExtensions(Revit.Elements)
clr.ImportExtensions(Revit.GeometryConversion)
clr.AddReference("RevitServices")
import RevitServices
from RevitServices.Persistence import DocumentManager 
from RevitServices.Transactions import TransactionManager 

clr.AddReference("RevitAPI")

import Autodesk 
from Autodesk.Revit.DB import *

doc = DocumentManager.Instance.CurrentDBDocument

input = UnwrapElement(IN[0])

options=Options()
geos = input.Geometry[options]
for geo in geos:
	if str(geo.GetType()) == 'Autodesk.Revit.DB.GeometryInstance':
		test = geo.GetInstanceGeometry()

OUT = test

what did I miss? thanks!!

Hello,
can you share the Revit file?

1 Like

I found that I got null for some of the beams
even using clockwork package

You have a solid (DB.Solid) at output


but for some reason the node can’t convert it to protoGeometry

2 Likes

is it the weakness of dynamo handling geometry?
no cure?
I heard rhino grasshopper is better in handling geometry

1 Like

You heard right. Revit is very unforgiving when it comes to working with geometry, sometimes it refuses to accept imports (that AutoCAD can take), and doesn’t usually give specific/clear reasoning as to why. Especially challenging when trying to convince designers Revit can be used for design.

A lot of geometry and analysis I take to Rhino these days. Works like a dream vs Revit for mesh and heavier solid analysis.

1 Like

By curiosity, can you share here (or via PM) the Revit family ?

1 Like

while that may be true. In this specific example, Revit is successfully outputting the geometry for use in a Revit API context, (Autodesk.Revit.DB.Solid).

Where this workflow is actually falling apart is in the Dynamo side with the ToProtoType converters, (Solid converters are here).

@GavinCrump - I realize it is the “cool” thing to do to bash Revit and say, “RHiNo iS bETteR”, which I can agree with in a lot of instances. But in this case, and I mean this respectfully, you’re assumption re: Revit not handling the geometry is simply incorrect, (because once again, this is happening on the Dynamo conversion portion).


The best thing OP can do is first, supply a sample file here for us to help further (we don’t even know the Revit version at this point), then, open a Github Issue, supply the sample Revit file and the team can refine/work on the converters for solids regarding Dynamo geometry. This is how Dynamo becomes better.

9 Likes

I’m not trying to be cool or edgy, I’m just trying to encourage people to explore other options. I genuinely feel that Dynamo for data and Rhino(Inside) form a solid combination when both learnt that help plug each others limitations or weaker aspects.

I know we’re on Dynamo forums here, so I get that it’s not the most ‘helpful’ answer but at the same time I think it’s helpful to have some confirmation on what they’ve heard and specifically mentioned. If they hadn’t mentioned it then I probably wouldn’t have bothered bringing it up.

Sorry if it ruffles anyones feathers/rubs people the wrong way. Not my intent here.

It’s no problem at all. I think mentioning the other ones is fine and it doesn’t matter that this is the “Dynamo forum”. I didn’t post my reply to scold for mentioning an alternative product.

I replied because the statement re: Revit’s handling of the geometry is still incorrect regardless. It is most definitely the Dynamo converter itself (separate from the Revit API) that is the issue. If Rhino or whatever else successfully converts that solid, that’s cool. That just means that the Dynamo converter needs to adopt a similar method.

Either way, there is no sample file to reproduce the issue, so you can’t even prove that the alternative methods do work at this time with OPs specific Revit element.

5 Likes

test.rvt (5.0 MB)

hello you can check on this one, the beam in the middle I cannot find its geometry.

2022-03-21_09h37_13
OK, i don`t know this error

is it costum family?

@newshunhk Given that we can get the solid, we are able to at least see the problem, and perhaps use a creative method to approximate a reconstruction of the solid, if that is acceptable
?

Apologies to Clockwork for butchering Mr Dieckmann’s code :slight_smile:

Mark

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

clr.AddReference("RevitNodes")
import Revit
clr.ImportExtensions(Revit.Elements)
clr.ImportExtensions(Revit.GeometryConversion)

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

# this function takes care of exploding 
# GeometryInstance objects. GI objects typically
# represent family instance geometry.
# in order to also catch possible nested families
# the fucntion calls itself recursively.
def convert_geometry_instance(geo, elementlist):
	for g in geo:
		if str(g.GetType()) == 'Autodesk.Revit.DB.GeometryInstance':
			elementlist = convert_geometry_instance(g.GetInstanceGeometry(), elementlist)
		else:
			try: 
				if g.Volume != 0:
					elementlist.append(g)
			except:
				pass
	return elementlist

doc = DocumentManager.Instance.CurrentDBDocument
items = UnwrapElement(IN[0])
if IN[1] == "Coarse": detail_lvl = ViewDetailLevel.Coarse
elif IN[1] == "Fine": detail_lvl = ViewDetailLevel.Fine
else: detail_lvl = ViewDetailLevel.Medium
inc_invis = IN[2]
view = UnwrapElement(IN[3])
inserts = UnwrapElement(IN[4])
remove_inserts = IN[5]
revitlist = list()
dynlist = list()
catlist = list()
# we might need a transaction in order to 
# temporarily delete all inserts and retrieve gross wall areas
TransactionManager.Instance.EnsureInTransaction(doc)
trans = SubTransaction(doc)
trans.Start()
i = 0
for item in items:
	if remove_inserts == True:
		for insert in inserts[i]:
			doc.Delete(insert.Id)
		doc.Regenerate()
	geo_options = Options()
	if view == None: geo_options.DetailLevel = detail_lvl
	geo_options.IncludeNonVisibleObjects = inc_invis
	if view != None: geo_options.View = view
	revitGeo = item.Geometry[geo_options]
	try:		
		revit_geos = convert_geometry_instance(revitGeo, list())
		revitlist.append(revit_geos)
		dyn_geos = list()
		cats = list()
		for geo in revit_geos:
			try:
				dyn_geos.append(geo.ToProtoType())
			except:
				dyn_geos.append(None)
			try:
				graphstyle = doc.GetElement(geo.GraphicsStyleId)
				if graphstyle != None:
					cats.append(Revit.Elements.Category.ById(graphstyle.GraphicsStyleCategory.Id.IntegerValue))
				else:
					cats.append(None)
			except:
				cats.append(None)
		dynlist.append(dyn_geos)
		catlist.append(cats)		
	except:
		revitlist.append(list())
		dynlist.append(list())
		catlist.append(list())
	i += 1
trans.RollBack()
TransactionManager.Instance.TransactionTaskDone()

facesOut = []
edgesOut = []

for solidList in revitlist:
    for solid in solidList:
#        for face in solid.Faces:
#            facesOut.append(face.ToProtoType())
         for edge in solid.Edges:
             edgesOut.append(edge.AsCurve().ToProtoType())    

OUT = edgesOut#facesOut#(dynlist,revitlist,catlist)

EDIT:

From memory, these kinds of operations can be very systematic, ie. whichever element is interrogated, the geometry is returned in a predictable way. Hopefully this is the case for you
 (group Curves is Archilab)

4 Likes

Hi,
here another workaround geometry conversion, using Solid.ByJoinedSurfaces() (only for solids with planar faces)

import clr
import System
import sys
clr.AddReference('ProtoGeometry')
from Autodesk.DesignScript.Geometry import *
import Autodesk.DesignScript.Geometry as DS


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

clr.AddReference("RevitNodes")
import Revit
clr.ImportExtensions(Revit.Elements)
clr.ImportExtensions(Revit.GeometryConversion)

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

	
def get_AllSolid(lst_elem, inc = 0):
	# sub functon
	def populate_lstGeo(g):
		if isinstance(g, Solid) and g.Volume > 0: 
			solids.append(g)
		elif isinstance(g, GeometryInstance):
			geoInst.append(g)
		else:pass
	#
	# main  recursive function		
	global opt
	solids = []
	geoInst = []
	lst_elem = lst_elem if hasattr(lst_elem, "__iter__") else [lst_elem]
	if len(lst_elem) > 0 and inc < 2000:
		for elem in lst_elem:
			if isinstance(elem, GeometryInstance):
				for j in elem.GetInstanceGeometry():
					populate_lstGeo(j)			
			else:
				geoSet = elem.get_Geometry(opt)
				for i in geoSet:
					populate_lstGeo(i)
		return solids + get_AllSolid(geoInst, inc + 1)
	else:
		return []
		

elem = UnwrapElement(IN[0])

opt = Options()
solids = get_AllSolid(elem)

ds_Solids = []
for s in solids:
	try:
		ds_Solid = s.ToProtoType()
		ds_Solids.append(ds_Solid)
	except:
		# failed conversion DB.Solid to Solid Prototype -> try get make Solid with ByJoinedSurfaces 
		ds_face = []
		for f in s.Faces:
			try:
				ds_face.extend(f.ToProtoType())
			except:
				# failed conversion DB.Face to Prototype -> try get make Surface with PolyCurves.Patch() 
				ds_edges = [c.ToProtoType() for curveloop in f.GetEdgesAsCurveLoops() for c in  curveloop]
				ds_poly_edges = PolyCurve.ByJoinedCurves(ds_edges)
				ds_face.append(ds_poly_edges.Patch())
		ds_Solid = DS.Solid.ByJoinedSurfaces(ds_face)
		ds_Solids.append(ds_Solid)
		

OUT = ds_Solids
6 Likes

Maybe you could add this as a pull request? :smiley:

2 Likes

The problem, this workaround work only for planar Faces
 I have no solution if the bug come from a curved face

1 Like

I think curved works, just not maybe double curved?

Still though, if this is an edge case, perhaps 5%
 and the workaround catches 80% of the rest, it might a worthwhile improvement


Cheers,

Mark

I also had a post shared here before, I was in a lot of pain with some such projects

At the moment, im using rhino inside revit for some project like that


Home.dyn (3.8 KB)
let rename to gh
unnamed.gh.dyn (2.5 KB)

4 Likes

works with @chuongmep file example

I open a new issue and propose this workaround

4 Likes

For curvilinear geometries, it’s still a big obsession. :neutral_face:

3 Likes