The question of getting the size of a part frequently comes up and I wanted to spend some time discussing the existing functionality and other options. The discussion here applies to both Fusion 360 and Inventor (and probably most other CAD systems).

**What is a Bounding Box?**

The easiest way to get a size of a part is to get the bounding box (also called the range box) of the object. Let’s look at what a bounding box is by looking at some simple 2D examples first. A 2D bounding box is a rectangle that encompasses the object. Below is an example of a part (the shaded area) and it’s bounding rectangle (dashed lines). If we measured the size of this box I think we would all agree that it looks like an accurate measure of the overall size of the part.

A typical bounding box is defined using just two points; the minimum and maximum points. The picture below shows the two 2D points used to define the bounding box. A limitation with defining a bounding box in this way is that the rectangle is oriented such that it’s edges are always parallel to the x and y model axes.

Below is the same part that has been rotated and its bounding box is displayed. In this case the size of the bounding box probably isn’t what you wanted and in most cases is not particularly useful.

What you probably really wanted was this bounding box but that box can’t be defined by a simple two points and needs additional information to define the orientation.

Bounding boxes aren’t something specific to the Inventor and Fusion 360 API’s but are a basic concept in computer graphics. The usual intent of a bounding box is not to provide a tight fitting, orientated box around a part but instead to provide a very fast box that fits around a certain piece of geometry. The only thing guaranteed is that the object is completely contained within the box and there is no guarantee about how tight the box fits around the object. In many cases, like in the first example, the size of the range box is the same as the physical size of the part but there are cases when this is not the case. Below, on the left, is an example from Inventor where the bounding box is quite a bit larger than the visible part. At first glance this would seem to be a bug in the calculation but the bounding box is including the control polygon of the spline surface, as shown on the right. So it may not be what you want but it is arguably correct and is the simplest for Inventor to calculate.

Bounding boxes are intended to be used in more complex operations where you need to first determine if a particular object should be considered in a calculation. To determine if an object should be included you can often use it’s bounding box to see if it’s within the area to be calculated. This is a very simple and fast calculation that can be performed to determine if the object can be eliminated from the more complicated and costly computations. Operations with bounding boxes like this are also very simple. For example you can combine bounding boxes to create a new box that contains the originals.

The Inventor API has the Box and Box2d objects that are used to pass back the bounding box information and these objects also provide properties and methods to let you work with the box information. The Fusion 360 API has the BoundingBox3D and BoundingBox2D objects that provide the equivalent functionality. The most important feature of these objects is that they return the coordinates of the min and max points.

**Getting Accurate Bounding Boxes**

As discussed above, the bounding box returned by the Inventor RangeBox property and returned by the Fusion360 boundingBox property may not be what you need. Unfortunately, a bounding box that is always tight fitting to the visible graphics is not currently provided by either Inventor or Fusion 360. However, it is possible to calculate a very close approximation on your own using other API functionality. What I’m going to show you here will create a tight range box but it will still be oriented so it’s parallel to the world XYZ planes. The ability to automatically calculate a bounding box that is oriented to get the tightest fitting box possible is a very difficult problem that I haven’t seen a solution to. It’s something you could probably write a PhD paper on. The easiest approach to the orientation problem is to ask the user for help by lettin them define the coordinate system the bounding box should be calculated in, essentially defining the directions for the length, width and height. That’s possible but a little more than I wanted to go into in this post so I’ll limit this discussion to calculating a tight fitting bounding box that’s oriented parallel to the world XYZ planes.

