+Ok here is a rudely functional overkill for Inventor using vb.net and parallel threading. Let me know if I left any pieces out.
Private Sub OverKillSketchLines(oSketch As Sketch)
Dim booFound As Boolean
'redo and split this into groups of line segments that all have the same unit vector first.
Dim lstLinesByUnitVector As New SortedList(Of uVector, List(Of SketchLine))
For Each sl1 As SketchLine In oSketch.SketchLines
Dim uv2d As uVector = New uVector(sl1.Geometry.StartPoint.VectorTo(sl1.Geometry.EndPoint).AsUnitVector)
If lstLinesByUnitVector.ContainsKey(uv2d) = False Then
lstLinesByUnitVector.Add(uv2d, New List(Of SketchLine))
End If
lstLinesByUnitVector(uv2d).Add(sl1)
Next
Dim lstSketchLinesDelete As New List(Of SketchLine)
System.Threading.Tasks.Parallel.ForEach(Of KeyValuePair(Of uVector, List(Of SketchLine)))(lstLinesByUnitVector.AsEnumerable,
Sub(kvp)
'For Each kvp As KeyValuePair(Of uVector, List(Of SketchLine))() In lstLinesByUnitVector
Dim lstSketchLines As List(Of SketchLine) = kvp.Value
Dim colGroup As New CollinearGroups
SyncLock colGroup
For Each sl As SketchLine In lstSketchLines
colGroup.IsCollinear(sl)
Next
System.Threading.Tasks.Parallel.ForEach(Of CollinearLines)(colGroup,
Sub(cl)
SyncLock cl.SketchLines
Do
For j As Integer = cl.SketchLines.Count - 1 To 0 Step -1
Dim sl1 As SketchLine = cl.SketchLines(j)
' Dim sl1Vector As Vector2d = sl1.Geometry.StartPoint.VectorTo(sl1.Geometry.EndPoint)
booFound = False
For i As Integer = cl.SketchLines.Count - 1 To 0 Step -1
Dim sl2 As SketchLine = cl.SketchLines(i)
If sl1 Is sl2 Then Continue For
If DoLineSegmentsOverlap(sl1, sl2) = True Then
MergeLines(sl1, sl2)
booFound = True
cl.SketchLines.Remove(sl2)
lstSketchLinesDelete.Add(sl2)
Exit For 'exit both loops and restart, because we changed the underlying list by deleting a sketch line
End If
Next
If booFound Then Exit For 'exit both loops and restart, because we changed the underlying list by deleting a sketch line
Next
Loop Until booFound = False
End SyncLock
End Sub)
End SyncLock
'Next
End Sub)
For Each sl As SketchLine In lstSketchLinesDelete
If sl IsNot Nothing Then sl.Delete()
Next
End Sub
Private Sub MergeLines(ByRef sl1 As SketchLine, ByVal sl2 As SketchLine)
Dim points As New List(Of Point2d)
points.Add(sl1.StartSketchPoint.Geometry)
points.Add(sl1.EndSketchPoint.Geometry)
points.Add(sl2.StartSketchPoint.Geometry)
points.Add(sl2.EndSketchPoint.Geometry)
points.Sort(Function(x, y)
Dim comp As Integer = x.X.CompareTo(y.X)
If comp = 0 Then
comp = x.Y.CompareTo(y.Y)
End If
Return comp
End Function)
sl1.Reference = False 'break reference to sl1 first.
sl1.StartSketchPoint.Geometry.X = points(0).X
sl1.StartSketchPoint.Geometry.Y = points(0).Y
sl1.EndSketchPoint.Geometry.X = points(3).X
sl1.EndSketchPoint.Geometry.Y = points(3).Y
End Sub
Public Function DoLineSegmentsOverlap(sl1 As SketchLine, sl2 As SketchLine, Optional sl1Vector As Vector2d = Nothing) As Boolean
' If sl1Vector Is Nothing Then
' sl1Vector = sl1.Geometry.StartPoint.VectorTo(sl1.Geometry.EndPoint)
' End If
' Dim sl2Vector As Vector2d = sl2.Geometry.StartPoint.VectorTo(sl2.Geometry.EndPoint)
'If sl1Vector.IsParallelTo(sl2Vector, 4) Then ' IsParallel(sl1Vector, sl2Vector) Then
If IsPointOnLineSegment_Distance(sl1.StartSketchPoint.Geometry3d, sl1.EndSketchPoint.Geometry3d, sl2.StartSketchPoint.Geometry3d) Then
'merge these two lines
Return True
ElseIf IsPointOnLineSegment_Distance(sl1.StartSketchPoint.Geometry3d, sl1.EndSketchPoint.Geometry3d, sl2.EndSketchPoint.Geometry3d) Then
'merge these two lines
Return True
End If
'End If
Return False
End Function
End Class
Public Class uVector
Implements IComparable
Dim invVec As UnitVector2d
Public Sub New(vec As Inventor.UnitVector2d)
invVec = vec
End Sub
Public Function CompareTo(obj As Object) As Integer Implements IComparable.CompareTo
If invVec Is Nothing AndAlso obj Is Nothing Then Return 0
If invVec IsNot Nothing AndAlso obj Is Nothing Then Return 1
If obj IsNot Nothing AndAlso invVec Is Nothing Then Return -1
Dim comp As Integer = 0
If TypeOf obj Is uVector Then
Dim objVec As uVector = obj
comp = Math.Round(invVec.X, 6).CompareTo(Math.Round(objVec.X, 6))
If comp = 0 Then
comp = Math.Round(invVec.Y, 6).CompareTo(Math.Round(objVec.Y, 6))
'If comp = 0 Then
'comp = Math.Round(invVec.Z, 6).CompareTo(Math.Round(objVec.Z, 6))
'End If
End If
End If
Return comp
End Function
Public Property X As Double
Get
Return invVec.X
End Get
Set(value As Double)
invVec.X = value
End Set
End Property
Public Property Y As Double
Get
Return invVec.Y
End Get
Set(value As Double)
invVec.Y = value
End Set
End Property
Public Property Z As Double
Get
Return invVec.Z
End Get
Set(value As Double)
invVec.Z = value
End Set
End Property
Public ReadOnly Property Length As Double
Get
Return invVec.Length
End Get
End Property
Public Overrides Function Equals(obj As Object) As Boolean
If invVec Is Nothing AndAlso obj Is Nothing Then Return True
If invVec IsNot Nothing AndAlso obj Is Nothing Then Return False
If invVec Is Nothing AndAlso obj IsNot Nothing Then Return False
If TypeOf obj Is uVector Then
Dim intRound As Integer = 6
Dim uVec As uVector = obj
If Math.Round(uVec.X, intRound) = Math.Round(invVec.X, intRound) AndAlso Math.Round(uVec.Y, intRound) = Math.Round(invVec.Y, intRound) AndAlso Math.Round(uVec.Z, intRound) = Math.Round(invVec.Z, intRound) Then
Return True
End If
End If
Return False
End Function
End Class
Public Class CollinearLines
Public Property SketchLines As List(Of SketchLine)
Public Sub New()
SketchLines = New List(Of SketchLine)
End Sub
Public Function IsCollinear(slTest As SketchLine)
If SketchLines.Count > 0 Then
If AreaOfTriangle(SketchLines(0).Geometry.StartPoint, SketchLines(0).Geometry.EndPoint, slTest.Geometry.StartPoint) = 0 Then
If AreaOfTriangle(SketchLines(0).Geometry.StartPoint, SketchLines(0).Geometry.EndPoint, slTest.Geometry.EndPoint) = 0 Then
SketchLines.Add(slTest)
Return True
End If
End If
Else
SketchLines.Add(slTest)
Return True
End If
Return False
End Function
End Class
Public Class CollinearGroups
Inherits List(Of CollinearLines)
Public Sub IsCollinear(slTest As SketchLine)
'look for line in collection, if found, automatically add line and end sub
For Each cl As CollinearLines In Me
If cl.IsCollinear(slTest) = True Then
Exit Sub
End If
Next
'if not found add a new collection
Dim clNew As New CollinearLines
Me.Add(clNew)
clNew.IsCollinear(slTest)
End Sub
End Class
Public Function IsPointOnLineSegment_Distance(pStart As Point, pEnd As Point, pTest As Point, Optional tol As Integer = 6) As Boolean
If Math.Round(pStart.DistanceTo(pTest), tol) + Math.Round(pEnd.DistanceTo(pTest), tol) = Math.Round(pStart.DistanceTo(pEnd), tol) Then
Return True
End If
Return False
End Function
I use 6 decimal rounding, because in my experience Inventor gets goofy at 8, and we only really ever use 4 in our designs.
Also feel free to hurt my ego and make this run better, faster, and more efficient, just post the result here for prosperity, as I did. This overkill's line entities only at this time. My test reduced a 360+ count of sketchLines to 80+ items (projected from only 60+ faces). The end result still left some overlapping lines. Might be due to rounding errors. A similar process could be created to detect other overlapping types such as arc and ellipses. Also, it is not a fast process, it takes my Xeon E-2186G 6 core with 32gb ram and NVIDIA P5000 combo a minute or two to fully process (used divide and conquer, and parallel computing really helps).
Note to multithreaded/tasking/parallel developers (so for everyone today) if attempting to make parallel computing work with Inventor, be sure to SyncLock any collections of Inventor's, such as sketch, sketch lines etc; in addition to your own collections if you are going to write-to them. Think of SyncLock as a way to make all the threads wait in line to modify the source (place it outside of the loop). Adding is can be the same problem as subtraction, also remember adding that fails = subtraction to back out. Use Parallel.ForEach if your list is not going to change, otherwise collect items to delete, and remove them after the parallel processing has stopped. Common errors are Inventor completely crashes (boom! always good for a laugh!) stating 'memory is in inconsistent state' - solved with SyncLock on sketch object (used when adding sketch entities, not shown here), and a for each loop failing because collection has changed (even though I immediately exit loop after changing collection, and the loop is not a parallel task, but it resides in a parallel task)- solved with looping with index (in reverse as necessary) instead of with foreach.
Jamie Johnson : Owner / Sisu Lissom, LLC https://sisulissom.com/