Holes counting and sorting based on diameter.

Holes counting and sorting based on diameter.

Ahmed.shawkyXTZHN
Enthusiast Enthusiast
3,514 Views
23 Replies
Message 1 of 24

Holes counting and sorting based on diameter.

Ahmed.shawkyXTZHN
Enthusiast
Enthusiast

Hello all ,

I have one code to count the number of holes in the whole assembly , but I need to also sort the holes based on the dia.

for example  10 mm = # 100 

                        12 mm = # 50

and so on , so can Count the fasteners based on these details.

 holes counting rule .

'To run external rule for all sheet metal parts
Dim aDoc As AssemblyDocument
aDoc = ThisApplication.ActiveDocument
Dim iDoc As Document
For Each iDoc In aDoc.AllReferencedDocuments
If iDoc.SubType = "{9C464203-9BAE-11D3-8BAD-0060B0CE6BB4}" Then
auto = iLogicVb.Automation
auto.RunExternalRule(iDoc, ”Hole”)
iDoc.Close()
End If
Next

iLogicVb.UpdateWhenDone = True

  thanks in advance.

0 Likes
Accepted solutions (3)
3,515 Views
23 Replies
Replies (23)
Message 2 of 24

A.Acheson
Mentor
Mentor

You have attached the main rule and not the hole counting rule. Please attach the hole counting rule. If possible a sample file containing the holes. 

If this solved a problem, please click (accept) as solution.‌‌‌‌
Or if this helped you, please, click (like)‌‌
Regards
Alan
0 Likes
Message 3 of 24

Ahmed.shawkyXTZHN
Enthusiast
Enthusiast

Sorry , find the below.

 

Dim oDoc As PartDocument = ThisDoc.Document

If oDoc.SubType = "{9C464203-9BAE-11D3-8BAD-0060B0CE6BB4}" Then

  Dim oCD As SheetMetalComponentDefinition = oDoc.ComponentDefinition
  If oCD.HasFlatPattern = False Then 
	oCD.Unfold
	oCD.FlatPattern.ExitEdit
  End If

  Dim oFace As Face = oCD.FlatPattern.TopFace
  Dim i As Integer = oFace.EdgeLoops.Count-1

'  MessageBox.Show("Number of Holes: " & i)
iProperties.Value("Custom", "No Of Holes")= i
End If
0 Likes
Message 4 of 24

JhoelForshav
Mentor
Mentor

Hi @Ahmed.shawkyXTZHN 

How about something like this? 🙂

Dim oDoc As PartDocument = ThisDoc.Document

If oDoc.SubType = "{9C464203-9BAE-11D3-8BAD-0060B0CE6BB4}" Then

  Dim oCD As SheetMetalComponentDefinition = oDoc.ComponentDefinition
  If oCD.HasFlatPattern = False Then 
	oCD.Unfold
	oCD.FlatPattern.ExitEdit
  End If
Dim UoM As UnitsOfMeasure = oDoc.UnitsOfMeasure
'Add all holes (diameters) to a list
Dim oHoles As New List(Of String)
  Dim oFace As Face = oCD.FlatPattern.TopFace
  For Each oLoop As EdgeLoop In oFace.EdgeLoops
	  'Make sure the edgeloop is a circle
	  If oLoop.IsOuterEdgeLoop = False AndAlso oLoop.Edges.Count = 1 _
		  AndAlso oLoop.Edges(1).GeometryType = CurveTypeEnum.kCircleCurve
			  oHoles.Add(UoM.GetStringFromValue(oLoop.Edges(1).Geometry.Radius * 2, UoM.LengthUnits))
		  End If
Next
'Sort the list
oHoles.Sort(Function(a, b) UoM.GetValueFromExpression(a, UoM.LengthUnits).CompareTo(UoM.GetValueFromExpression(b, UoM.LengthUnits)))
'Step through the list and create properties of diameter and count.
Dim currCount As Integer = 0
For i = 0 To oHoles.Count - 1
	If i > 0 AndAlso oHoles(i) <> oHoles(i - 1)
		iProperties.Value("Custom", oHoles(i - 1)) = currCount
		MsgBox(oHoles(i - 1) & vbCrLf & "Count = " & currCount)
		currCount = 1
	Else
		currCount += 1
	End If
	If i = oHoles.Count - 1
		MsgBox(oHoles(i) & vbCrLf & "Count = " & currCount)
		iProperties.Value("Custom", oHoles(i))= currCount
	End If