To do this you can use a triangular mesh representation of the model and calculate your own bounding box by including all of the vertices of the mesh. The result will be as accurate as the mesh. In both Inventor and Fusion 360 you can calculate a mesh representation to any tolerance you want or you can get the existing mesh that Inventor or Fusion 360 is using for the display of the model. The actual model is made up of accurate smooth surfaces, but a mesh representation is created and used internally to display the model. Using the existing mesh is faster that calculating a new one but if accuracy is critical you might want to calculate a new mesh. The shape of the model will also affect the accuracy. A model made up entirely of planes will result in an exact mesh representation regardless of the tolerance of the mesh because the triangles exactly represent those faces. If a model has any curved surfaces, even as simple as a cylinder, then the mesh is an approximation. I’ve tried to illustrate this in the picture below. On the left are the original models where one model is made entirely of planes and the other has planes, cylinders, and a sphere. On the right is the triangular mesh representations of the two parts. The first model is an exact representation because the shape can be exactly represented by the triangles. However, the second model has curved surfaces and has to be approximated by the triangles. The accuracy of the bounding box you build will depend on their being a triangle vertex at the minimum and maximum X, Y, and Z sizes of the model. The more triangles, the more likely you’ll have vertices at those locations but it also means more processing for Inventor or Fusion to calculate the mesh and more processing for you to analyze the mesh to build the range box.

I’ve used the code similar to that below in a few programs I’ve posted previously. The calculateTightBoundingBox function takes in a body and optional tolerance and returns the tight fitting bounding box. If no tolerance is provided, the existing display mesh is used. There can be more than one display mesh because Inventor and Fusion will generate different meshes depending on how close you zoom into the model so the display always appears smooth. When using the display mesh, this function will use the highest quality display mesh that exists. If a tolerance is provided, then a new mesh is calculated using that tolerance. There is a test function for each that is used to test the calculateTightBoundingBox function. Samples below are provided in Python for Fusion 360 and VBA and Visual Basic for Inventor. Below is the result on the previous model where the bounding box returned by Inventor was much larger.

**Fusion 360 Python**

# Function to test the calculateTightBoundingBox function.

def run(context):

ui = None

try:

app = adsk.core.Application.get()

ui = app.userInterface

des = adsk.fusion.Design.cast(app.activeProduct)

bodySelect = ui.selectEntity('Select the body.', 'Bodies')

body = adsk.fusion.BRepBody.cast(bodySelect.entity)

# Call the function to get the tight bounding box.

bndBox= calculateTightBoundingBox(body)

# Draw the bounding box using a sketch.

sk = des.rootComponent.sketches.add(des.rootComponent.xYConstructionPlane)

lines = sk.sketchCurves.sketchLines

minXYZ = bndBox.minPoint

minXYmaxZ = adsk.core.Point3D.create(bndBox.minPoint.x, bndBox.minPoint.y, bndBox.maxPoint.z)

minXmaxYZ = adsk.core.Point3D.create(bndBox.minPoint.x, bndBox.maxPoint.y, bndBox.maxPoint.z)

minXZmaxY = adsk.core.Point3D.create(bndBox.minPoint.x, bndBox.maxPoint.y, bndBox.minPoint.z)

maxXYZ = bndBox.maxPoint

maxXYminZ = adsk.core.Point3D.create(bndBox.maxPoint.x, bndBox.maxPoint.y, bndBox.minPoint.z)

maxXZminY = adsk.core.Point3D.create(bndBox.maxPoint.x, bndBox.minPoint.y, bndBox.maxPoint.z)

maxXminYZ = adsk.core.Point3D.create(bndBox.maxPoint.x, bndBox.minPoint.y, bndBox.minPoint.z)

lines.addByTwoPoints(minXYZ, minXYmaxZ)

lines.addByTwoPoints(minXYZ, minXZmaxY)

lines.addByTwoPoints(minXZmaxY, minXmaxYZ)

lines.addByTwoPoints(minXYmaxZ, minXmaxYZ)

lines.addByTwoPoints(maxXYZ, maxXYminZ)

lines.addByTwoPoints(maxXYZ, maxXZminY)

lines.addByTwoPoints(maxXYminZ, maxXminYZ)

lines.addByTwoPoints(maxXZminY, maxXminYZ)

lines.addByTwoPoints(minXYZ, maxXminYZ)

lines.addByTwoPoints(minXYmaxZ, maxXZminY)

lines.addByTwoPoints(minXmaxYZ, maxXYZ)

lines.addByTwoPoints(minXZmaxY, maxXYminZ)

except:

if ui:

ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))

# Calculates a tight bounding box around the input body. An optional

# tolerance argument is available. This specificies the tolerance in

# centimeters. If not provided the best existing display mesh is used.

def calculateTightBoundingBox(body, tolerance = 0):

