Bounding Box from Assembly to Parts

Bounding Box from Assembly to Parts

valdas_kulikajevasYW7SV
Contributor Contributor
2,166 Views
12 Replies
Message 1 of 13

Bounding Box from Assembly to Parts

valdas_kulikajevasYW7SV
Contributor
Contributor

I am looking for a Illogic rule, or VBA code, that could be run from Assembly, that could write Minimum bounding box measurements into Custom properties of each files associated with it including current assembly.

Can anyone help me with this? (minimum bounding box is calculated by minimum space required to fit in stock, i.e. part rotated should be counted by minimal dimensions, not by X, Y, Z)

 

 

0 Likes
Accepted solutions (1)
2,167 Views
12 Replies
Replies (12)
Message 2 of 13

WCrihfield
Mentor
Mentor
Accepted solution

Hi @valdas_kulikajevasYW7SV.  I do not know what you want to call this custom iProperty, or how you want the information that will be set as its value to be formatted, but here is an example iLogic rule that you could try out.  It will recursively iterates though all levels of the components in the assembly, using a List to keep track of which referenced documents we have already processed, to avoid processing the same one multiple times.  It uses the new property ComponentOccurrence.OrientedMinimumCRangeBox which just became available in the 2024 version of Inventor, so if you are using an older version, let me know, and we can see about changing that part of the code.  If you want to change the name of the custom iProperty, or change how its value is formatted, that part is down in the lower portion of the 'ProcessComponent' Sub routine's code.  I can help you change it, if needed, just let me know how you need it changed.

Sub Main
	If ThisDoc.Document.DocumentType <> DocumentTypeEnum.kAssemblyDocumentObject Then Return
	Dim oADoc As AssemblyDocument = ThisDoc.Document
	Dim oADef As AssemblyComponentDefinition = oADoc.ComponentDefinition
	Dim oOccs As ComponentOccurrences = oADef.Occurrences
	oProcessedDocs = New List(Of String) 'initialize the list
	RecurseComponents(oOccs, AddressOf ProcessComponent)
	If oADoc.RequiresUpdate Then oADoc.Update2(True)
	'If oADoc.Dirty Then oADoc.Save2(True)
	MsgBox("This rule's work has finished.", vbInformation, "Job Is Done!")
End Sub

Dim oProcessedDocs As List(Of String)

Sub RecurseComponents(oComps As ComponentOccurrences, ComponentProcess As Action(Of ComponentOccurrence))
	If oComps Is Nothing OrElse oComps.Count = 0 Then Return
	For Each oComp As ComponentOccurrence In oComps
		ComponentProcess(oComp)
		If oComp.Suppressed = False AndAlso _
			oComp.DefinitionDocumentType = DocumentTypeEnum.kAssemblyDocumentObject Then
			RecurseComponents(oComp.Definition.Occurrences, ComponentProcess)
		End If
	Next
End Sub

Sub ProcessComponent(oComp As ComponentOccurrence)
	If oComp Is Nothing OrElse oComp.Suppressed Then Return
	If TypeOf oComp.Definition Is VirtualComponentDefinition Then Return
	If TypeOf oComp.Definition Is WeldsComponentDefinition Then Return
	Dim oCompDoc As Inventor.Document = oComp.Definition.Document
	If oCompDoc.IsModifiable = False Then Return 'can not write to it, so skip it
	'avoid processing the same referenced document more than once by using the List to keep track
	If oProcessedDocs.Contains(oCompDoc.FullDocumentName) Then
		Return 'exits this Sub routine, and goes to next component in loop
	Else
		oProcessedDocs.Add(oCompDoc.FullDocumentName)
	End If
	Dim UOM As Inventor.UnitsOfMeasure = oCompDoc.UnitsOfMeasure
	Dim oBox As OrientedBox = oComp.OrientedMinimumRangeBox
	Dim oSizes As New List(Of Double)
	Dim dL1 As Double = oBox.DirectionOne.Length
	oSizes.Add(oBox.DirectionOne.Length)
	oSizes.Add(oBox.DirectionTwo.Length)
	oSizes.Add(oBox.DirectionThree.Length)
	For i As Integer = 0 To 2
		oSizes.Item(i) = UOM.ConvertUnits(oSizes.Item(i), UnitsTypeEnum.kDatabaseLengthUnits, UOM.LengthUnits)
	Next
	oSizes.Sort
	Dim oCProps As Inventor.PropertySet = oCompDoc.PropertySets.Item(4) 'the Custom set
	Dim oCProp As Inventor.Property = Nothing
	Dim sCPropName As String = "Component Size"
	Dim sCPropValue As String = oSizes.Item(0).ToString & " x " & oSizes.Item(1).ToString & " x " & oSizes.Item(2).ToString
	Try
		oCProp = oCProps.Item(sCPropName)
	Catch
		oCProp = oCProps.Add(sCPropValue, sCPropName)
	End Try
	If oCProp IsNot Nothing AndAlso oCProp.Value <> sCPropValue Then
		Try : oCProp.Value = sCPropValue : Catch : End Try
	End If
