Count the holes and semi circles.

Count the holes and semi circles.

iva.btblan
Advocate Advocate
1,547 Views
14 Replies
Message 1 of 15

Count the holes and semi circles.

iva.btblan
Advocate
Advocate

Can anyone help?

Ilogic need to count all the holes in the plate.

Ilogic doesn't count the semi circles.

Total holes 439.

See the iLogic rule.

 

IBRITO

0 Likes
Accepted solutions (1)
1,548 Views
14 Replies
Replies (14)
Message 2 of 15

Andrii_Humeniuk
Advisor
Advisor

Hi @iva.btblan . Sorry but i don't see your ilogic code. Please try my ilogic code it can count all holes.

Public Sub Main()
	Dim oInvApp As Inventor.Application = ThisApplication
	Dim oPDoc As PartDocument = TryCast(oInvApp.ActiveDocument, PartDocument)
	If oPDoc Is Nothing Then Exit Sub
	Dim oPDef As PartComponentDefinition = oPDoc.ComponentDefinition
	Dim oHoles As HoleFeatures = oPDef.Features.HoleFeatures
	If oHoles.Count = 0 Then
		If Not oPDef.SurfaceBodies.Count = 0 Then
			Dim iCount As Integer
			Dim oFace As Face
			oFace = oInvApp.CommandManager.Pick(SelectionFilterEnum.kPartFaceCylindricalFilter,
												"Select hole of face...")
			If oFace Is Nothing Then Exit Sub
			MsgBoxHoles(GetCountHoleFaces(oFace.Parent, oFace.Geometry.Radius),
						"Body " & oFace.Parent.Name)
		End If
	Else
		MsgBoxHoles(oHoles(1).HoleCenterPoints.Count, "Feature " & oHoles(1).Name)
	End If
End Sub

Private Sub MsgBoxHoles(ByVal iCount As Integer, ByVal sName As String)
	MessageBox.Show(iCount & " Holes", sName)	
End Sub

Private Function GetCountHoleFaces(ByVal oBody As SurfaceBody, ByVal dRad As Double) As Integer
	Dim iCount As Integer
	For i As Integer = 1 To oBody.Faces.Count
		Dim dFaceRad As Double
		Try : dFaceRad = oBody.Faces(i).Geometry.Radius
		Catch : Continue For : End Try
		If EqualWithinTolerance(dFaceRad, dRad, 0.001) Then iCount += 1
	Next i
	Return iCount
End Function

 

Andrii Humeniuk - CAD Coordinator, Autodesk Certified Instructor

LinkedIn | My free Inventor Addin | My Repositories

Did you find this reply helpful ? If so please use the Accept as Solution/Like.

EESignature

0 Likes
Message 3 of 15

chris
Advisor
Advisor

@Andrii_Humeniuk I tried the above code and regardless of how many holes I place, whether it's one per feature or one per sketch, or an array of holes, running the code only returns a value of (1) hole?

chris_0-1714294683075.png

chris_1-1714294719806.png

 

 

0 Likes
Message 4 of 15

Andrii_Humeniuk
Advisor
Advisor

Please try this code:

Public Sub Main()
	Dim oInvApp As Inventor.Application = ThisApplication
	Dim oPDoc As PartDocument = TryCast(oInvApp.ActiveDocument, PartDocument)
	If oPDoc Is Nothing Then Exit Sub
	Dim oPDef As PartComponentDefinition = oPDoc.ComponentDefinition
	Dim oHoles As HoleFeatures = oPDef.Features.HoleFeatures
	If oHoles.Count = 0 Then
		If Not oPDef.SurfaceBodies.Count = 0 Then
			Dim iCount As Integer
			Dim oFace As Face
			oFace = oInvApp.CommandManager.Pick(SelectionFilterEnum.kPartFaceCylindricalFilter,
												"Select hole of face...")
			If oFace Is Nothing Then Exit Sub
			MsgBoxHoles(GetCountHoleFaces(oFace.Parent, oFace.Geometry.Radius),
						"Body " & oFace.Parent.Name)
		End If
	Else
		Dim iCount As Integer
		For i As Integer = 1 To oHoles.Count
			Dim iHole As Integer = oHoles(i).HoleCenterPoints.Count
			iCount += iHole
			MsgBoxHoles(iHole, "Feature " & oHoles(i).Name)			
		Next i
		MsgBoxHoles(iCount, "Total Holes:")	
	End If