try:

# If the tolerance is zero, use the best display mesh available.

if tolerance <= 0:

# Get the best display mesh available.

triMesh = body.meshManager.displayMeshes.bestMesh

else:

# Calculate a new mesh based on the input tolerance.

meshMgr = adsk.fusion.MeshManager.cast(body.meshManager)

meshCalc = meshMgr.createMeshCalculator()

meshCalc.surfaceTolerance = tolerance

triMesh = meshCalc.calculate()

# Calculate the range of the mesh.

smallPnt = adsk.core.Point3D.cast(triMesh.nodeCoordinates[0])

largePnt = adsk.core.Point3D.cast(triMesh.nodeCoordinates[0])

vertex = adsk.core.Point3D.cast(None)

for vertex in triMesh.nodeCoordinates:

if vertex.x < smallPnt.x:

smallPnt.x = vertex.x

if vertex.y < smallPnt.y:

smallPnt.y = vertex.y

if vertex.z < smallPnt.z:

smallPnt.z = vertex.z

if vertex.x > largePnt.x:

largePnt.x = vertex.x

if vertex.y > largePnt.y:

largePnt.y = vertex.y

if vertex.z > largePnt.z:

largePnt.z = vertex.z

# Create and return a BoundingBox3D as the result.

return(adsk.core.BoundingBox3D.create(smallPnt, largePnt))

except:

# An error occurred so return None.

return(None)

**Inventor VBA**

Public Sub TestTightBoundingBox()

' Have a body selected.

Dim body As SurfaceBody

Set body = ThisApplication.CommandManager.Pick(kPartBodyFilter, "Select the body.")

' Call the function to get the tight bounding box.

Dim bndBox As Box

Set bndBox = calculateTightBoundingBox(body)

' Draw the bounding box using a 3D sketch.

Dim partDoc As PartDocument

Set partDoc = ThisApplication.ActiveDocument

Dim sk As Sketch3D

Set sk = partDoc.ComponentDefinition.Sketches3D.Add()

Dim lines As SketchLines3D

Set lines = sk.SketchLines3D

Dim tg As TransientGeometry

Set tg = ThisApplication.TransientGeometry

Dim minXYZ As Point

Dim minXYmaxZ As Point

Dim minXmaxYZ As Point

Dim minXZmaxY As Point

Set minXYZ = bndBox.MinPoint

Set minXYmaxZ = tg.CreatePoint(bndBox.MinPoint.x, bndBox.MinPoint.y, bndBox.MaxPoint.Z)

Set minXmaxYZ = tg.CreatePoint(bndBox.MinPoint.x, bndBox.MaxPoint.y, bndBox.MaxPoint.Z)

Set minXZmaxY = tg.CreatePoint(bndBox.MinPoint.x, bndBox.MaxPoint.y, bndBox.MinPoint.Z)

Dim maxXYZ As Point

Dim maxXYminZ As Point

Dim maxXZminY As Point

Dim maxXminYZ As Point

Set maxXYZ = bndBox.MaxPoint

Set maxXYminZ = tg.CreatePoint(bndBox.MaxPoint.x, bndBox.MaxPoint.y, bndBox.MinPoint.Z)

Set maxXZminY = tg.CreatePoint(bndBox.MaxPoint.x, bndBox.MinPoint.y, bndBox.MaxPoint.Z)

Set maxXminYZ = tg.CreatePoint(bndBox.MaxPoint.x, bndBox.MinPoint.y, bndBox.MinPoint.Z)

Call lines.AddByTwoPoints(minXYZ, minXYmaxZ)

Call lines.AddByTwoPoints(minXYZ, minXZmaxY)

Call lines.AddByTwoPoints(minXZmaxY, minXmaxYZ)

Call lines.AddByTwoPoints(minXYmaxZ, minXmaxYZ)

Call lines.AddByTwoPoints(maxXYZ, maxXYminZ)

Call lines.AddByTwoPoints(maxXYZ, maxXZminY)

Call lines.AddByTwoPoints(maxXYminZ, maxXminYZ)

Call lines.AddByTwoPoints(maxXZminY, maxXminYZ)

