How to get the size of an assembly instance?

How to get the size of an assembly instance? I do not know the size of the assembly because it has no geometry.

The assembly location is not necessarily the geometric centre of all the elements of the assembly, I wish but not the case.

Any idea without crashing dynamo to resolve this? Do I need to take the geometry of the elements in the assembly to know this or can I query just the assembly elements?

Thanks

Get the member ids of the assembly then the bounding box(ed) of the elements.

2 Likes

thanks for the response, I already took the bounding box of all the assembly elements and get the bounding box of each and combine and get the centroid of the combined bounding box and the point that I get is identical than the assembly instance element Location.

import clr
clr.AddReference('RevitAPI')
from Autodesk.Revit.DB import BoundingBoxXYZ, XYZ

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

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

clr.AddReference('ProtoGeometry')
from Autodesk.DesignScript.Geometry import BoundingBox, Point

doc = DocumentManager.Instance.CurrentDBDocument
assemblies = UnwrapElement(IN[0])
union_bounding_box = None

for assembly_instance in assemblies:
    memberslist = assembly_instance.GetMemberIds()
    for member_id in memberslist:
        element = doc.GetElement(member_id)
        bounding_box = element.get_BoundingBox(None)

        # If this is the first bounding box, use it to initialize the union bounding box
        if union_bounding_box is None:
            union_bounding_box = bounding_box
            continue
        
        # Extend the union bounding box to include this element's bounding box
        union_bounding_box.Min = XYZ(
            min(union_bounding_box.Min.X, bounding_box.Min.X),
            min(union_bounding_box.Min.Y, bounding_box.Min.Y),
            min(union_bounding_box.Min.Z, bounding_box.Min.Z)
        )
        union_bounding_box.Max = XYZ(
            max(union_bounding_box.Max.X, bounding_box.Max.X),
            max(union_bounding_box.Max.Y, bounding_box.Max.Y),
            max(union_bounding_box.Max.Z, bounding_box.Max.Z)
        )

# Convert the Revit bounding box to Dynamo bounding box
min_point = union_bounding_box.Min.ToPoint()
max_point = union_bounding_box.Max.ToPoint()

# Calculate the centroid of the bounding box
centroid_x = (min_point.X + max_point.X) / 2
centroid_y = (min_point.Y + max_point.Y) / 2
centroid_z = (min_point.Z + max_point.Z) / 2
centroid_point = Point.ByCoordinates(centroid_x, centroid_y, centroid_z)

# Output the centroid point
OUT = centroid_point

displaying the geometry in Revit 3D view you can see what is the bounding box of the combined bounding boxes of the assembly elements, the centroid is highlighted with a sphere, although you can imagine the geometry of the elements within the assembly because they are the blue points and lines, so for me that does not make sense, the centroid should be more in the centre to the left of the image instead.

1 Like

the node Elements.solid is a killer, I am not going to do that for sure

with identical density for each of the solids
(which is often the case)
cordially
christian.stan

1 Like

Use that to build out your python. Teaching you how to fish instead of handing off a completed solution.

1 Like
centroids = [] #empty list to hold the assemblies
for assembly in assemblies: #for each assembly
    memberIds = assembly.GetMemberIds() #get the member ids
    members = [doc.GetElement(i) for i in memberIds] #get the members
    geo = [i.get_Geometry(Options()) for i in members] #get the goemetry 
    solids = [i for geoset in geo for i in geoset if i.__class__ == Autodesk.Revit.DB.Solid] #filter out non-solids and returna flat list
    solid = solids.pop() #get one solid from the list
    for s in solids: #for each remaining solid in the list of solids
        solid = BooleanOperationsUtils.ExecuteBooleanOperation (solid,s,BooleanOperationsType.Union) #merge each solid in sequence
    centroid = solid.ComputeCentroid() #compute the centroid of the unioned solid
    centroids.append(centroid.ToPoint()) #append the centroid to the list of centroids
