Apply cut length rule to all parts within an assembly

Apply cut length rule to all parts within an assembly

peterkerman
Contributor Contributor
814 Views
9 Replies
Message 1 of 10

Apply cut length rule to all parts within an assembly

peterkerman
Contributor
Contributor


Hi There,

 

Please can someone help with applying an ilogic rule to all parts within an assembly, I have combined a few ideas to create the rule below, this determines the max cut length assuming that the cut length is always larger than the section size, it then adds this as a custom iproperty "cut length".

 

This works nicely on individual parts but we want to deploy to all parts within an assembly so that all new BOMs have this information included.

 

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

' Get surface body to measure (assume it's the first body).
Dim body1 As SurfaceBody = partDoc.ComponentDefinition.SurfaceBodies.Item(1)

' Get the oriented mininum range box of the body.
' NOTE: "OrientedMinimumRangeBox" was added in Inventor 2020.3/2021.
Dim minBox As OrientedBox = body1.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)

iProperties.Value("Custom", "Cut Length") = Round(maxLength, 2)

 

Thank you, Pete

0 Likes
Accepted solutions (1)
815 Views
9 Replies
Replies (9)
Message 2 of 10

WCrihfield
Mentor
Mentor

Hi @peterkerman.  Here is something that should work for you.  You can use this rule on either a part or an assembly.  And if used on an assembly, it will attempt to process every referenced part within all levels of the assembly.

Sub Main
	Dim oDoc As Inventor.Document = ThisDoc.Document
	If oDoc.DocumentType = DocumentTypeEnum.kPartDocumentObject Then
		RecordCutLength(oDoc)
	ElseIf oDoc.DocumentType = DocumentTypeEnum.kAssemblyDocumentObject Then
		Dim oRefDocs As DocumentsEnumerator = oDoc.AllReferencedDocuments
		For Each oRefDoc As Inventor.Document In oRefDocs
			If oRefDoc.DocumentType = DocumentTypeEnum.kPartDocumentObject Then
				RecordCutLength(oDoc)
			End If
		Next 'oRefDoc
	Else 'not part or assembly
		Exit Sub
	End If
	If oDoc.RequiresUpdate Then oDoc.Update2(True)
	'If oDoc.Dirty Then oDoc.Save2(True)
End Sub

Sub RecordCutLength(oPDoc As PartDocument)
	If oPDoc.IsModifiable = False Then Exit Sub
	Dim oBodies As SurfaceBodies = oPDoc.ComponentDefinition.SurfaceBodies
	If oBodies.Count = 0 Then Exit Sub
	Dim oBox As OrientedBox = oBodies.Item(1).OrientedMinimumRangeBox
	Dim oLengths As New List(Of Double)
	oLengths.Add(oBox.DirectionOne.Length)
	oLengths.Add(oBox.DirectionTwo.Length)
	oLengths.Add(oBox.DirectionThree.Length)
	oLengths.Sort
	Dim dMaxLength As Double = oLengths.Last
	Dim UOM As UnitsOfMeasure = oPDoc.UnitsOfMeasure
	dMaxLength = Round(UOM.ConvertUnits(dMaxLength, "cm", UOM.LengthUnits), 2)
	Dim oCProps As Inventor.PropertySet = oPDoc.PropertySets.Item(4)
	Dim oCProp As Inventor.Property = Nothing
	Try
		oCProp = oCProps.Item("Cut Length")
		oCProp.Value = dMaxLength
	Catch
		oCProp = oCProps.Add(dMaxLength, "Cut Length")
	End Try
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)

0 Likes
Message 3 of 10

peterkerman
Contributor
Contributor

Hi @WCrihfield,

 

Thank you for looking into this for me, the following error returns when the code is run:

 

Error on line 9 in rule: CutLengthAssy, in document: VOY2011.iam

Unable to cast COM object of type 'System.__ComObject' to interface type 'Inventor.PartDocument'. This operation failed because the QueryInterface call on the COM component for the interface with IID '{29F0D463-C114-11D2-B77F-0060B0F159EF}' failed due to the following error: No such interface supported (Exception from HRESULT: 0x80004002 (E_NOINTERFACE)).

 

Does the first part apply to each member in the assembly and the second just determines the value.

 

Best Regards,

 

Pete

 

0 Likes
Message 4 of 10

WCrihfield
Mentor
Mentor

I see the issue.  It does not like converting a generic Document type object into the more specific type (PartDocument).  To fix that, within the Sub Main area, I replaced the following line, which appears twice:

RecordCutLength(oDoc)

...with these two lines:

Dim oPDoc As PartDocument = oDoc
RecordCutLength(oPDoc)

...that way we are sending an actual PartDocument to the custom Sub routine, which is set up to receive a PartDocument type input.