End Sub

If this solved your problem, or answered your question, please click ACCEPT SOLUTION .
Or, if this helped you, please click (LIKE or KUDOS) 👍.

 

Wesley Crihfield

EESignature

(Not an Autodesk Employee)

Message 3 of 13

valdas_kulikajevasYW7SV
Contributor
Contributor

Hello, @WCrihfield , thank you for your reply.

I have tested the code, and it works pretty well!

Is it possible to round up the numbers to 1mm? or 0.1 mm?

valdas_kulikajevasYW7SV_0-1704719361342.png

 

 

 

0 Likes
Message 4 of 13

WCrihfield
Mentor
Mentor

Hi @valdas_kulikajevasYW7SV.  Sure.  I usually include something like that, but did not know what your preference was, or what units you may be using.  Find the 'For...Next' loop in the code, which contains the following line:

oSizes.Item(i) = UOM.ConvertUnits(oSizes.Item(i), UnitsTypeEnum.kDatabaseLengthUnits, UOM.LengthUnits)

...then insert this line of code right under that line of code, but still within that loop (before the 'Next' keyword).

oSizes.Item(i) = Math.Ceiling(oSizes.Item(i) / 0.1) * 0.1

That will round the value up to the next increment of .1, by dividing the value by that increment amount, then rounding that result up to the next whole number, then multiplying that result by the increment amount again.  I am also assuming that your document units are millimeters, because the 'database' units for distance in Inventor are centimeters, so most distances you get from Inventor objects by code will be in centimeters, instead of document units (if they are different).  Also most raw numerical values you put into a code window, that are supposed to represent a distance, will be automatically understood as being a value in centimeters.  Just something to keep in mind.  When simply converting from centimeters to millimeters, some simple math can be used, instead of a units conversion Function, but some folks deal with many different types of units, in which case the simple math would not always work.

 

Also, if there are things like WorkPoints, WorkAxis, WorkPlanes turned on within your model files, or within the assembly, for the component origin work features, that might effect the accuracy of these 'bounding box' measurement type codes.  So, you may need to turn all of that type of stuff off before taking these measurements, to get more accurate results.  I do not know if using the ComponentOccurrence.OrientedMinimumRangeBox property would do anything to avoid those types of things, because there is very little documentation being shown on its online help web page.

Wesley Crihfield

EESignature

(Not an Autodesk Employee)

0 Likes
Message 5 of 13

valdas_kulikajevasYW7SV
Contributor
Contributor

Thank you for reply, @WCrihfield 

I have added those code lines and noticed that dimensions are sometimes 0.1 mm bigger:

valdas_kulikajevasYW7SV_0-1704780674420.png

 

Probably as you mentioned, could be because inventor runs in centimeter?

 

oSizes.Item(i) = Math.Ceiling(oSizes.Item(i) / 1) *1

 

I changed this line, to show in mm.

then it makes a bigger error:

valdas_kulikajevasYW7SV_1-1704780993291.png

Yeah I am using Inventor 2024 and it is setup in mm.

I wonder, because before roundup it show quite exact dimensions:

valdas_kulikajevasYW7SV_2-1704781076959.png

Maybe the round up option can be done after the dimensions are put into string?

Although it could complicate the code quite alot?

 

0 Likes
Message 6 of 13

WCrihfield
Mentor
Mentor

Hi @valdas_kulikajevasYW7SV.  There are several aspects to the way that math is functioning.  For one thing, the Double data type goes all the way out to 15 decimal places, I believe.  This can make it difficult to test if one Double type value is equal to another Double type value, when one or both may be the result of a measurement or math, because one could be 15.0000000000001, which would make it not equal to 15.0000000000000, and therefore, the first value may get rounded up to the next increment, while the second value may not be.  What could be done, is to round of the initial measured value to a specific number of decimal places first, then round that value up to the nearest increment of 0.1 afterwards, in an attempt to eliminate a minutely off value.  Something like the following:

oSizes.Item(i) = Ceil(Round(oSizes.Item(i), 3) / 0.1) * 0.1

But if you just round off the initial value to 1 decimal place, without using the 'round up to increment' process, you may end up with something like an initial value of 20.444 that will get rounded down to 20.4 instead of getting rounded up to 20.5.  If rounding a value like that down to 20.4 is OK, then we could change that line of code to:

 

oSizes.Item(i) = Round(oSizes.Item(i), 1, MidpointRounding.AwayFromZero)

 

...where the 1, indicates the number of decimal places of precision, and the last input tells it to round a midpoint value (like 5.45) up to the next value (like 5.5), instead of to nearest even number (like 5.4).

https://learn.microsoft.com/en-us/dotnet/api/system.math.round?view=net-8.0#system-math-round(system... 

 

Wesley Crihfield

EESignature