Next
End If
0 Likes
Message 5 of 24

Ahmed.shawkyXTZHN
Enthusiast
Enthusiast

@JhoelForshav   thanks for your response , Yes , similar to this , but this is working great with part level , my target is to get same result from assembly level.

0 Likes
Message 6 of 24

JhoelForshav
Mentor
Mentor
Accepted solution

Hi @Ahmed.shawkyXTZHN 

Based on the first rule you posted I thought you wanted it on part level... Try running this rule in your assembly 🙂

Dim oAsm As AssemblyDocument = ThisDoc.Document
Dim oHoles As New List(Of String)
Dim UoM As UnitsOfMeasure = oAsm.UnitsOfMeasure
For Each oOcc As ComponentOccurrence In oAsm.ComponentDefinition.Occurrences
	If oOcc.DefinitionDocumentType = DocumentTypeEnum.kPartDocumentObject AndAlso oOcc.Definition.Document.SubType = "{9C464203-9BAE-11D3-8BAD-0060B0CE6BB4}" Then
		Dim oDoc As PartDocument = oOcc.Definition.Document

		Dim oCD As SheetMetalComponentDefinition = oDoc.ComponentDefinition
		If oCD.HasFlatPattern = False Then
			oCD.Unfold
			oCD.FlatPattern.ExitEdit
			oDoc.Close
			oAsm.Activate
		End If
		
		'Add all holes (diameters) to a list

		Dim oFace As Face = oCD.FlatPattern.TopFace
		For Each oLoop As EdgeLoop In oFace.EdgeLoops
			'Make sure the edgeloop is a circle
			If oLoop.IsOuterEdgeLoop = False AndAlso oLoop.Edges.Count = 1 _
				AndAlso oLoop.Edges(1).GeometryType = CurveTypeEnum.kCircleCurve
				oHoles.Add(UoM.GetStringFromValue(oLoop.Edges(1).Geometry.Radius * 2, UoM.LengthUnits))
			End If
		Next
	End If
Next
'Sort the list
oHoles.Sort(Function(a, b) UoM.GetValueFromExpression(a, UoM.LengthUnits).CompareTo(UoM.GetValueFromExpression(b, UoM.LengthUnits)))
'Step through the list and create properties of diameter and count.
Dim currCount As Integer = 0
For i = 0 To oHoles.Count - 1
	If i > 0 AndAlso oHoles(i) <> oHoles(i - 1)
		iProperties.Value("Custom", oHoles(i - 1)) = currCount
		MsgBox(oHoles(i - 1) & vbCrLf & "Count = " & currCount)
		currCount = 1
	Else
		currCount += 1
	End If
	If i = oHoles.Count - 1
		MsgBox(oHoles(i) & vbCrLf & "Count = " & currCount)
		iProperties.Value("Custom", oHoles(i)) = currCount
	End If
Next
0 Likes
Message 7 of 24

Ahmed.shawkyXTZHN
Enthusiast
Enthusiast

Thank you very much , it will help a lot😊 , I have another question similar , can we get the number of instances done by punch tool feature ?? 

for example I have sheet metal punch tool called speed nut  if we can get the same count for it ,  so we can get the punch tool name and the number of instances under this punch tool .

0 Likes
Message 8 of 24

JhoelForshav
Mentor
Mentor
Accepted solution

Hi @Ahmed.shawkyXTZHN 

I updated the rule to count punches as well as remove properties if the punch or holediameter doesn't exist in the assembly anymore. Try this 🙂

