External Rule Performing Differently When Accessed From Assembly

External Rule Performing Differently When Accessed From Assembly

mason_pfauE84JT
Explorer Explorer
619 Views
3 Replies
Message 1 of 4

External Rule Performing Differently When Accessed From Assembly

mason_pfauE84JT
Explorer
Explorer

Hi,
I'm running into an issue when running a rule on a part, accessed at the assembly level.

For context, I'm trying to generate a standard set of custom iProperties (PART_LENGTH, PART_WIDTH, and PART_THICKNESS) in a part file, regardless of whether the original part had those properties. When run at the part level, the rule works as intended, outputting the expected values written as a custom iProperty. However, when the rule is run at the assembly level, half of the parts output the correct value, and half of the parts display the same (incorrect) values: Length= 12 13/16, Width=12 5/16, and Thickness=5 9/16. 

To access the external rules, I've been using this rule, run from the assembly:

Imports System.Threading
Sub Main()
    Dim asmDoc As AssemblyDocument = ThisApplication.ActiveDocument
    ProcessAssembly(asmDoc)
    MessageBox.Show("Parts and Subassemblies Updated", " ")
End Sub

Sub ProcessAssembly(asmDoc As AssemblyDocument)
    For Each oRefDoc As Document In asmDoc.AllReferencedDocuments
        If oRefDoc.DocumentType = DocumentTypeEnum.kPartDocumentObject Then
            ProcessPart(oRefDoc)
        ElseIf oRefDoc.DocumentType = DocumentTypeEnum.kAssemblyDocumentObject Then
            ' Open the subassembly document with write permissions
            Dim subAsmDoc As AssemblyDocument = ThisApplication.Documents.Open(oRefDoc.FullFileName, False)
            ' Process the subassembly
            ProcessAssembly(subAsmDoc)
            ' Save and close the subassembly document
            subAsmDoc.Save()
            subAsmDoc.Close()
        End If
    Next
End Sub



Sub ProcessPart(partDoc As Document)
    ' Open the part document with write permissions
    partDoc = ThisApplication.Documents.Open(partDoc.FullFileName, False)
    ' Add a small delay before activation
    Thread.Sleep(500)
    ' Check if the document is already active
    If Not partDoc Is ThisApplication.ActiveDocument Then
        Try
            partDoc.Activate()
            ' Add a delay to ensure activation
            Thread.Sleep(500)
        Catch ex As Exception
            Debug.Print("Error activating document: " & ex.Message)
        End Try
    End If
    ' Log document activation
    Debug.Print("Activated document: " & partDoc.FullFileName)
    ' Add a 500ms delay before running external rules
    Thread.Sleep(500)
    ' Run the external rules
    RunExternalRules(partDoc)
    ' Add a 500ms delay after running external rules
    Thread.Sleep(500)
    ' Save and close the document
    partDoc.Save()
    partDoc.Close()
    ' Log document processing completion
    Debug.Print("Processed document: " & partDoc.FullFileName)
End Sub




Sub RunExternalRules(partDoc As Document)
    Dim ruleNames As String() = {"AUTO_SIZE"}
    For Each ruleName As String In ruleNames
        Try
            iLogicVb.Automation.RunExternalRule(partDoc, ruleName)
        Catch ex As Exception
            ' Handle exceptions if needed
        End Try
    Next
End Sub

 

The external rule I'm accessing (AUTO_SIZE) is:

'THIS RULE DETERMINES PART SIZE USING TWO METHODS. 
'THE FIRST METHOD MEASURES THE PART AGAINST THE DEFAULT XYZ ORIENTATION.
'THE SECOND METHOD IS USED IF A PART IS NOT ALIGNED WITH THE DEFAULT XYZ AXIS, 
'AND IS DEPENDENT ON A USER-DEFINED UCS (WORK FEATURES > UCS). 

'THE PART'S MEASUREMENTS ARE OUTPUT AS A SORTED LIST:
'PARTS ARE SORTED BY:  "PART_LENGTH" > "PART_WIDTH" > "PART_THICKNESS" AND OUTPUT AS A 
'CUSTOM IPROPERTY VALUE ROUNDED TO THE NEAREST 1/16" (ADJUSTABLE, SEE "Dim inc =").

'RULE SHOULD BE RUN IN THE PART ENVIRONMENT

Dim oDoc As Document
oDoc = ThisDoc.Document

Dim oPDef As PartComponentDefinition = oDoc.ComponentDefinition
Dim oUCSs As UserCoordinateSystems = oPDef.UserCoordinateSystems
Dim oUCS As UserCoordinateSystem = Nothing

Dim oA As Double
Dim oB As Double
Dim oC As Double

'DEFINE ROUNDING INCREMENT FOR FRACTIONAL OUTPUT HERE<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
Dim inc = .0625' rounding increment ( .125, .25, .5, etc)

If oUCSs.Count = 0 Then 
    'IF NO USER-DEFINED UCS, USE DEFAULT PART ORIENTATION
	
    oA = Math.Round(Measure.PreciseExtentsLength, 3)
    oB = Math.Round(Measure.PreciseExtentsWidth, 3)
    oC = Math.Round(Measure.PreciseExtentsHeight, 3)
	