1 Like

bloody Revit why so complicated, I modified the python script, now makes sense you can see the difference of centroid point between using bounding boxes of assembly elements and solid geometry of assembly elements, but the geometry of some pipe element is wrong therefore the combined bounding box size or combined solid size is not correct.

import clr
clr.AddReference('RevitAPI')
from Autodesk.Revit.DB import BooleanOperationsUtils, BooleanOperationsType, Options, Solid

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

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

doc = DocumentManager.Instance.CurrentDBDocument
assemblies = UnwrapElement(IN[0])
centroids = [] # Empty list to hold the centroids

for assembly in assemblies: # For each assembly
    memberIds = assembly.GetMemberIds() # Get the member ids
    members = [doc.GetElement(i) for i in memberIds] # Get the members
    geo = [i.get_Geometry(Options()) for i in members] # Get the geometry
    solids = [i for geoset in geo for i in geoset if i.__class__ == Solid] # Filter out non-solids and return a flat list
    solid = solids.pop() # Get one solid from the list
    for s in solids: # For each remaining solid in the list of solids
        solid = BooleanOperationsUtils.ExecuteBooleanOperation(solid, s, BooleanOperationsType.Union) # Merge each solid in sequence
    centroid = solid.ComputeCentroid() # Compute the centroid of the unioned solid
    centroids.append(centroid.ToPoint()) # Append the centroid to the list of centroids

OUT = centroids



I modified the script again to also show me the dynamo geometry of the elements; the mark-up of the screenshot belongs to a pipe that was originally split by a pipe accessory but it seems Revit is considering the geometry of the pipe is full and not split, because the right split of the pipe which has other Revit element ID is not inside of the assembly but it appears like if the geometry of it was part of the original pipe without accessories.

So if there is a one pipe modelled and it is split by a revit family of pipe accessory, revit tells me there are 2 pipe elements, but what I see is that one of them has geometry like the full pipe and the other part split has the geometry that you actually can see and measure which is correct, but the other side is not correct.

import clr
clr.AddReference('RevitAPI')
from Autodesk.Revit.DB import BooleanOperationsUtils, BooleanOperationsType, Options, Solid

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

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

doc = DocumentManager.Instance.CurrentDBDocument
assemblies = UnwrapElement(IN[0])
result = [] # Empty list to hold the combined solids and centroids

for assembly in assemblies: # For each assembly
    memberIds = assembly.GetMemberIds() # Get the member ids
    members = [doc.GetElement(i) for i in memberIds] # Get the members
    geo = [i.get_Geometry(Options()) for i in members] # Get the geometry
    solids = [i for geoset in geo for i in geoset if i.__class__ == Solid] # Filter out non-solids and return a flat list
    solid = solids.pop() # Get one solid from the list
    for s in solids: # For each remaining solid in the list of solids
        solid = BooleanOperationsUtils.ExecuteBooleanOperation(solid, s, BooleanOperationsType.Union) # Merge each solid in sequence
    centroid = solid.ComputeCentroid().ToPoint() # Compute the centroid of the unioned solid and convert to Dynamo point
    result.append((solid.ToProtoType(), centroid)) # Append the combined solid and centroid to the result list

OUT = result

Might be resolvable via the geometry options, or another bit. Hard to say without a model and I don’t have time to dig into it even if I did.

My recommendation is to focus on getting the geometry as you’d expect it to be returned first, instead of solving for all the things at once. You know how to get the size of an assembly, it’s now a matter of getting the right stuff into the assembly. Note that part of this may be due to an error in how the assembly was originally created, so that edge case may have to be handled independently via an error handling method of your choice.

I opted to ignore pipes and pipe insulations so result that I get with bounding boxes is acceptable, the pipe gives trouble with bounding boxes because if the original pipe is split in piece, one of the part always remembers the original length size even it is split in small piece. I took the first option script but ignoring elements of categories Pipes and Pipe Insulations.