Call lines.AddByTwoPoints(minXYZ, maxXminYZ)

Call lines.AddByTwoPoints(minXYmaxZ, maxXZminY)

Call lines.AddByTwoPoints(minXmaxYZ, maxXYZ)

Call lines.AddByTwoPoints(minXZmaxY, maxXYminZ)

End Sub

' Calculates a tight bounding box around the input body. An optional

' tolerance argument is available. This specificies the tolerance in

' centimeters. If not provided the best existing display mesh is used.

Public Function calculateTightBoundingBox(body As SurfaceBody, Optional Tolerance As Double = 0) As Box

On Error GoTo ErrorFound

Dim vertCount As Long

Dim facetCount As Long

Dim vertCoords() As Double

Dim normVectors() As Double

Dim vertInds() As Long

' If the tolerance is zero, use the best display mesh available.

If Tolerance <= 0 Then

' Get the best display mesh available.

Dim tolCount As Long

Dim tols() As Double

Call body.GetExistingFacetTolerances(tolCount, tols)

Dim i As Integer

Dim bestTol As Double

bestTol = tols(0)

For i = 1 To tolCount - 1

If tols(i) < bestTol Then

bestTol = tols(i)

End If

Next

Call body.GetExistingFacets(bestTol, vertCount, facetCount, vertCoords, normVectors, vertInds)

Else

' Calculate a new mesh based on the input tolerance.

Call body.CalculateFacets(Tolerance, vertCount, facetCount, vertCoords, normVectors, vertInds)

End If

Dim tg As TransientGeometry

Set tg = ThisApplication.TransientGeometry

' Calculate the range of the mesh.

Dim smallPnt As Point

Dim largePnt As Point

Set smallPnt = tg.CreatePoint(vertCoords(0), vertCoords(1), vertCoords(2))

Set largePnt = tg.CreatePoint(vertCoords(0), vertCoords(1), vertCoords(2))

For i = 1 To vertCount - 1

Dim vertX As Double

Dim vertY As Double

Dim vertZ As Double

vertX = vertCoords(i * 3)

vertY = vertCoords(i * 3 + 1)

vertZ = vertCoords(i * 3 + 2)

If vertX < smallPnt.x Then

smallPnt.x = vertX

End If

If vertY < smallPnt.y Then

smallPnt.y = vertY

End If

If vertZ < smallPnt.Z Then

smallPnt.Z = vertZ

End If

If vertX > largePnt.x Then

largePnt.x = vertX

End If

If vertY > largePnt.y Then

largePnt.y = vertY

End If

If vertZ > largePnt.Z Then

largePnt.Z = vertZ

End If

Next

' Create and return a Box as the result.

Set calculateTightBoundingBox = tg.CreateBox()

calculateTightBoundingBox.MinPoint = smallPnt

calculateTightBoundingBox.MaxPoint = largePnt

Exit Function

ErrorFound:

Set calculateTightBoundingBox = Nothing

Exit Function

End Function

**Inventor Visual Basic (iLogic)**

Public Sub TestTightBoundingBox()
Dim invApp As Inventor.Application = GetObject(, "Inventor.Application")
' Have a body selected.
Dim body As SurfaceBody
body = invApp.CommandManager.Pick(SelectionFilterEnum.kPartBodyFilter, "Select the body.")
' Call the function to get the tight bounding box.

Dim bndBox As Box = calculateTightBoundingBox(body)

' Draw the bounding box using a 3D sketch.

Dim partDoc As PartDocument = invApp.ActiveDocument

Dim sk As Sketch3D = partDoc.ComponentDefinition.Sketches3D.Add()

Dim lines As SketchLines3D = sk.SketchLines3D

Dim tg As TransientGeometry = invApp.TransientGeometry

Dim minXYZ As Point = bndBox.MinPoint

Dim minXYmaxZ As Point = tg.CreatePoint(bndBox.MinPoint.X, bndBox.MinPoint.Y, bndBox.MaxPoint.Z)

Dim minXmaxYZ As Point = tg.CreatePoint(bndBox.MinPoint.X, bndBox.MaxPoint.Y, bndBox.MaxPoint.Z)