End Sub

Private Sub MsgBoxHoles(ByVal iCount As Integer, ByVal sName As String)
	MessageBox.Show(iCount & " Holes", sName)	
End Sub

Private Function GetCountHoleFaces(ByVal oBody As SurfaceBody, ByVal dRad As Double) As Integer
	Dim iCount As Integer
	For i As Integer = 1 To oBody.Faces.Count
		Dim dFaceRad As Double
		Try : dFaceRad = oBody.Faces(i).Geometry.Radius
		Catch : Continue For : End Try
		If EqualWithinTolerance(dFaceRad, dRad, 0.001) Then iCount += 1
	Next i
	Return iCount
End Function

 

Andrii Humeniuk - CAD Coordinator, Autodesk Certified Instructor

LinkedIn | My free Inventor Addin | My Repositories

Did you find this reply helpful ? If so please use the Accept as Solution/Like.

EESignature

0 Likes
Message 5 of 15

chris
Advisor
Advisor

@Andrii_Humeniuk  Here's what happened, each time I clicked the message blox I got this:

 

1 hole

1 Hole

26 Holes

28 Holes

 

I have 4 features, the first (3) make sense, but the last one with the pattern, should have shown 160?

Instead of the rule stepping through different message boxes, can it just show the total amount of holes used in the part file?

 

0 Likes
Message 6 of 15

chris
Advisor
Advisor

Here's the test file I made, it's created with 2025

0 Likes
Message 7 of 15

Andrii_Humeniuk
Advisor
Advisor

It is difficult to predict how the holes were created, so I suggest choosing a hole, and then the code will count the number of cylindrical faces of the corresponding diameter in the body.

 

Public Sub Main()
	Dim oInvApp As Inventor.Application = ThisApplication
	Dim oPDoc As PartDocument = TryCast(oInvApp.ActiveDocument, PartDocument)
	If oPDoc Is Nothing Then Exit Sub
	Dim oPDef As PartComponentDefinition = oPDoc.ComponentDefinition
	If Not oPDef.SurfaceBodies.Count = 0 Then
		Dim oFace As Face
		oFace = oInvApp.CommandManager.Pick(SelectionFilterEnum.kPartFaceCylindricalFilter,
											"Select hole of face...")
		If oFace Is Nothing Then Exit Sub
		Dim dRad As Double = oFace.Geometry.Radius
		Dim iCount As Integer = GetCountHoleFaces(oFace.Parent, dRad)
		MessageBox.Show(iCount & " Holes, Diameter - " & Round(dRad * 2 * 10, 3) & " mm",
						"Body " & oFace.Parent.Name)
	End If
End Sub

Private Function GetCountHoleFaces(ByVal oBody As SurfaceBody, ByVal dRad As Double) As Integer
	Dim iCount As Integer
	For i As Integer = 1 To oBody.Faces.Count
		Dim dFaceRad As Double
		Try : dFaceRad = oBody.Faces(i).Geometry.Radius
		Catch : Continue For : End Try
		If EqualWithinTolerance(dFaceRad, dRad, 0.001) Then iCount += 1
	Next i
	Return iCount
End Function

 

 

Andrii Humeniuk - CAD Coordinator, Autodesk Certified Instructor

LinkedIn | My free Inventor Addin | My Repositories

Did you find this reply helpful ? If so please use the Accept as Solution/Like.

EESignature

0 Likes
Message 8 of 15

iva.btblan
Advocate
Advocate

Thank you all!

The rules submitted are excellent!

Is it possible to improve this rule I'm sending?

This rule puts the result in FX.

That way I can transport it to 2d sheet.

0 Likes
Message 9 of 15

_dscholtes_
Advocate
Advocate