Dim oAsm As AssemblyDocument = ThisDoc.Document
Dim oHoles As New List(Of String)
Dim oPunches As New List(Of String)
Dim UoM As UnitsOfMeasure = oAsm.UnitsOfMeasure
For Each oOcc As ComponentOccurrence In oAsm.ComponentDefinition.Occurrences
	If oOcc.DefinitionDocumentType = DocumentTypeEnum.kPartDocumentObject AndAlso oOcc.Definition.Document.SubType = "{9C464203-9BAE-11D3-8BAD-0060B0CE6BB4}" Then
		Dim oDoc As PartDocument = oOcc.Definition.Document

		Dim oCD As SheetMetalComponentDefinition = oDoc.ComponentDefinition
		If oCD.HasFlatPattern = False Then
			oCD.Unfold
			oCD.FlatPattern.ExitEdit
			oDoc.Close
			oAsm.Activate
		End If

		'Add all holes (diameters) to a list

		Dim oFace As Face = oCD.FlatPattern.TopFace
		For Each oLoop As EdgeLoop In oFace.EdgeLoops
			'Make sure the edgeloop is a circle
			If oLoop.IsOuterEdgeLoop = False AndAlso oLoop.Edges.Count = 1 _
				AndAlso oLoop.Edges(1).GeometryType = CurveTypeEnum.kCircleCurve
				oHoles.Add(UoM.GetStringFromValue(oLoop.Edges(1).Geometry.Radius * 2, UoM.LengthUnits))
			End If
		Next
		For Each oPunch As PunchToolFeature In oCD.Features.PunchToolFeatures
			For i = 1 To oPunch.PunchCenterPoints.Count
				oPunches.Add(System.IO.Path.GetFileNameWithoutExtension(oPunch.iFeatureTemplateDescriptor.LastKnownSourceFileName))
			Next
		Next
	End If
Next
For Each oProp As Inventor.Property In oAsm.PropertySets("{D5CDD505-2E9C-101B-9397-08002B2CF9AE}")
	If oProp.Name.StartsWith("Hole: ") Or oProp.Name.StartsWith("Punch: ") Then oProp.Delete
Next
'Sort the list
oHoles.Sort(Function(a, b) UoM.GetValueFromExpression(a, UoM.LengthUnits).CompareTo(UoM.GetValueFromExpression(b, UoM.LengthUnits)))
'Step through the list and create properties of diameter and count.
Dim currCount As Integer = 0
For i = 0 To oHoles.Count - 1
	If i > 0 AndAlso oHoles(i) <> oHoles(i - 1)
		iProperties.Value("Custom", "Hole: " & oHoles(i - 1)) = currCount
		MsgBox(oHoles(i - 1) & vbCrLf & "Count = " & currCount)
		currCount = 1
	Else
		currCount += 1
	End If
	If i = oHoles.Count - 1
		MsgBox(oHoles(i) & vbCrLf & "Count = " & currCount)
		iProperties.Value("Custom", "Hole: " & oHoles(i)) = currCount
	End If
Next
oPunches.Sort(Function(a, b) a.CompareTo(b))
currCount = 0
For i = 0 To oPunches.Count - 1
	If i > 0 AndAlso oPunches(i) <> oPunches(i - 1)
		iProperties.Value("Custom", "Punch: " & oPunches(i - 1)) = currCount
		MsgBox(oPunches(i - 1) & vbCrLf & "Count = " & currCount)
		currCount = 1
	Else
		currCount += 1
	End If
	If i = oPunches.Count - 1
		MsgBox(oPunches(i) & vbCrLf & "Count = " & currCount)
		iProperties.Value("Custom", "Punch: " & oPunches(i)) = currCount
	End If
Next
oAsm.Update
0 Likes
Message 9 of 24

Ahmed.shawkyXTZHN
Enthusiast
Enthusiast

WoW that's Great 😉 u are master 😊 , one extra help , I tried it on one assembly it worked so fine , but when i tried it on assembly that contain non sheet metal parts it gave me error , so can we skip the non sheet metal parts so it will not make faults , sorry for bothering u. @JhoelForshav  thanks in advance .

0 Likes
Message 10 of 24

JhoelForshav
Mentor
Mentor

Hi @Ahmed.shawkyXTZHN 

That sounds odd...

The line:

If oOcc.DefinitionDocumentType = DocumentTypeEnum.kPartDocumentObject AndAlso oOcc.Definition.Document.SubType = "{9C464203-9BAE-11D3-8BAD-0060B0CE6BB4}" Then

Should make sure it skips non-sheetmetal parts...
What's the error message?

0 Likes
Message 11 of 24

Ahmed.shawkyXTZHN
Enthusiast
Enthusiast

@JhoelForshav  I changed the line  but still receiving the same error , 

before the error appear the non sheet metal part will open and this will appear :

"Unspecified error (Exception from HRESULT: 0x80004005 (E_FAIL))"

 