(Not an Autodesk Employee)

Message 7 of 13

valdas_kulikajevasYW7SV
Contributor
Contributor

Thank You, @WCrihfield  very much!

I ended up using:

 

oSizes.Item(i) = Ceil(Round(oSizes.Item(i), 3) / 0.1) * 0.1 'great, rounds up, to 0.1

Since it's a fraction of a mm, and sometimes i have sheets that are 2.5, or 1.5 mm.

Although with flat pattern (sheet bended parts) it does not work this way. But that's a topic for later maybe :).

Really big help. I wish Inventor could have this implemented in their system already (Like Bounding Box in Solidworks are done from weldment menu)

0 Likes
Message 8 of 13

Jeroen_van_belleghem
Explorer
Explorer

Hi @WCrihfield 

 

I am running Inventor 2025 and find following error.

 

Can you help pls?

 

0 Likes
Message 9 of 13

WCrihfield
Mentor
Mentor

Hi @Jeroen_van_belleghem.  Looking at those two error reports, it looks like the error is happening at Line 39, where it is using the ComponentOccurrence.OrientedMinimumRangeBox property to get its OrientedBox.  But there is no further helpful information about why it threw an error at that point in the process.  We have already filtered out suppressed components, and virtual components, which would not have any physical size, so I am not sure what could cause a problem at that point.  Are there any components within the entire structure (all levels) of the assembly that are not resolved (files they reference can not be found)?  Is there a component that represents a part document, where the only geometry within that part is being derived into that part from some other model document, but maybe the link to that other model document has something wrong with it, resulting in no physical geometry within the component in your assembly?  Or maybe you have a component in your assembly that represents a part document that simply does not have any solid bodies in it on purpose, I can not be sure.  Just trying to think of anything odd that may be present in your assembly that might possibly cause an issue at that point.

 

I would recommend that you put some form of feedback into your code, that way you will know specifically which component this issue is being encountered with, which will help you pinpoint the problematic one and check things out.  Since an error is being thrown by simply accessing that property of one (or more) of your components, you can enclose a portion of that line of code within a Try...Catch...End Try statement, on the 'Try' side, then put a message on the 'Catch' side which includes the name of that component, and what was trying to be done on the 'Try' side of it.

Wesley Crihfield

EESignature

(Not an Autodesk Employee)

0 Likes
Message 10 of 13

Jeroen_van_belleghem
Explorer
Explorer

Hi @WCrihfield,

 

I had a reference part, where i've set the bom structure to reference.  If i change it to Default the rule works fine.

0 Likes
Message 11 of 13

WCrihfield
Mentor
Mentor

Hi @Jeroen_van_belleghem.  I'm glad to hear that you seem to have figured it out.  I had not considered that possibility.  If you need that part to remain as reference, and need the code to work anyways, then we may be able to work around that issue.  Since that status seems to cause a problem in this process, there is a way to filter components like that out, if needed.  BOMStructure status can be applied to individual assembly component occurrences, within the context of the assembly only, or it can be applied directly to the model document itself (more specifically to its 'definition').  So, the following block of code can be put into the 'ProcessComponent' Sub routine, below where it filters out Definition types.  Its first 2 lines check the assembly component occurrence BOMStructure status for 'reference' or 'phantom', then the next two lines check that those statuses of the ComponentDefinition that they reference.  If any of those first 4 lines evaluate to True, then that component will skip being processed, due to the 'Return' statement.  I am using 'OrElse', instead of 'Or' so that if an earlier expression is True, it will stop there, instead of continuing to check all 4 expressions, for performance purposes.

 

If oComp.BOMStructure = BOMStructureEnum.kReferenceBOMStructure OrElse
	oComp.BOMStructure = BOMStructureEnum.kPhantomBOMStructure OrElse
	oComp.Definition.BOMStructure = BOMStructureEnum.kReferenceBOMStructure OrElse
	oComp.Definition.BOMStructure = BOMStructureEnum.kPhantomBOMStructure Then
	Return
End If

 

Almost forgot to mention that BOMStructure status can be applied to an entire BOMRow also.

BOMRow.BOMStructure 

Wesley Crihfield

EESignature

(Not an Autodesk Employee)

0 Likes
Message 12 of 13

mathew_kenney
Explorer
Explorer

Hi @WCrihfield 

How would I go about separating the string for the "component size" to break it up into Length, width and thickness as separate custom properties?

 

 

0 Likes
Message 13 of 13

WCrihfield
Mentor
Mentor

Hi @mathew_kenney.  I copied my code from earlier in this conversation, applied a couple modifications to it (BOMStructure filtering & rounding values to 3 decimal places), then modified the last portion of the code, where it is writing the data to custom iProperties.  It now tries to create/update 3 different custom iProperties named "Thickness", "Width", & "Length", with Thickness being the smallest value, and Length being the largest value.  See attached text file.

Wesley Crihfield

EESignature

(Not an Autodesk Employee)