The custom Sub routine named RecordCutLength is essentially the same task code you already had, but instead of using 'ThisDoc.Document' to identify which document it will attempt to process, that routine is being supplied the document to process by the main routine.  Then the main routine is handling whether the 'active' document is a part or an assembly.  If it is a part, then it passes that part directly down to that sub routine.  If it is an assembly, then it iterates through all of the documents referenced by that assembly, and if any of them is a part, it sends that part to the sub routine to process.  Then I also included a couple lines of code for updating the document after the processing.  If the active document was an assembly, and it processed a bunch of parts within that assembly, then updating the assembly should also update those referenced parts within it, because they are all invisibly open in the background.

Wesley Crihfield

EESignature

(Not an Autodesk Employee)

Message 5 of 10

WCrihfield
Mentor
Mentor

I just noticed another opportunity to further reduce the several lines of code down to one line within the RecordCutLengh Sub routing.  Instead of the List(Of Double) object, we could have used the MaxOfMany() Math function, which returns the 'Max' value of all the input values, as a Double.  So, all these lines of code:

Dim oLengths As New List(Of Double)
oLengths.Add(oBox.DirectionOne.Length)
oLengths.Add(oBox.DirectionTwo.Length)
oLengths.Add(oBox.DirectionThree.Length)
oLengths.Sort
Dim dMaxLength As Double = oLengths.Last

...could be reduced to just this one line of code:

Dim dMaxLength As Double = MaxOfMany(oBox.DirectionOne.Length, oBox.DirectionTwo.Length, oBox.DirectionThree.Length)

 

Wesley Crihfield

EESignature

(Not an Autodesk Employee)

Message 6 of 10

peterkerman
Contributor
Contributor

Hi  @WCrihfield

 

Sub Main
	Dim oDoc As Inventor.Document = ThisDoc.Document
	If oDoc.DocumentType = DocumentTypeEnum.kPartDocumentObject Then
		Dim oPDoc As PartDocument = oDoc
RecordCutLength(oPDoc)
	ElseIf oDoc.DocumentType = DocumentTypeEnum.kAssemblyDocumentObject Then
		Dim oRefDocs As DocumentsEnumerator = oDoc.AllReferencedDocuments
		For Each oRefDoc As Inventor.Document In oRefDocs
			If oRefDoc.DocumentType = DocumentTypeEnum.kPartDocumentObject Then
'				RecordCutLength(oDoc)
Dim oPDoc As PartDocument = oDoc
RecordCutLength(oPDoc)
			End If
		Next 'oRefDoc
	Else 'not part or assembly
		Exit Sub
	End If
	If oDoc.RequiresUpdate Then oDoc.Update2(True)
	'If oDoc.Dirty Then oDoc.Save2(True)
End Sub

Sub RecordCutLength(oPDoc As PartDocument)
	If oPDoc.IsModifiable = False Then Exit Sub
	Dim oBodies As SurfaceBodies = oPDoc.ComponentDefinition.SurfaceBodies
	If oBodies.Count = 0 Then Exit Sub
	Dim oBox As OrientedBox = oBodies.Item(1).OrientedMinimumRangeBox
	Dim dMaxLength As Double = MaxOfMany(oBox.DirectionOne.Length, oBox.DirectionTwo.Length, oBox.DirectionThree.Length)
	Dim UOM As UnitsOfMeasure = oPDoc.UnitsOfMeasure
	dMaxLength = Round(UOM.ConvertUnits(dMaxLength, "cm", UOM.LengthUnits), 2)
	Dim oCProps As Inventor.PropertySet = oPDoc.PropertySets.Item(4)
	Dim oCProp As Inventor.Property = Nothing
	Try
		oCProp = oCProps.Item("Cut Length")
		oCProp.Value = dMaxLength
	Catch
		oCProp = oCProps.Add(dMaxLength, "Cut Length")
	End Try
End Sub

I have modified the above but get the error:

Error on line 10 in rule: CutLengthAssy, in document: VOY2011.iam

Unable to cast COM object of type 'System.__ComObject' to interface type 'Inventor.PartDocument'. This operation failed because the QueryInterface call on the COM component for the interface with IID '{29F0D463-C114-11D2-B77F-0060B0F159EF}' failed due to the following error: No such interface supported (Exception from HRESULT: 0x80004002 (E_NOINTERFACE)).

 

Seems similar to the last error have I made the changes correctly?

 

TIA, Pete

0 Likes
Message 7 of 10

WCrihfield
Mentor
Mentor

You almost had it right.  You just need to set the value of oPDoc to oRefDoc, instead of oDoc on the assembly side.  I have attached the text file of the corrected code, to make it simpler.