and this  description will be in more info :

"System.Runtime.InteropServices.COMException (0x80004005): Unspecified error (Exception from HRESULT: 0x80004005 (E_FAIL))
at System.RuntimeType.ForwardCallToInvokeMember(String memberName, BindingFlags flags, Object target, Int32[] aWrapperTypes, MessageData& msgData)
at Inventor.SheetMetalComponentDefinition.Unfold()
at ThisRule.Main()
at Autodesk.iLogic.Exec.AppDomExec.ExecRuleInAssembly(Assembly assem)
at iLogic.RuleEvalContainer.ExecRuleEval(String execRule)"

 

Thanks.

0 Likes
Message 12 of 24

JhoelForshav
Mentor
Mentor

@Ahmed.shawkyXTZHN 

I can't replicate the error. What line do you mean you changed?🤔

Non-sheetmetal parts shouldn't be affected by the code. You could try to check if the occurrence is sheetmetal by its definition instead and see if that helps:

Dim oAsm As AssemblyDocument = ThisDoc.Document
Dim oHoles As New List(Of String)
Dim oPunches As New List(Of String)
Dim UoM As UnitsOfMeasure = oAsm.UnitsOfMeasure
For Each oOcc As ComponentOccurrence In oAsm.ComponentDefinition.Occurrences
	If TypeOf (oOcc.Definition) Is SheetMetalComponentDefinition Then
		Dim oDoc As PartDocument = oOcc.Definition.Document
		Dim oCD As SheetMetalComponentDefinition = oDoc.ComponentDefinition
		If oCD.HasFlatPattern = False Then
			oCD.Unfold
			oCD.FlatPattern.ExitEdit
			oDoc.Close
			oAsm.Activate
		End If
		Dim oFace As Face = oCD.FlatPattern.TopFace
		For Each oLoop As EdgeLoop In oFace.EdgeLoops
			If oLoop.IsOuterEdgeLoop = False AndAlso oLoop.Edges.Count = 1 _
				AndAlso oLoop.Edges(1).GeometryType = CurveTypeEnum.kCircleCurve
				oHoles.Add(UoM.GetStringFromValue(oLoop.Edges(1).Geometry.Radius * 2, UoM.LengthUnits))
			End If
		Next
		For Each oPunch As PunchToolFeature In oCD.Features.PunchToolFeatures
			For i = 1 To oPunch.PunchCenterPoints.Count
				oPunches.Add(System.IO.Path.GetFileNameWithoutExtension(oPunch.iFeatureTemplateDescriptor.LastKnownSourceFileName))
			Next
		Next
	End If
Next
For Each oProp As Inventor.Property In oAsm.PropertySets("{D5CDD505-2E9C-101B-9397-08002B2CF9AE}")
	If oProp.Name.StartsWith("Hole: ") Or oProp.Name.StartsWith("Punch: ") Then oProp.Delete
Next
oHoles.Sort(Function(a, b) UoM.GetValueFromExpression(a, UoM.LengthUnits).CompareTo(UoM.GetValueFromExpression(b, UoM.LengthUnits)))
Dim currCount As Integer = 0
For i = 0 To oHoles.Count - 1
	If i > 0 AndAlso oHoles(i) <> oHoles(i - 1)
		iProperties.Value("Custom", "Hole: " & oHoles(i - 1)) = currCount
		MsgBox(oHoles(i - 1) & vbCrLf & "Count = " & currCount)
		currCount = 1
	Else
		currCount += 1
	End If
	If i = oHoles.Count - 1
		MsgBox(oHoles(i) & vbCrLf & "Count = " & currCount)
		iProperties.Value("Custom", "Hole: " & oHoles(i)) = currCount
	End If
Next
oPunches.Sort(Function(a, b) a.CompareTo(b))
currCount = 0
For i = 0 To oPunches.Count - 1
	If i > 0 AndAlso oPunches(i) <> oPunches(i - 1)
		iProperties.Value("Custom", "Punch: " & oPunches(i - 1)) = currCount
		MsgBox(oPunches(i - 1) & vbCrLf & "Count = " & currCount)
		currCount = 1
	Else
		currCount += 1
	End If
	If i = oPunches.Count - 1
		MsgBox(oPunches(i) & vbCrLf & "Count = " & currCount)
		iProperties.Value("Custom", "Punch: " & oPunches(i)) = currCount
	End If