@Andrii_Humeniuk 

There's a incorrect "design" assumption in your code, which leads to incorrect results in certain cases: when three or more holes are partly overlapping.

  • when 3 holes are overlapping and their resulting shape looks like a triangle made of circles, the code will count three cilindrical faces.
  • when 3 holes are overlapping and the resulting shape looks like a line made of circles, the code will count four cilindrical faces, which is one more than there are actual holes.

I currently have no solution to this. It depends on @iva.btblan if this is an issue or not.

 

 

@iva.btblan 

Please find below a different approach. It checks all the edges of a user selected face and checks if they are circular shaped (of any radius). It has the same flaw as I mentioned above to @Andrii_Humeniuk. Depending on your workflow, you can replace the user selection a face with a detection of the correct face.


VBA:

 

Public Sub CountHoles()

    'Get face to count holes in
    Dim oFace As Face
    Set oFace = ThisApplication.CommandManager.Pick(kPartFacePlanarFilter, "Select perforated face (or press ESC to quit)")

    'Check if user selected a face. If not, quit
    If oFace Is Nothing Then Exit Sub

    'Declarations
    Dim oEdge As Edge
    Dim oEdgeLoop As EdgeLoop
    Dim dHoleCount As Double
        
    
    'Iterate though each edge loop
    For Each oEdgeLoop In oFace.EdgeLoops

        'Iterate through each edge
        For Each oEdge In oEdgeLoop.Edges

            'Check if edge has circular shape
            If oEdge.GeometryType = kCircleCurve Or oEdge.GeometryType = kCircularArcCurve Then
                dHoleCount = dHoleCount + 1
            End If
        Next
    Next

    'Inform user
    MsgBox "Ammount of holes: " & CStr(dHoleCount - 1), vbInformation + vbOKOnly, "Count holes"

End Sub

 

 

iLogic:

 

'Get face to count holes in
Dim oFace As Face = ThisApplication.CommandManager.Pick(kPartFacePlanarFilter, "Select perforated face (or press ESC to quit)")

'Check if user selected a face. If not, quit
If oFace Is Nothing Then Exit Sub


'Compensate for circular shaped outer contour
Dim dHoleCount As Double = - 1
    

'Iterate though each edge loop
For Each oEdgeLoop As EdgeLoop In oFace.EdgeLoops

    'Iterate through each edge
    For Each oEdge As Edge In oEdgeLoop.Edges

        'Check if edge has circular shape
        If oEdge.GeometryType = kCircleCurve Or oEdge.GeometryType = kCircularArcCurve Then
            dHoleCount = dHoleCount + 1
        End If
    Next
Next

'Inform user
MsgBox ("Ammount of holes: " & CStr(dHoleCount), vbInformation + vbOKOnly, "Count holes")

 

 

[Edit 02-05-2024] Added iLogic example code and modified VBA example (added "- 1"  in line 30).

0 Likes
Message 10 of 15

chris
Advisor
Advisor

@_dscholtes_ When I try to rule your rule, I get this message 

chris_0-1714397882754.png

 

0 Likes
Message 11 of 15

Curtis_Waguespack
Consultant
Consultant

@chris, the example appears to have been written for VBA

 

change line 1 that reads "Public Sub CountHoles()" to "Sub Main" and it will fix that error.

 

and change "Set oFace =" on line 5 to just "oFace =", as well

 

Then change this : MsgBox "Ammount of holes: " & CStr(dHoleCount), vbInformation + vbOKOnly, "Count holes"

 

To this :                    MsgBox ("Ammount of holes: " & CStr(dHoleCount), vbInformation + vbOKOnly, "Count holes")

 

 

EESignature

Message 12 of 15

chris
Advisor
Advisor

@Curtis_Waguespack That worked, thank you!

0 Likes
Message 13 of 15

Andrii_Humeniuk
Advisor
Advisor

This is a universal code that counts all cylindrical faces directed to the middle. Next, it outputs information to Logger.Info and writes the total number of holes to the parameter how_many_holes (line 25) for Mr. @iva.btblan .