Wesley Crihfield

EESignature

(Not an Autodesk Employee)

Message 8 of 10

peterkerman
Contributor
Contributor
@WCrihfield Thank you for helping,

For some reason I am getting the following error:
Error on line 10 in rule: Record Cut Length, in document: VOY2011.iam

Unable to cast COM object of type 'System.__ComObject' to interface type 'Inventor.PartDocument'. This operation failed because the QueryInterface call on the COM component for the interface with IID '{29F0D463-C114-11D2-B77F-0060B0F159EF}' failed due to the following error: No such interface supported (Exception from HRESULT: 0x80004002 (E_NOINTERFACE)).

Will try and work through, some of the commands are unfamiliar to me 🙂

Have a good weekend,

Pete
0 Likes
Message 9 of 10

WCrihfield
Mentor
Mentor
Accepted solution

I can't believe it.  I just downloaded the text file I had attached to my last response, and that document reference is still not the way I had it for some reason.  I don't know if there is some sort of history recall or copy/paste error going on, but it still shows setting the value of oPDoc to oDoc on the assembly side.  The exact thing that I fixed, and talked about in that last post, before posting that.  It's like it copied the 'old' version of the code, instead of the corrected version.  This time I am going to type the whole thing out on the forum window, and add lines of comments just before the lines where these problems are happening, to try to explain what needs to happen.  Maybe then it won't change on me before I can post it.

Sub Main
	Dim oDoc As Inventor.Document = ThisDoc.Document
	If oDoc.DocumentType = DocumentTypeEnum.kPartDocumentObject Then
		'the oDoc variable already represents a PartDocument now,
		'but the variable's Type is just a generic Document type
		'so we create a PartDocument type variable, then set oDoc as its value
		Dim oPDoc As PartDocument = oDoc
		'then send that PartDocument to the custom Sub routine below
		RecordCutLength(oPDoc)
	ElseIf oDoc.DocumentType = DocumentTypeEnum.kAssemblyDocumentObject Then
		Dim oRefDocs As DocumentsEnumerator = oDoc.AllReferencedDocuments
		For Each oRefDoc As Inventor.Document In oRefDocs
			If oRefDoc.DocumentType = DocumentTypeEnum.kPartDocumentObject Then
				'at this point we know that oDoc represents an AssemblyDocument
				'and oRefDoc represents a PartDocument, but both are still Document type variables
				'so, we create the PartDocument Type variable, and set its value to oRefDoc,
				'because we want to process the PartDocument that oRefDoc represents
				'we do not want to sent oDoc (an assembly) to that Sub routine
				Dim oPDoc As PartDocument = oRefDoc
				'then this next line sends that part to the Sub routine to process it
				RecordCutLength(oPDoc)
			End If
		Next 'oRefDoc
	Else 'not part or assembly
		Exit Sub
	End If
	If oDoc.RequiresUpdate Then oDoc.Update2(True)
	'If oDoc.Dirty Then oDoc.Save2(True)
End Sub

Sub RecordCutLength(oPDoc As PartDocument)
	If oPDoc.IsModifiable = False Then Exit Sub
	Dim oBodies As SurfaceBodies = oPDoc.ComponentDefinition.SurfaceBodies
	If oBodies.Count = 0 Then Exit Sub
	Dim oBox As OrientedBox = oBodies.Item(1).OrientedMinimumRangeBox
	Dim dMaxLength As Double = MaxOfMany(oBox.DirectionOne.Length, oBox.DirectionTwo.Length, oBox.DirectionThree.Length)
	Dim UOM As UnitsOfMeasure = oPDoc.UnitsOfMeasure
	dMaxLength = Round(UOM.ConvertUnits(dMaxLength, "cm", UOM.LengthUnits), 2)
	Dim oCProps As Inventor.PropertySet = oPDoc.PropertySets.Item(4)
	Dim oCProp As Inventor.Property = Nothing
	Try
		oCProp = oCProps.Item("Cut Length")
		oCProp.Value = dMaxLength
	Catch
		oCProp = oCProps.Add(dMaxLength, "Cut Length")
	End Try
End Sub

The error was happening because the code was trying to send an assembly 'oDoc' to that custom Sub routine that is expecting a part, and it can not convert an assembly into a part.  This is the whole reason why we have the lines of code in there for checking the DocumentType of every document involved.

 

Wesley Crihfield

EESignature

(Not an Autodesk Employee)

0 Likes
Message 10 of 10

peterkerman
Contributor
Contributor

@WCrihfield 

 

Thank you, I did try to edit but got stuck between 2 errors and couldn't see the issue.

 

Problem solved for me and now our cut lengths can be exported directly to our production system.

 

Much Appreciated,

 

Pete

0 Likes