Getting accurate RangeBox XYZ values

NachoShaw
Advisor Advisor
12,046 Views
55 Replies
Message 1 of 56

Getting accurate RangeBox XYZ values

NachoShaw
Advisor
Advisor

Hey

 

I'm using the RangeBox method to return the XYZ values of some parts. My problem with this is that if the part was angled, I do not get the correct XYZ but instead, I get XYZ of the angled part as if it was flat. Hard to explain but let's say for example the part was 10" x 10" x 1". that's the RB set of values but if the same part was angled at 45 degrees, I then get something like 10" x 10" x 5"...

 

is there a method of routine available that would allow me to obtain the true XYX even if the part wasnt laid flat or angled?

 

 

thanks

 

Nacho

Nacho
Automation & Design Engineer

Inventor automation Programmer (C#, VB.Net / iLogic)
Furniture, Sheet Metal, Structural, Metal fab, Tradeshow, Fabrication, CNC

EESignature


Did you find this post helpful? Feel free to Like this post.
Did your question get successfully answered? Then click on the ACCEPT SOLUTION button.


0 Likes
Accepted solutions (3)
12,047 Views
55 Replies
Replies (55)
Message 21 of 56

dba78
Advocate
Advocate

Since SheetMetalComponentDefinition derives from PartComponentDefinition, I wonder you can't apply it to Sheetmetal parts.... Actually I use it...

Can you explain your issue?

0 Likes
Message 22 of 56

NachoShaw
Advisor
Advisor

Hi Daniel

 

Thanks for the reply albeit, the post is 2 yrs old.. Since this post, Inventor has provided a method of getting a rotated size.

 

Thanks

Nacho
Automation & Design Engineer

Inventor automation Programmer (C#, VB.Net / iLogic)
Furniture, Sheet Metal, Structural, Metal fab, Tradeshow, Fabrication, CNC

EESignature


Did you find this post helpful? Feel free to Like this post.
Did your question get successfully answered? Then click on the ACCEPT SOLUTION button.


0 Likes
Message 23 of 56

dba78
Advocate
Advocate

Hi, the thread is old indeed, but the post I replied is not (Message 20) 😊

Cheers, D

0 Likes
Message 24 of 56

DRoam
Mentor
Mentor

@Anonymous  / @dba78 , the code I posed above should work fine in Sheet Metal parts. I just tested and it does. However, it will return the bounding box of the FOLDED version of the part, not the flat pattern.

 

 You could modify the code to get the oriented range box of the Flat Pattern. However, I think generally you would simply use the extents of the Flat Pattern, which have always been available using the "Width" and "Length" properties of the Flat Pattern. That said, depending on the Flat Pattern's orientation, the extents of the Flat Pattern may not actually correspond to the tightest possible length/width the flat pattern could be cut out from. So comparing the minimum bounding box size to the flat pattern extents would be a good way to check for that condition.

 

So, to that end, the code below will return both the minimum bounding box size and the extents size for the Flat Pattern:

 

' Get the current Part document.
Dim partDoc As PartDocument = ThisDoc.Document

'Get the Sheet Metal Component Definition.
Dim smCompDef As SheetMetalComponentDefinition = partDoc.ComponentDefinition

' Make sure Flat Pattern exists.
If Not smCompDef.HasFlatPattern Then MessageBox.Show("Must create Flat Pattern first") : Exit Sub
	
' Get the Flat Pattern.
Dim fPattern As FlatPattern = smCompDef.FlatPattern

' Get Flat Pattern's surface body.
Dim flatPatternBody As SurfaceBody = fPattern.SurfaceBodies.Item(1)

' Get the oriented mininum range box of the Flat Pattern body.
' NOTE: "OrientedMinimumRangeBox" was added in Inventor 2020.3/2021.
Dim minBox As OrientedBox = flatPatternBody.OrientedMinimumRangeBox

' Get length of each side of mininum range box.
Dim dir1 As Double = minBox.DirectionOne.Length
Dim dir2 As Double = minBox.DirectionTwo.Length
Dim dir3 As Double = minBox.DirectionThree.Length

' Convert lengths to document's length units.
Dim uom As UnitsOfMeasure = partDoc.UnitsOfMeasure

dir1 = uom.ConvertUnits(dir1, "cm", uom.LengthUnits)
dir2 = uom.ConvertUnits(dir2, "cm", uom.LengthUnits)
dir3 = uom.ConvertUnits(dir3, "cm", uom.LengthUnits)

' Sort lengths from smallest to largest.
Dim lengths As New List(Of Double) From {dir1, dir2, dir3 }
lengths.Sort

Dim minLength As Double = lengths(0)
Dim midLength As Double = lengths(1)
Dim maxLength As Double = lengths(2)

' Get Flat Pattern extents for comparison.
Dim fpDir1 As Double = ThisApplication.MeasureTools.GetMinimumDistance(fPattern.TopFace, fPattern.BottomFace)
Dim fpDir2 As Double = fPattern.Width
Dim fpDir3 As Double = fPattern.Length

fpDir1 = uom.ConvertUnits(fpDir1, "cm", uom.LengthUnits)
fpDir2 = uom.ConvertUnits(fpDir2, "cm", uom.LengthUnits)
fpDir3 = uom.ConvertUnits(fpDir3, "cm", uom.LengthUnits)

lengths = New List(Of Double) From {fpDir1, fpDir2, fpDir3 }
lengths.Sort

Dim fpMinLength As Double = lengths(0)
Dim fpMidLength As Double = lengths(1)
Dim fpMaxLength As Double = lengths(2)

' Display minimum rangebox size.
MessageBox.Show("Flat Pattern Oriented Minimum Rangebox Size: " & vbCr &
	minLength.ToString("0.###") & " x " & midLength.ToString("0.###") & " x " & maxLength.ToString("0.###") & vbCr &
	vbCr &
	"Flat Pattern Extents Size: " & vbCr &
	fpMinLength.ToString("0.###") & " x " & fpMidLength.ToString("0.###") & " x " & fpMaxLength.ToString("0.###"),
	"Flat Pattern Size", MessageBoxButtons.OK, MessageBoxIcon.Information)
0 Likes
Message 25 of 56

dba78
Advocate
Advocate

As of MultiBody: OrientedBox has no "Add"-Method, like the box object, so you need to combine the bodies into one and get the prop from this one. Fortunatelly this can be done with transientBrep (purely mathematically):

 

 

 

 

'iLogic

Dim brep = ThisApplication.TransientBRep
Dim bodies As SurfaceBodies
bodies = ThisApplication.ActiveDocument.Componentdefinition.surfacebodies

'Exception if there is no body at all
Dim blank =  brep.Copy (bodies(1))

'I know, there is a redundance with the first body :-)
For Each body In bodies
	brep.DoBoolean (blank, brep.Copy (body), BooleanTypeEnum.kBooleanTypeUnion  )
Next

MsgBox("1 : " & blank.OrientedMinimumRangeBox.DirectionOne.Length & vbCrLf & _
"2 : " & blank.OrientedMinimumRangeBox.DirectionTwo.Length & vbCrLf & _
"3 : " & blank.OrientedMinimumRangeBox.DirectionThree.Length )

 

 

 

something similar can be done with assemblies too, there you loop over the occurrences (AllLeafOccurrences) (since only parts has surfacebodies - except welds, etc) Be cautios with the Assembly-Size, Performance can be an issue!

Message 26 of 56

dba78
Advocate
Advocate

and for the flat pattern Extents:

 

 

'iLogic

Dim fp As FlatPattern
'assume ActiveDocument is a sheetmetalpart and flatpattern already exist
fp = ThisApplication.ActiveDocument.ComponentDefinition.Flatpattern
'flatpattern has it's own Surfacebodies Property
blank = fp.SurfaceBodies(1)

MsgBox("1 : " & blank.OrientedMinimumRangeBox.DirectionOne.Length & vbCrLf & _
"2 : " & blank.OrientedMinimumRangeBox.DirectionTwo.Length & vbCrLf & _
"3 : " & blank.OrientedMinimumRangeBox.DirectionThree.Length )

 

0 Likes
Message 27 of 56

dba78
Advocate
Advocate

sorry @DRoam , overseen, you added the flatpattern-part. 🙂

0 Likes
Message 28 of 56

_dscholtes_
Advocate
Advocate

@dba78 Thank you for posting a solution. I did already solve the issue in exactly the same way, by using B-reps, but now the whole community can benefit.

I'm a bit worried that the redundancy of the first body will be an issue. Lately, I have received some user feedback that in certain cases my macro fails and a quick inspection learned it tried to union a body with itself (both bodies had the same ID upon inspection in the debugger). I have not looked into it in detail though. Did you test the code?

0 Likes
Message 29 of 56

DRoam
Mentor
Mentor

Hopefully this is useful to some -- this is a rule that will get the bounding box of all solids in a part, and not only tell you its size, but also display it in the part so you can see how it's oriented and how it encapsulates all the solids:

 

' Get the current Part document.
Dim partDoc As PartDocument = ThisDoc.Document

' Get the TransientBRep and TransientGeometry objects.
Dim transBRep As TransientBRep = ThisApplication.TransientBRep
Dim transGeom As TransientGeometry = ThisApplication.TransientGeometry

' Combine all bodies in Part into a single transient Surface Body.
Dim combinedBodies As SurfaceBody = Nothing
For Each surfBody As SurfaceBody In partDoc.ComponentDefinition.SurfaceBodies
	If combinedBodies Is Nothing Then
		combinedBodies = transBRep.Copy(surfBody)
	Else
		transBRep.DoBoolean(combinedBodies, surfBody, BooleanTypeEnum.kBooleanTypeUnion)
	End If
Next

' Get the oriented mininum range box of all bodies in Part.
' NOTE: "OrientedMinimumRangeBox" was added in Inventor 2020.3/2021.
Dim minBox As OrientedBox = combinedBodies.OrientedMinimumRangeBox

' Get length of each side of mininum range box.
Dim dir1 As Double = minBox.DirectionOne.Length
Dim dir2 As Double = minBox.DirectionTwo.Length
Dim dir3 As Double = minBox.DirectionThree.Length

' Convert lengths to document's length units.
Dim uom As UnitsOfMeasure = partDoc.UnitsOfMeasure

dir1 = uom.ConvertUnits(dir1, "cm", uom.LengthUnits)
dir2 = uom.ConvertUnits(dir2, "cm", uom.LengthUnits)
dir3 = uom.ConvertUnits(dir3, "cm", uom.LengthUnits)

' Sort lengths from smallest to largest.
Dim lengths As New List(Of Double) From {dir1, dir2, dir3 }
lengths.Sort

Dim minLength As Double = lengths(0)
Dim midLength As Double = lengths(1)
Dim maxLength As Double = lengths(2)

' Create surface to represent oriented range box...

' Create starting box with dimensions of oriented rangebox.
Dim startBox As Box = transGeom.CreateBox()
Dim boxMaxPoint As Point = transGeom.CreatePoint(minBox.DirectionOne.Length, minBox.DirectionTwo.Length, minBox.DirectionThree.Length)
startBox.Extend(boxMaxPoint)

' Create transformation matrix to move box to correct location/orientation.
Dim transMatrix As Matrix = ThisApplication.TransientGeometry.CreateMatrix
transMatrix.SetCoordinateSystem(minBox.CornerPoint, minBox.DirectionOne.AsUnitVector.AsVector, minBox.DirectionTwo.AsUnitVector.AsVector, minBox.DirectionThree.AsUnitVector.AsVector)

' Create surface body for the range box.
Dim minBoxSurface As SurfaceBody = ThisApplication.TransientBRep.CreateSolidBlock(startBox)

' Transform range box surface body to the correct location/orientation.
ThisApplication.TransientBRep.Transform(minBoxSurface, transMatrix)

' Display range box on screen.
Dim transac As Transaction = ThisApplication.TransactionManager.StartTransaction(partDoc, "DisplayRangeBox")

Dim cGraphics As ClientGraphics

Try
	cGraphics = partDoc.ComponentDefinition.ClientGraphicsCollection.Add("OrientedRangeBox")
	Dim surfacesNode As GraphicsNode = cGraphics.AddNode(1)
	Dim surfGraphics As SurfaceGraphics = surfacesNode.AddSurfaceGraphics(minBoxSurface)
	Dim targetAppearance As Asset
	
	Try
		targetAppearance = partDoc.Assets.Item("Clear - Blue")
	Catch
		Dim sourceAppearance As Asset = ThisApplication.AssetLibraries.Item("314DE259-5443-4621-BFBD-1730C6CC9AE9").AppearanceAssets.Item("InvGen-001-1-2") ' "Clear - Blue"
		targetAppearance = sourceAppearance.CopyTo(partDoc)
	End Try
	
	surfacesNode.Appearance = targetAppearance

	ThisApplication.ActiveView.Update

	' Display message with minimum rangebox size.
	MessageBox.Show("Oriented Minimum Rangebox Size: " &
	minLength.ToString("#.###") & " x " & midLength.ToString("#.###") & " x " & maxLength.ToString("#.###"),
	"Oriented Minimum Rangebox", MessageBoxButtons.OK, MessageBoxIcon.Information)
Finally
	' Remove range box from screen.
	transac.Abort
	ThisApplication.ActiveView.Update
End Try

 

Here's a sample result:

OrientedRangeBoxDisplay.png

Message 30 of 56

dba78
Advocate
Advocate

@_dscholtes_ 

Hello, tested slightly, worked at first glance for a simple part. I know it's not nicely implemented, that's why I commented about the redundancy. My point was to show the idea, and I skipped all the error checking/optimization (acitvedocument-type, existence of surfacebodies at all, etc.). As I experienced, the brep-operation on the native body may fail sometimes, therefore I always create a mathematical copy (brep.Copy) before boolean operation

BR,

Daniel

0 Likes
Message 31 of 56

dba78
Advocate
Advocate

for sake of completeness, here one possible solution for assemblies. Again, slightly tested 😊

 

'iLogic
Imports System.Linq

Dim assy As AssemblyDocument =ThisApplication.ActiveDocument 
Dim assyCD As AssemblyComponentDefinition=assy.ComponentDefinition 
Dim brep As TransientBRep = ThisApplication.TransientBRep 

Dim bodies = assyCD.Occurrences.AllLeafOccurrences.Cast(Of ComponentOccurrence).SelectMany(Function(occ) occ.Definition.SurfaceBodies.Cast (Of SurfaceBody))

Dim blank As SurfaceBody = brep.Copy (bodies.first)

For Each body In bodies.Skip(1)
	brep.DoBoolean (blank, brep.Copy (body), BooleanTypeEnum.kBooleanTypeUnion )
Next

MsgBox("1 : " & blank.OrientedMinimumRangeBox.DirectionOne.Length & vbCrLf & _
"2 : " & blank.OrientedMinimumRangeBox.DirectionTwo.Length & vbCrLf & _
"3 : " & blank.OrientedMinimumRangeBox.DirectionThree.Length)

 

0 Likes
Message 32 of 56

_dscholtes_
Advocate
Advocate

@dba78 FYI, I found out the redundancy of the first body is not the reason my macro fails. It fails when it tried to union a surface body (IsSolid = False) with a solid body (IsSolid = True). Turns out we use surface bodies more than I was told and that they cannot simply be discarded. Oh, well, challenge accepted.

0 Likes
Message 33 of 56

brendon.serrano
Enthusiast
Enthusiast

Here is the code we use for sheet metal. It doesnt address the orientation issue, but it works for general purposes. you would have to edit the code to work for your purposes, but all of the functionality should be there. 

 

oDoc = ThisDoc.Document


'Get active document unit of measure
Dim uom As UnitsOfMeasure = oDoc.UnitsOfMeasure
'Converts length unit to a string
Dim Units As String = uom.GetStringFromType(uom.LengthUnits)

Dim oParameter As Parameter
Dim oFormat As CustomPropertyFormat

For Each oParameter In oDoc.ComponentDefinition.Parameters.UserParameters
	If Units = "inch" Then
		If oParameter.ExposedAsProperty Then
			oFormat = oParameter.CustomPropertyFormat
			oFormat.Units = Units
			oFormat.Precision = Inventor.CustomPropertyPrecisionEnum.kSixteenthsFractionalLengthPrecision
		End If 
	Else
		If oParameter.ExposedAsProperty Then
			oFormat = oParameter.CustomPropertyFormat
			oFormat.Units = Units
			oFormat.Precision = Inventor.CustomPropertyPrecisionEnum.kTwoDecimalPlacesPrecision
		End If 
	 End If 
Next 



'Checks To see If the active document Is a standard part
If oDoc.SubType = "{4D29B490-49B2-11D0-93C3-7E0706000000}" Then
	   'Go To the FlatPattern
	   Dim oSMCD As SheetMetalComponentDefinition
	   oSMCD = oDoc.ComponentDefinition
	   'Look For Flatpattern
	   If Not oSMCD.HasFlatPattern Then
	      'Create Flatpattern If the part doesn't have one
	      oSMCD.Unfold()
	      oDoc.Update2(True)
	      oSMCD.FlatPattern.ExitEdit()
	   End If

	   'create the component definition of Flatpattern
	   Dim oFPCD As ComponentDefinition = oSMCD.FlatPattern

	   'Get the min and max point of the Flatpattern
	   Dim minPoint As Point = oFPCD.SurfaceBodies.Item(1).RangeBox.MinPoint
	   Dim maxPoint As Point = oFPCD.SurfaceBodies.Item(1).RangeBox.MaxPoint
	   'X, Y & Z values are maxPoint - minPoint'Since FlatPattern always returns "cm", we also have to do some conversion to match the document's unit of measure
	   X = uom.ConvertUnits ((maxPoint.X - minPoint.X), "cm", uom.LengthUnits)
	   Dim Y As Double = uom.ConvertUnits ((maxPoint.Y - minPoint.Y), "cm", uom.LengthUnits)
	   Dim Z As Double = uom.ConvertUnits ((maxPoint.Z - minPoint.Z), "cm", uom.LengthUnits)

	   Dim LengthString As String = MaxOfMany (X,Y,Z)
	   Dim WidthString As String = X + Y + Z - MaxOfMany (X,Y,Z) - MinOfMany(X,Y,Z)
	   Dim ThicknessString As String = MinOfMany(X, Y, Z)
	   
	   RoundThick = Round(CDblAny(ThicknessString), 4)-0.001
	   RoundWidth = Round(CDblAny(WidthString), 4)-0.001
	   RoundLength = Round(CDblAny(LengthString), 4)-0.001
	   'MsgBox(RoundThick)
	   'MsgBox(RoundWidth)
	   'MsgBox(RoundLength)
	   
	   
	   If Units = "inch"
		   If Parameter("MATL_SHAPE") = "SHEET"
			   Parameter("EX_TH") = RoundThick.ToString
			   Parameter("EX_W") = RoundToFraction(RoundWidth, 1/16, RoundingMethod.RoundUp)
			   Parameter("EX_L") = RoundToFraction(RoundLength, 1/16, RoundingMethod.RoundUp)
		   Else 
			   Parameter("EX_TH") = RoundToFraction(RoundThick, 1/16, RoundingMethod.RoundUp)
			   Parameter("EX_W") = RoundToFraction(RoundWidth, 1/16, RoundingMethod.RoundUp)
			   Parameter("EX_L") = RoundToFraction(RoundLength, 1/16, RoundingMethod.RoundUp)
		   End If 
		Else
			Parameter("EX_TH") = Round(RoundThick, 1)
			Parameter("EX_W") = Round(RoundWidth, 1)
			Parameter("EX_L") = Round(RoundLength, 1)
		End If 
End If

 I tried to delete some useless lines from our code (we would convert parts to sheetmetal and back to get the size of them this way as well. 

 

Hope this helps!

0 Likes
Message 34 of 56

NachoShaw
Advisor
Advisor

with a flat pattern, you can get these sizes natively by using

 

FlatPattern.Length()

FlatPattern.width()

Thickness is set in the Sheet Metal parameters

 

you can also get the true XYZ of a part / assembly by calling the 'OrientedMinimumRangebox()'

 

 

Nacho
Automation & Design Engineer

Inventor automation Programmer (C#, VB.Net / iLogic)
Furniture, Sheet Metal, Structural, Metal fab, Tradeshow, Fabrication, CNC

EESignature


Did you find this post helpful? Feel free to Like this post.
Did your question get successfully answered? Then click on the ACCEPT SOLUTION button.


0 Likes
Message 35 of 56

dba78
Advocate
Advocate
Accepted solution

- The point of the OrientedMinimumRangeBox IS, that's independent of XYZ
- This Property is part of the SurfaceBody-Object, and since Assemby Surfacebodies doesn't include the Bodies of the Occurrences (to be honest, I've never seen anything in there), you can't "call the OrientedMinimumBox" on it...

The provided Flatpattern.Width, etc still sticks to xyz (of the Flatpattern-CS), which can be defined by Inventor, or the user, and is not necessarily a minimum solution... but the Flatpattern has also Surfacebodies, so you can call this Prop on them

No offense, but please try to stay accurate when you post an answer, your comment is pretty clumsy and not really helpful

0 Likes
Message 36 of 56

NachoShaw
Advisor
Advisor

What is clumsy about it Daniel? It's true that you can get the flat pattern extents from a part irrespective of the origin coordinates. There are some methods around showing this and also was a suggestion from an autodesk guy on here once stating that converting a part to FP would give the extents.

 

As far as assembly goes, I am getting my xyz somehow and seeing as I recently wrote the functions for both part and assembly, its working somehow. I'll check my code obvs but I'm pretty sure I am using something very similar to OrientedMinimumRangeBox.

 

Lastly, when someone says 'no offense but', it means offense in the same way as 'I'm not being rude but' is being rude.

 

Be mindful how you respond to people because they (I) will be less likely to reply in future

Nacho
Automation & Design Engineer

Inventor automation Programmer (C#, VB.Net / iLogic)
Furniture, Sheet Metal, Structural, Metal fab, Tradeshow, Fabrication, CNC

EESignature


Did you find this post helpful? Feel free to Like this post.
Did your question get successfully answered? Then click on the ACCEPT SOLUTION button.


0 Likes
Message 37 of 56

dba78
Advocate
Advocate

So first, I really didn't mean to be rude.

 

The first part may be a reflection to the message you replied, but does not provide a useful answer to the topic itself.

 

And: 

"you can also get the true XYZ of a part / assembly by calling the 'OrientedMinimumRangebox()' "

This is just not right

  • Calling the 'OrientedMinimumRangebox' gives NOT 'true XYZ', it gives true Extents regardless of XYZ
  • Can't call it on assembly (need to parse the Occurrences)
  • the 'true XYZ' is obtained by Componentdefintion.Rangebox... (in XYZ, but even this can be "untrue" sometimes ) 

 

By saying "you can get XYZ of a part..." you probably referred to the 'RangeBox'-Property, which is indeed available at the Componentdefinition object (Part & Assembly).

 

So in context of the Topic such an answer is like "hey dudes, are you all rookies or what..."

However, didn't mean to be mean to anyone...

 

0 Likes
Message 38 of 56

brendon.serrano
Enthusiast
Enthusiast

I shared the code I wrote in response to a comment that I no longer see, so it doesnt seem to be useful in this thread any longer. However, there are many people on the forums who are rookies. I for one wrote that code with maybe 2 months experience and that was the best way I could find to do it at the time. I appreciate people pointing out how I can improve my code. Thank you both for your diligent replies! @NachoShaw @dba78 

0 Likes
Message 39 of 56

ganesh_omkaar
Contributor
Contributor

Please attached image how it's work with example

0 Likes
Message 40 of 56

ganesh_omkaar
Contributor
Contributor

Nice invention by Autodesk Inventor for scew part it's very helpful for skeletal method. lot of time save by this code. many thank for this for this code

0 Likes