Next
oAsm.Update
0 Likes
Message 13 of 24

Ahmed.shawkyXTZHN
Enthusiast
Enthusiast

it's working fine 👌, the issue was this particular part I put other non sheet metal parts and it is working great 👍 , thank u 😊.

  

Is it possible to link this results to reflect as a table in the drawing ??

0 Likes
Message 14 of 24

JhoelForshav
Mentor
Mentor

@Ahmed.shawkyXTZHN 

This way you don't really link the results to update dynamically, but you can use iLogic to read the properties created in the assembly and create static tables based on them.

Run this rule in your drawing after you've ran the previous rule in the assembly:

Dim oDrawing As DrawingDocument = ThisDrawing.Document
Dim oSheet As Sheet = oDrawing.ActiveSheet
Dim oHoles As New List(Of KeyValuePair(Of String, Integer))
Dim oPunches As New List(Of KeyValuePair(Of String, Integer))

Dim oAsm As AssemblyDocument = oSheet.DrawingViews(1).ReferencedDocumentDescriptor.ReferencedDocument
Dim oCustomProps As PropertySet = oAsm.PropertySets("{D5CDD505-2E9C-101B-9397-08002B2CF9AE}")
For Each oProp As Inventor.Property In oCustomProps
	If oProp.Name.StartsWith("Hole: ") Then
		oHoles.Add(New KeyValuePair(Of String, Integer)(oProp.Name.Replace("Hole: ", ""), oProp.Value))
	ElseIf oProp.Name.StartsWith("Punch: ") Then
		oPunches.Add(New KeyValuePair(Of String, Integer)(oProp.Name.Replace("Punch: ", ""), oProp.Value))
	End If
Next
Dim oHoleTable As CustomTable
Dim oPunchTable As CustomTable
Dim oTG As TransientGeometry = ThisApplication.TransientGeometry
If oHoles.Count > 0
	Dim colTitles(1) As String
	colTitles(0) = "Diameter"
	colTitles(1) = "Number"
	oHoleTable = oSheet.CustomTables.Add("Holes", oTG.CreatePoint2d(10, 10), 2, oHoles.Count, colTitles)
	oHoleTable.Layer = oSheet.Parent.StylesManager.Layers.Item("0")
	oHoleTable.Columns.Item(1).ValueHorizontalJustification = HorizontalTextAlignmentEnum.kAlignTextCenter
	For i = 1 To oHoles.Count
		oHoleTable.Rows(i).Item("Diameter").Value = oHoles(i - 1).Key
		oHoleTable.Rows(i).Item("Number").Value = oHoles(i - 1).Value
	Next
End If
If oPunches.Count > 0
	Dim colTitles(1) As String
	colTitles(0) = "Name"
	colTitles(1) = "Number"
	oPunchTable = oSheet.CustomTables.Add("Punches", oTG.CreatePoint2d(If (oHoleTable Is Nothing, 10, 10 + oHoleTable.RangeBox.MaxPoint.X - oHoleTable.RangeBox.MinPoint.X) _
	, 10), 2, oPunches.Count, colTitles)
	oPunchTable.Layer = oSheet.Parent.StylesManager.Layers.Item("0")
	oPunchTable.Columns.Item(1).ValueHorizontalJustification = HorizontalTextAlignmentEnum.kAlignTextCenter
	For i = 1 To oPunches.Count
		oPunchTable.Rows(i).Item("Name").Value = oPunches(i - 1).Key
		oPunchTable.Rows(i).Item("Number").Value = oPunches(i - 1).Value
	Next
End If
0 Likes
Message 15 of 24

Ahmed.shawkyXTZHN
Enthusiast
Enthusiast

@JhoelForshav  thanks , I will check it and gave you the feedback😊 .

 

how to link it to iproperty in the assembly first.

0 Likes
Message 16 of 24

Ahmed.shawkyXTZHN
Enthusiast
Enthusiast

@JhoelForshav  I couldn't link it assembly iproperty  instead of showing in msgbox😪

0 Likes
Message 17 of 24

Ahmed.shawkyXTZHN
Enthusiast
Enthusiast

@JhoelForshav  thanks , i found that the rule u provided is already making custom properties , 