Else
	'IF USER DEFINED UCS IS PRESENT, MEASURE PART BASED ON THAT
	Dim sb As SurfaceBody = oDoc.ComponentDefinition.SurfaceBodies.Item(1) 'get 3d solid
	Dim ucs As UserCoordinateSystem = oDoc.ComponentDefinition.UserCoordinateSystems(1)'get custom user coordinate system
	Dim vPoints As New List(Of Point) 'create a list of points (for sorting)
	Dim mat As Matrix = ucs.Transformation 'get the transformation matrix from the usc (what it takes to translate from user ucs to origin)
	mat.Invert() 'invert the matrix (what it takes to translate from origin to user ucs)
	For Each vert As Vertex In sb.Vertices 'cycle through all the points
	    Dim p As Point = vert.Point 'get the Point data From the Vertex
	    p.TransformBy(mat) 'invert translate the point data (from origin to user ucs)
	    vPoints.Add(p) 'add translated point to collection
	Next
	Dim tg = ThisApplication.TransientGeometry 'create empty min and max points
	Dim minPoint As Point = tg.CreatePoint(0, 0, 0)
	Dim maxPoint As Point = tg.CreatePoint(0, 0, 0)
	'sort points based on x values, and get lowest and highest value
	vPoints.Sort(Function(x, y) x.X.CompareTo(y.X))
	minPoint.X = vPoints.First.X
	maxPoint.X = vPoints.Last.X
	'sort points based on y values, and get lowest and highest values
	vPoints.Sort(Function(x, y) x.Y.CompareTo(y.Y))
	minPoint.Y = vPoints.First.Y
	maxPoint.Y = vPoints.Last.Y
	'sort points based on z values, and get lowest and highest values
	vPoints.Sort(Function(x, y) x.Z.CompareTo(y.Z))
	minPoint.Z = vPoints.First.Z
	maxPoint.Z = vPoints.Last.Z
	
	Dim sizeX As Double = Math.Abs(maxPoint.X - minPoint.X)
	Dim sizeY As Double = Math.Abs(maxPoint.Y - minPoint.Y)
	Dim sizeZ As Double = Math.Abs(maxPoint.Z - minPoint.Z)
	
	oA = Math.Round(sizeX/2.54, 5)
	oB = Math.Round(sizeY/2.54, 5)
	oC = Math.Round(sizeZ/2.54, 5)
End If

Dim sortedValues As New List(Of Double) From {oA, oB, oC}

' Sort the values in descending order
sortedValues.Sort(Function(a, b) b.CompareTo(a))

' Now you can access the sorted values
Dim sortedOa As Double = sortedValues(0)
Dim sortedOb As Double = sortedValues(1)
Dim sortedOc As Double = sortedValues(2)

' Use sortedOa, sortedOb, and sortedOc as needed 
' THESE STRINGS DETERMINE THE OUTPUT NAME OF THE CUSTOM IPROPERTIES
Dim propLength As String = "PART_LENGTH"
Dim Length As Double = sortedOa
Dim propWidth As String = "PART_WIDTH"
Dim Width As Double = sortedOb
Dim propHeight As String = "PART_THICKNESS"
Dim Height As Double = sortedOc
Dim roundedLength As Double = Math.Round(Length / inc) * inc
Dim roundedWidth As Double = Math.Round(Width / inc) * inc
Dim roundedHeight As Double = Math.Round(Height / inc) * inc

customPropertySet = ThisDoc.Document.PropertySets.Item("Inventor User Defined Properties")
Try
    prop = customPropertySet.Item(propLength)
Catch ' Assume error means not found
    customPropertySet.Add("", propLength)
End Try
Try
    prop = customPropertySet.Item(propWidth)
Catch  ' Assume error means not found
    customPropertySet.Add("", propWidth)
End Try
Try
    prop = customPropertySet.Item(propHeight)
Catch  ' Assume error means not found
    customPropertySet.Add("", propHeight)
End Try

iProperties.Value("Custom", propLength) = FormatAsFraction(roundedLength)
iProperties.Value("Custom", propWidth) = FormatAsFraction(roundedWidth)
iProperties.Value("Custom", propHeight) = FormatAsFraction(roundedHeight)



I'm not an expert at coding, but there's been a lot of helpful content on here that's gotten me to this point. I'm running out of ideas as to why I'm getting incorrect values when run from the assembly, but running the rule from the part level shows the expected values.

0 Likes
Accepted solutions (1)
620 Views
3 Replies
Replies (3)
Message 2 of 4

TomaszDabrowski
Autodesk
Autodesk
Accepted solution

Hi.

Looks like the problem is not with code, but with parameters. Your parameters are exported to custom iProperties. 

The rule inserts correct values, but in the end, the values are overwritten by those from parameters.

Uncheck the Export checkboxes in parameters to make it work.

 

 

Tomasz Dąbrowski
Technical Support Specialist
Customer Technical Success
0 Likes
Message 3 of 4

_dscholtes_
Advocate
Advocate

Side-note, when accessing assembly components, you either:

  1. Go through AllReferencedDocuments (as a list of documents) or
  2. Travel along the assembly tree (using a recursive function to access all component occurrences).

You do a combination of both, which is unnecessary (extra processing work / time as multiple components can be reverenced by a single document). Please find a nice article here about travelling assembly components by Brian Ekins (original Inventor API designer).

0 Likes
Message 4 of 4

mason_pfauE84JT
Explorer
Explorer
Thanks for the quick response, this worked!
I'll have to spend some time cleaning up the way the parts are called from the assembly to minimize the processing time required.
0 Likes