How To Visualize a BoundingBox with Revit API?
If you start using BoundingBox, and something doesn't add up, then it's a good point to visualize your bounding box to better understand the issue. If you use Dynamo then you can simply get a preview in the Dynamo Viewer.
However, if you use pyRevit, then it gets a bit tricky. However, there is a way out by converting bounding box into a solid geometry. And for that we need to use DirectShape class from Revit API, so we can create this solid in the project.
To do that we need to do the following steps:
Get BoundingBox
Create Base Outline
Create solid with CreateExtrusionGeometry
Create DirectShape from the solid
Let's look how to make it happen
Get BoundingBox
For this example, I will just get my current selection from Revit's UI. But please adjust it to your own needs.
Here is how to get selected elements and retrieve their BoundingBox.
#⬇️ IMPORTS
from Autodesk.Revit.DB import *
#Import .NET List
import clr
clr.AddReference('System')
from System.Collections.Generic import List
#📦 VARIABLES
uidoc = __revit__.ActiveUIDocument
doc = __revit__.ActiveUIDocument.Document
# Get Selected Elements
selected_elems = [doc.GetElement(elId) for elId in uidoc.Selection.GetElementIds()]
# Get BoundingBoxes
for elem in selected_elems:
bbox = elem.get_BoundingBox(None)
Create Solid from BoundingBox
Now we need to convert BoundingBox to a Solid object, so we can construct a DirectShape .
Since BoundingBoxes are simple boxes, we can use CreateExtrusionGeometry method to create it. We just need to create an outline by using its Min and Max points.
Here is function that can do that for you:
def solidBoundingBox(elem):
bbox = elem.get_BoundingBox(None)
pt0 = XYZ(bbox.Min.X, bbox.Min.Y, bbox.Min.Z)
pt1 = XYZ(bbox.Max.X, bbox.Min.Y, bbox.Min.Z)
pt2 = XYZ(bbox.Max.X, bbox.Max.Y, bbox.Min.Z)
pt3 = XYZ(bbox.Min.X, bbox.Max.Y, bbox.Min.Z)
edge0 = Line.CreateBound(pt0, pt1)
edge1 = Line.CreateBound(pt1, pt2)
edge2 = Line.CreateBound(pt2, pt3)
edge3 = Line.CreateBound(pt3, pt0)
edges = [edge0, edge1, edge2, edge3]
baseLoop = CurveLoop.Create(edges)
loopList = [baseLoop]
height = bbox.Max.Z - bbox.Min.Z
preTransformBox = GeometryCreationUtilities.CreateExtrusionGeometry(loopList, XYZ.BasisZ, height)
transformBox = SolidUtils.CreateTransformed(preTransformBox, bbox.Transform)
return transformBox
Create Direct Shape
Now, once you have your Solid geometry it's very easy to create a direct shape.
Here is the code snippet:
t = Transaction(doc, 'Create DirectShape from BoundingBox')
t.Start()
for el in selection:
solid = solidBoundingBox(el)
ds = DirectShape.CreateElement(doc, ElementId(BuiltInCategory.OST_GenericModel))
ds.SetShape([solid])
t.Commit()
Final Snippet
Here is the whole code put together so there are no misunderstandings. You can even use Revit Python Shell to test it.
from Autodesk.Revit.DB import *
import clr
clr.AddReference('System')
from System.Collections.Generic import List
uidoc = __revit__.ActiveUIDocument
doc = __revit__.ActiveUIDocument.Document
selected_elems = [doc.GetElement(elId) for elId in uidoc.Selection.GetElementIds()]
t = Transaction(doc, 'Create DirectShape from BoundingBox')
t.Start()
def solidBoundingBox(elem):
bbox = elem.get_BoundingBox(None)
pt0 = XYZ(bbox.Min.X, bbox.Min.Y, bbox.Min.Z)
pt1 = XYZ(bbox.Max.X, bbox.Min.Y, bbox.Min.Z)
pt2 = XYZ(bbox.Max.X, bbox.Max.Y, bbox.Min.Z)
pt3 = XYZ(bbox.Min.X, bbox.Max.Y, bbox.Min.Z)
edge0 = Line.CreateBound(pt0, pt1)
edge1 = Line.CreateBound(pt1, pt2)
edge2 = Line.CreateBound(pt2, pt3)
edge3 = Line.CreateBound(pt3, pt0)
edges = [edge0, edge1, edge2, edge3]
baseLoop = CurveLoop.Create(edges)
loopList = [baseLoop]
height = bbox.Max.Z - bbox.Min.Z
preTransformBox = GeometryCreationUtilities.CreateExtrusionGeometry(loopList, XYZ.BasisZ, height)
transformBox = SolidUtils.CreateTransformed(preTransformBox, bbox.Transform)
return transformBox
for el in selection:
solid = solidBoundingBox(el)
ds = DirectShape.CreateElement(doc, ElementId(BuiltInCategory.OST_GenericModel))
ds.SetShape([solid])
t.Commit()