Dim minXZmaxY As Point = tg.CreatePoint(bndBox.MinPoint.X, bndBox.MaxPoint.Y, bndBox.MinPoint.Z)

Dim maxXYZ As Point = bndBox.MaxPoint

Dim maxXYminZ As Point = tg.CreatePoint(bndBox.MaxPoint.X, bndBox.MaxPoint.Y, bndBox.MinPoint.Z)

Dim maxXZminY As Point = tg.CreatePoint(bndBox.MaxPoint.X, bndBox.MinPoint.Y, bndBox.MaxPoint.Z)

Dim maxXminYZ As Point = tg.CreatePoint(bndBox.MaxPoint.X, bndBox.MinPoint.Y, bndBox.MinPoint.Z)

lines.AddByTwoPoints(minXYZ, minXYmaxZ)

lines.AddByTwoPoints(minXYZ, minXZmaxY)

lines.AddByTwoPoints(minXZmaxY, minXmaxYZ)

lines.AddByTwoPoints(minXYmaxZ, minXmaxYZ)

lines.AddByTwoPoints(maxXYZ, maxXYminZ)

lines.AddByTwoPoints(maxXYZ, maxXZminY)

lines.AddByTwoPoints(maxXYminZ, maxXminYZ)

lines.AddByTwoPoints(maxXZminY, maxXminYZ)

lines.AddByTwoPoints(minXYZ, maxXminYZ)

lines.AddByTwoPoints(minXYmaxZ, maxXZminY)

lines.AddByTwoPoints(minXmaxYZ, maxXYZ)

lines.AddByTwoPoints(minXZmaxY, maxXYminZ)

End Sub

' Calculates a tight bounding box around the input body. An optional

' tolerance argument is available. This specificies the tolerance in

' centimeters. If not provided the best existing display mesh is used.

Public Function calculateTightBoundingBox(body As SurfaceBody, Optional Tolerance As Double = 0) As Box

Try

Dim vertCount As Integer

Dim facetCount As Integer

Dim vertCoords() As Double = {}

Dim normVectors() As Double = {}

Dim vertInds() As Integer = {}

' If the tolerance is zero, use the best display mesh available.

If Tolerance <= 0 Then

' Get the best display mesh available.

Dim tolCount As Long

Dim tols() As Double = {}

Call body.GetExistingFacetTolerances(tolCount, tols)

Dim bestTol As Double

bestTol = tols(0)

For i As Integer = 1 To tolCount - 1

If tols(i) < bestTol Then

bestTol = tols(i)

End If

Next

body.GetExistingFacets(bestTol, vertCount, facetCount, vertCoords, normVectors, vertInds)

Else

' Calculate a new mesh based on the input tolerance.

body.CalculateFacets(Tolerance, vertCount, facetCount, vertCoords, normVectors, vertInds)

End If

Dim tg As TransientGeometry = body.Application.TransientGeometry

' Calculate the range of the mesh.

Dim smallPnt As Point = tg.CreatePoint(vertCoords(0), vertCoords(1), vertCoords(2))

Dim largePnt As Point = tg.CreatePoint(vertCoords(0), vertCoords(1), vertCoords(2))

For i As Integer = 1 To vertCount - 1

Dim vertX As Double = vertCoords(i * 3)

Dim vertY As Double = vertCoords(i * 3 + 1)

Dim vertZ As Double = vertCoords(i * 3 + 2)

If vertX < smallPnt.X Then

smallPnt.X = vertX

End If

If vertY < smallPnt.Y Then

smallPnt.Y = vertY

End If

If vertZ < smallPnt.Z Then

smallPnt.Z = vertZ

End If

If vertX > largePnt.X Then

largePnt.X = vertX

End If

If vertY > largePnt.Y Then

largePnt.Y = vertY

End If

If vertZ > largePnt.Z Then

largePnt.Z = vertZ

End If

Next

' Create and return a Box as the result.

Dim newBox As Box = tg.CreateBox()

newBox.MinPoint = smallPnt

newBox.MaxPoint = largePnt

Return newBox

Catch ex As Exception

Return Nothing

End Try

End Function

-Brian