Public Sub Main()
	Dim oInvApp As Inventor.Application = ThisApplication
	oTG = oInvApp.TransientGeometry
	Dim oPDoc As PartDocument = TryCast(oInvApp.ActiveDocument, PartDocument)
	If oPDoc Is Nothing Then Exit Sub
	Dim oPDef As PartComponentDefinition = oPDoc.ComponentDefinition
	If oPDef.SurfaceBodies.Count = 0 Then Exit Sub
	Dim oFaces As Faces = oPDef.SurfaceBodies(1).Faces
	Dim listInCylinders As IEnumerable(Of Face)
	listInCylinders = findCylinder(oFaces, AddressOf WhereInCylinder)
	Dim oDict As New Dictionary(Of Double, Integer)
	For Each oFace As Face In listInCylinders
		Dim dRadius As Double = oFace.Geometry.Radius * 2 * 10
		If oDict.ContainsKey(dRadius) Then
			oDict(dRadius) = oDict(dRadius) + 1
		Else
			oDict.Add(dRadius, 1)
		End If
	Next
	Dim dTotalHoles As Integer
	For i As Integer = 0 To oDict.Count - 1
		dTotalHoles += oDict.Values(i)
		Logger.Info(i+1 & ") Diameter - " & oDict.Keys(i) & ", Hole(s) - " & oDict.Values(i))
	Next i
	Try : Parameter("how_many_holes") = dTotalHoles : Catch : End Try
End Sub

Dim oTG As TransientGeometry

Public Function findCylinder(oFaces As Faces, predicate As Func(Of Face, Boolean)) As IEnumerable(Of Face)
    Return oFaces.Cast(Of Face).Where(predicate)
End Function

Public Function WhereInCylinder(ByVal oFace As Face) As Boolean
	If oFace.SurfaceType = SurfaceTypeEnum.kCylinderSurface Then
		Return InOutCylinder(oFace)
	End If
    Return False
End Function

Public Function InOutCylinder(ByVal oFace As Face) As Boolean
	Dim oCylinder As Cylinder = oFace.Geometry
	
	Dim dParams As Double() = {0.5, 0.5 }
	Dim dPoints(2) As Double
	oFace.Evaluator.GetPointAtParam(dParams, dPoints)
	
	Dim oPoint As Inventor.Point = oTG.CreatePoint(dPoints(0), dPoints(1), dPoints(2))
	
	Dim dNormals(2) As Double
	oFace.Evaluator.GetNormal(dParams, dNormals)
	
	Dim oNormal As Inventor.Vector = oTG.CreateVector(dNormals(0), dNormals(1), dNormals(2))		
	oNormal.ScaleBy(oCylinder.Radius)
	
	Dim oSamplePoint As Inventor.Point = oPoint
	oSamplePoint.TranslateBy(oNormal)
	
	Dim oAxisLine As Inventor.Line = oTG.CreateLine(oCylinder.BasePoint, oCylinder.AxisVector.AsVector())
	Dim oSampleLine As Inventor.Line = oTG.CreateLine(oSamplePoint, oCylinder.AxisVector.AsVector())
	
    Return (oSampleLine.IsColinearTo(oAxisLine))
End Function

 

Andrii Humeniuk - CAD Coordinator, Autodesk Certified Instructor

LinkedIn | My free Inventor Addin | My Repositories

Did you find this reply helpful ? If so please use the Accept as Solution/Like.

EESignature

Message 14 of 15

_dscholtes_
Advocate
Advocate

@chris wrote:

@_dscholtes_ When I try to rule your rule, I get this message 


My bad, I'm a VBA type of guy and in my enthousiasm I forgot to translate to iLogic.

 

I also forgot that the shape @iva.btblan posted has a round contour, so the hole count is off by one 😉

 

@Curtis_Waguespack 

Thanks for stepping in and providing the translation.

Message 15 of 15

iva.btblan
Advocate
Advocate
Accepted solution

Thank you all!

We carry out the tests in the company!

Total joy. Thanks!

IBRITO

0 Likes