Try this:
Option Explicit On
Option Infer Off
Imports System.Collections.Generic
Imports System.Text
Public Class ThisRule
Private setName As String = "FlatPatternAttributes"
Private attName As String = "LayerName"
Private defaultLayerName As String = "CSK"
Private tolerance As Double = 0.05 ' cm tolerance
Public Sub Main()
Dim doc As PartDocument = ThisDoc.Document
If Not TypeOf doc.ComponentDefinition Is SheetMetalComponentDefinition Then
MsgBox("This rule only works with sheet metal parts.", vbExclamation, "Error")
Return
End If
Dim comDef As SheetMetalComponentDefinition = doc.ComponentDefinition
'---------------------------------------------------------
' 1️⃣ Prompt for hole diameter (default 14 mm)
'---------------------------------------------------------
Dim inputDia As String = InputBox("Enter diameter of the small hole (mm):", "Hole Diameter", "14")
Dim targetHoleDiameter As Double
If Not Double.TryParse(inputDia, targetHoleDiameter) Then
MsgBox("Invalid input. Using default 14mm.", vbExclamation)
targetHoleDiameter = 14
End If
targetHoleDiameter = targetHoleDiameter / 10 ' convert mm to cm
'---------------------------------------------------------
' 2️⃣ Flat pattern check / silent creation
'---------------------------------------------------------
If Not comDef.HasFlatPattern Then
Try
comDef.Unfold()
Catch ex As Exception
MsgBox("Failed to create flat pattern.", vbExclamation, "Error")
Return
End Try
End If
Try
comDef.FlatPattern.Edit()
Catch
End Try
'---------------------------------------------------------
' 3️⃣ Collect circular edges
'---------------------------------------------------------
Dim allCircularEdges As List(Of Edge) = GetAllCircularEdges(doc)
If allCircularEdges.Count = 0 Then
MsgBox("No circular edges found in the flat pattern.", vbExclamation, "No Geometry Found")
comDef.FlatPattern.ExitEdit()
Return
End If
'---------------------------------------------------------
' 4️⃣ Detect countersinks
'---------------------------------------------------------
Dim smallEdges As List(Of Edge) = FindSmallEdgesByConcentricGroups(allCircularEdges, targetHoleDiameter)
If smallEdges.Count = 0 Then
MsgBox("No small holes found with diameter ~" & targetHoleDiameter * 10 & " mm.", vbExclamation)
comDef.FlatPattern.ExitEdit()
Return
End If
'---------------------------------------------------------
' 5️⃣ Assign CSK layer only to the small edges
'---------------------------------------------------------
AssignLayerAttributes(smallEdges, defaultLayerName)
'---------------------------------------------------------
' 6️⃣ Export DXF with CSK green
'---------------------------------------------------------
ExportFlatPatternDXF(comDef, defaultLayerName)
'---------------------------------------------------------
' 7️⃣ Highlight for verification
'---------------------------------------------------------
HighlightEdges(smallEdges)
ShowSummary(smallEdges.Count, defaultLayerName)
comDef.FlatPattern.ExitEdit()
End Sub
'=========================================================
' Find only the smallest edge at each concentric group
'=========================================================
Private Function FindSmallEdgesByConcentricGroups(allEdges As List(Of Edge), targetHoleDiameter As Double) As List(Of Edge)
Dim smallEdges As New List(Of Edge)
Dim edgesByCenter As Dictionary(Of String, List(Of Edge)) = GroupEdgesByCenter(allEdges)
For Each groupEdges As List(Of Edge) In edgesByCenter.Values
If groupEdges.Count < 1 Then Continue For
Dim sortedEdges As List(Of Edge) = SortEdgesByDiameter(groupEdges)
Dim smallestCirc As Circle = TryCast(sortedEdges(0).Geometry, Circle)
If smallestCirc Is Nothing Then Continue For
Dim diameter As Double = smallestCirc.Radius * 2
If Math.Abs(diameter - targetHoleDiameter) <= tolerance Then
smallEdges.Add(sortedEdges(0)) ' only the smallest edge
End If
Next
Return smallEdges
End Function
'=========================================================
' Helpers: Group / Sort / Geometry
'=========================================================
Private Function GroupEdgesByCenter(edges As List(Of Edge)) As Dictionary(Of String, List(Of Edge))
Dim dict As New Dictionary(Of String, List(Of Edge))
For Each e As Edge In edges
Dim c As Circle = TryCast(E.Geometry, Circle)
If c Is Nothing Then Continue For
Dim key As String = Math.Round(c.Center.X, 4) & "," & Math.Round(c.Center.Y, 4) & "," & Math.Round(c.Center.Z, 4)
If Not dict.ContainsKey(key) Then dict.Add(key, New List(Of Edge))
dict(key).Add(E)
Next
Return dict
End Function
Private Function SortEdgesByDiameter(edges As List(Of Edge)) As List(Of Edge)
Dim tmp As New List(Of Tuple(Of Edge, Double))
For Each e As Edge In edges
Dim c As Circle = TryCast(E.Geometry, Circle)
If c IsNot Nothing Then tmp.Add(Tuple.Create(E, c.Radius * 2))
Next
tmp.Sort(Function(a, b) a.Item2.CompareTo(b.Item2))
Dim result As New List(Of Edge)
For Each t As Tuple(Of Edge, Double) In tmp
result.Add(t.Item1)
Next
Return result
End Function
Private Function GetAllCircularEdges(doc As PartDocument) As List(Of Edge)
Dim result As New List(Of Edge)
Dim fp As FlatPattern = doc.ComponentDefinition.FlatPattern
If fp.Body Is Nothing Then Return result
For Each f As Face In fp.Body.Faces
For Each e As Edge In f.Edges
If TypeOf E.Geometry Is Circle Then result.Add(E)
Next
Next
Return result
End Function
'=========================================================
' Assign layer
'=========================================================
Private Sub AssignLayerAttributes(edges As List(Of Edge), layerName As String)
For Each e As Edge In edges
Dim aSet As AttributeSet
If E.AttributeSets.NameIsUsed(setName) Then
aSet = E.AttributeSets.Item(setName)
Else
aSet = E.AttributeSets.Add(setName)
End If
If aSet.NameIsUsed(attName) Then
aSet.Item(attName).Value = layerName
Else
aSet.Add(attName, ValueTypeEnum.kStringType, layerName)
End If
Next
End Sub
'=========================================================
' Export DXF
'=========================================================
Private Sub ExportFlatPatternDXF(comDef As SheetMetalComponentDefinition, layerName As String)
Dim sOut As String = "FLAT PATTERN DXF?AcadVersion=2004"
sOut &= "&InvisibleLayers=IV_TANGENT;IV_FEATURE_PROFILES;IV_ARC_CENTERS;IV_TOOL_CENTER;IV_TOOL_CENTER_DOWN;IV_FEATURE_PROFILES_DOWN"
sOut &= "&UnconsumedSketchesLayer=" & layerName
sOut &= "&UnconsumedSketchesLayerColor=0;255;0" ' green RGB
sOut &= "?OFILE"
Dim path As String = ThisDoc.Path
Dim name As String = ThisDoc.Document.DisplayName.Replace(".ipt", "")
Dim filename As String = path & "\" & name & ".dxf"
Try
comDef.DataIO.WriteDataToFile(sOut, filename)
Catch ex As Exception
MsgBox("DXF export failed: " & ex.Message, vbExclamation, "Error")
End Try
End Sub
'=========================================================
' Highlight edges
'=========================================================
Private Sub HighlightEdges(edges As List(Of Edge))
Dim doc As PartDocument = ThisDoc.Document
For i As Integer = doc.HighlightSets.Count To 1 Step -1
doc.HighlightSets.Item(i).Delete()
Next
If edges.Count = 0 Then Return
Dim hs As HighlightSet = doc.HighlightSets.Add()
hs.Color = ThisApplication.TransientObjects.CreateColor(0, 255, 0)
Dim col As ObjectCollection = ThisApplication.TransientObjects.CreateObjectCollection()
For Each e As Edge In edges
col.Add(E)
Next
hs.AddMultipleItems(col)
End Sub
'=========================================================
' Show summary
'=========================================================
Private Sub ShowSummary(count As Integer, layerName As String)
MsgBox(count & " holes assigned to layer '" & layerName &
"' and exported to DXF.", vbInformation, "Complete")
End Sub
End Class