Mass GetGeneratingElementIds()

Hi,
Can the method GetGeneratingElementIds() retrieve the edges of a Mass object or the 2D geometry that creates it?
If no, then which method, if any?

You want to use yourMass.get_Geometry(Options()). From here you can traverse the geometry to get the edges. Perhaps this thread will help…

As for the 2D sketch profile that creates the mass, this (from memory) I don’t think can be accessed by the Revit API, however, there might be a trick to getting this similar to this article…

2 Likes

Thanks.
My question is a bit general and more about GetGeneratingElementIds() 's potential than how to extract a geometry. The method’s name is promising.
However, when using enu.Current to get the geometry from a mass the returned object is not a geometry but a GeometryInstance

Your question actually was…

The Long answer is as follows…

No…This is not quite what GetGeneratingElementIds does, in most cases this will just give you back the Element which created that Geometry (i.e. the Mass you trying to get the Geometry from), in some specific cases that Geometry was created by an operation between two or more Elements, it will return the Elements that form the Geometry (this could be when walls are mitered, using GetGeneratingElementIds() on the diagonal face would return both the walls that form part of the face, on all other faces it would return just the wall the Geometry it belongs to… make sense? :slight_smile:)

In your case you use the get_Geometry method. It’s there to get the geometry, this is precisely what it’s for. From there you get the a geometry element, from which you can get the instance geometry, then get the solids if any present and then get faces of the solid and then get edges.

Here is some code which dives a little deeper into what you want to do and maybe less ambiguous than explaining in plain english…

Element | GetEdgesExample | Py

This is pretty standard code for getting the Geometry from an Element. I have thrown in the GetGeneratingElementIds() in there to show that this doesn’t do what you hope it might. For further reading, see this API docs and read the remarks section…

"""
Description: Demonstrates how to GetGeometry from Element and why this is not what GetGeneratingElementIds() is.
Author: Dan Woodcock
Website: https://danimosite.wordpress.com/
Licence: Buy me a beer
"""
##### Imports #####
import clr

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

clr.AddReference("RevitServices")
import RevitServices
from RevitServices.Persistence import DocumentManager
doc =  DocumentManager.Instance.CurrentDBDocument

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

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

"""
Description: Wraps single object in array.
Args:
	obj1 = an object
Returns: array[obj1]
"""
def tolist(obj1):
	if hasattr(obj1,"__iter__"): return obj1
	else: return [obj1]

"""
Description: Gets the Solids from an Element
Args:
	e = The Element to operate on
Returns: An array of Revit Solids.
"""
def GetSolids(e):
	arr = []
	eGeom = e.get_Geometry(Options())	
	for g in eGeom:		
		if g.GetType() == GeometryInstance:
			ig = g.GetInstanceGeometry()
			if not ig == None:
				if ig.GetType() == GeometryElement:
					for ge in ig:
						if ge.GetType() == Solid and not ge.Faces.IsEmpty:
							arr.append(SolidUtils.Clone(ge))
							continue
				if ig.GetType() == Solid and not ig.Faces.Empty:
					arr.append(SolidUtils.Clone(ge))
					continue
		if g.GetType() == Solid and not g.Faces.IsEmpty:
			if not g.Faces.IsEmpty:
				arr.append(SolidUtils.Clone(g))			
	return arr	

"""
Description: Joins an Array of Revit Solids into one Solid.
Args:
	arr = array of Revit Solids
Returns: Single Revit Solid
"""
def JoinSolids(arr):
	try:
		cSld = arr[0]	
		if len(arr) > 1:
			arr.pop(0)
			for s in arr:
				cSld =  BooleanOperationsUtils.ExecuteBooleanOperation(cSld,s,BooleanOperationsType.Union)	
		return cSld
	except:
		return None

##### Inputs #####

# The Mass Element...
m = tolist(UnwrapElement(IN[0]))[0]

##### Outputs #####

crvLoops = []

##### Main #####

# Here we will test for GeneratingElementIds (Which should just returns the Mass Element as this is what Generated the Geometry)...
genElems = [doc.GetElement(e) for e in m.GetGeneratingElementIds(m.get_Geometry(Options()))]

# Here we will get the actual Solid Geometry from the Element...
sld = JoinSolids(GetSolids(m))

# Now we will get all the EdgeLoops from all the Solids faces...
loops = [f.EdgeLoops for f in sld.Faces]

# From the EdgeLoops, we will iterate through the Loops and return the Curves as a single DS Polycurve...
for lps in loops:
	for lp in lps:
		crvLoops.append(geom.PolyCurve.ByJoinedCurves([c.AsCurve().ToProtoType() for c in lp]))		

# Return the results to the graph...
OUT = crvLoops, genElems

Mass | GetProfiles | Py
Slightly non-standard way to get the Sketch Profiles although used quite often for this specific purpose. This technically temporarily deletes the Element, by deleting we can get ALL the related Elements to this given Element (i.e. the Sketch Profile in this case)…

  """
Description: Get the Sketch profiles for the given Mass Elements.
Author: Dan Woodcock
Website: https://danimosite.wordpress.com/
Licence: Buy me a beer
"""
 
###### Imports ######
 
import clr
 
clr.AddReference('ProtoGeometry')
from Autodesk.DesignScript import Geometry as geom
 
# Import Revit Services as we need the doc and TransactionManager...
clr.AddReference("RevitServices")
import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager
doc =  DocumentManager.Instance.CurrentDBDocument
 
# Import Revit Nodes and Geometry Extensions...
clr.AddReference("RevitNodes")
import Revit
clr.ImportExtensions(Revit.Elements)
clr.ImportExtensions(Revit.GeometryConversion)
 
# Import the Revit API...
clr.AddReference("RevitAPI")
from Autodesk.Revit.DB import *
 
###### Definitions ######
 
"""
Ensures object is a List and not a singleton.
"""
def tolist(obj1):
    if hasattr(obj1,"__iter__"): return obj1
    else: return [obj1]

###### Inputs ######
 
elems = tolist(UnwrapElement(IN[0])) # The In-Place Elements...

###### Output ######
 
outList = [] # The output list...
 
###### Main ######
 
# Need to force close other transactions here to ensure new transaction can start...
TransactionManager.Instance.ForceCloseTransaction() 
 
for e in elems: 
    # Check if Family is In-Place...
    if not e.Symbol.Family.IsInPlace:
        outList.append(None)
        continue
         
    eids = [] # Empty variable to store Deleted ElementIds...
         
    # Create a new Revit API Transaction...
    t = Transaction(doc, "Temp")
    # Start the Transaction...
    t.Start()   
    # Get deleted ElementIds...
    eids = doc.Delete(e.Id) 
     
    # Rollback the transaction to undo the delete...
    t.RollBack()    
    
    # Test to see if there are any Sketches deleted...
    sketches = [doc.GetElement(id) for id in eids if doc.GetElement(id).GetType() == Sketch]
    
    arr = []
    # Try get the profile curves of the Sketches. If successful, then give back DS Polycurve...
    for s in sketches:
    	try:
    		prof = s.Profile
    		if prof:    			
    			for lp in prof:
    				arr.append(geom.PolyCurve.ByJoinedCurves([l.ToProtoType() for l in lp]))
    	except Exception, ex:
    		continue
    
    outList.append(arr)

###### Output ######
 
OUT = outList

Hope this helps…please have a good look at the GetSolids() definition in the first example and how you need to traverse through to get what you actually want. :wink:

Cheers,
Dan

2 Likes