i run the rule in the drawing but it gives me error.

 

 

" The parameter is incorrect. (Exception from HRESULT: 0x80070057 (E_INVALIDARG)) "

0 Likes
Message 18 of 24

Ahmed.shawkyXTZHN
Enthusiast
Enthusiast

Also if we can run this rule from main assembly that have assemblies , as of now it is only working with assembly that have level parts under it , if it has other assemblies it will not run.

0 Likes
Message 19 of 24

JhoelForshav
Mentor
Mentor
Accepted solution

Hi @Ahmed.shawkyXTZHN 

I gave you code to handle assemblies with subassemblies in your other thread:

https://forums.autodesk.com/t5/inventor-ilogic-api-vba-forum/holes-counting-and-reflecting-the-resul...

When it comes to the table on the drawing there's no simple way to keep the table synced with the properties. Maybe create a table as sketched symbol, but we dont really know which properties will exist beforehand so it's difficult to make that generic. You could also try to push the properties to excel and then reference the excelsheet from the table. I think this static table is your best option in this case though. 

Maybe you don't have a layer called "0" in your drawing template and that's why it didn't work. I removed that line for you in the code now:

Dim oDrawing As DrawingDocument = ThisDrawing.Document
Dim oSheet As Sheet = oDrawing.ActiveSheet
Dim oHoles As New List(Of KeyValuePair(Of String, Integer))
Dim oPunches As New List(Of KeyValuePair(Of String, Integer))

Dim oAsm As AssemblyDocument = oSheet.DrawingViews(1).ReferencedDocumentDescriptor.ReferencedDocument
Dim oCustomProps As PropertySet = oAsm.PropertySets("{D5CDD505-2E9C-101B-9397-08002B2CF9AE}")
For Each oProp As Inventor.Property In oCustomProps
	If oProp.Name.StartsWith("Hole: ") Then
		oHoles.Add(New KeyValuePair(Of String, Integer)(oProp.Name.Replace("Hole: ", ""), oProp.Value))
	ElseIf oProp.Name.StartsWith("Punch: ") Then
		oPunches.Add(New KeyValuePair(Of String, Integer)(oProp.Name.Replace("Punch: ", ""), oProp.Value))
	End If
Next
Dim oHoleTable As CustomTable
Dim oPunchTable As CustomTable
Dim oTG As TransientGeometry = ThisApplication.TransientGeometry
If oHoles.Count > 0
	Dim colTitles(1) As String
	colTitles(0) = "Diameter"
	colTitles(1) = "Number"
	oHoleTable = oSheet.CustomTables.Add("Holes", oTG.CreatePoint2d(10, 10), 2, oHoles.Count, colTitles)
	oHoleTable.Columns.Item(1).ValueHorizontalJustification = HorizontalTextAlignmentEnum.kAlignTextCenter
	For i = 1 To oHoles.Count
		oHoleTable.Rows(i).Item("Diameter").Value = oHoles(i - 1).Key
		oHoleTable.Rows(i).Item("Number").Value = oHoles(i - 1).Value
	Next
End If
If oPunches.Count > 0
	Dim colTitles(1) As String
	colTitles(0) = "Name"
	colTitles(1) = "Number"
	oPunchTable = oSheet.CustomTables.Add("Punches", oTG.CreatePoint2d(If (oHoleTable Is Nothing, 10, 10 + oHoleTable.RangeBox.MaxPoint.X - oHoleTable.RangeBox.MinPoint.X) _
	, 10), 2, oPunches.Count, colTitles)
	oPunchTable.Columns.Item(1).ValueHorizontalJustification = HorizontalTextAlignmentEnum.kAlignTextCenter
	For i = 1 To oPunches.Count
		oPunchTable.Rows(i).Item("Name").Value = oPunches(i - 1).Key
		oPunchTable.Rows(i).Item("Number").Value = oPunches(i - 1).Value
	Next
End If

Make sure the active sheets first drawing view is referencing your assembly when you run this rule. Also make sure to run the rule to populate the iproperties in your assembly before running this rule in the drawing. Then it should work. Let me know if there are any problems 🙂

0 Likes
Message 20 of 24

Ahmed.shawkyXTZHN
Enthusiast
Enthusiast

 @JhoelForshav Thanks now it is coming  in the drawing 😀 .