Find touching face in a multi-body part
Posted: Sat Apr 13, 2024 7:10 am
Hi, I am writing a macro to automate creation of glued self-aligning joints for 3D printed parts. User splits the part, selects a face from the split, and runs the macro, which then creates a sketch on that face, does entity offset, cuts one part, then creates another sketch, offsets from the first sketch (to provide a small clearance), and does a extrude and merge with the second part. Both features done with a small draft angle:
I had initially hoped to achieve this with a Library Feature, but couldn't find a reliable way to make it work with any kind of faces that may result after a cut, since Offset Entities is not dynamic.
So anyway, the problem in my macro is that since user selects face on the first body, macro later has to get the reference to the second body to perform the second operation. Since there might be many bodies in the model, I think the best way to find the other body is to find the touching face, which should be identical to the one user selected. Currently I implemented this by iterating through all the bodies in the model and all their faces, and finding a face that matches the area of the face user selected:
There are two problems with this approach:
1. It is woefully inefficient if there are many bodies and faces;
2. If part is simple (say a rectangle extrusion or something) and has multiple splits, macro might latch on to another (non-touching) face that has the same area.
I tried comparing face center coordinates using https://www.codestack.net/solidworks-ap ... arameters/, but apparently however SW outputs these coordinates, makes it impossible to make such comparisons. And it still requires iteration through all bodies and faces.
Is there a simpler and better solution to find a touching face? Before you suggest it - I can't have the macro do the split itself (since then it would be easy to identify both bodies), because splits might be very complicated in actual parts.
Below is the whole macro code. Also attaching a sample part. To run the macro, select one of the faces from the split (use Select Other, or hide one of the bodies), and then run.
P.S. I forgot that I can use Face2.IsCoincident to check if faces are on the same plane, but that still leaves possibility of messing up if there are multiple faces of same size and on the same plane (parallel) in the model, and still requires to do these iterations through every single face in the model.
I had initially hoped to achieve this with a Library Feature, but couldn't find a reliable way to make it work with any kind of faces that may result after a cut, since Offset Entities is not dynamic.
So anyway, the problem in my macro is that since user selects face on the first body, macro later has to get the reference to the second body to perform the second operation. Since there might be many bodies in the model, I think the best way to find the other body is to find the touching face, which should be identical to the one user selected. Currently I implemented this by iterating through all the bodies in the model and all their faces, and finding a face that matches the area of the face user selected:
Code: Select all
Dim swBodies As Variant
swBodies = swPart.GetBodies2(0, False)
Dim flag As Boolean
Dim i As Integer
For i = 0 To UBound(swBodies)
If Not swBodies(i).Name = firstBody.Name Then
Dim bodyFaces As Variant
bodyFaces = swBodies(i).GetFaces
Dim j As Integer
For j = 0 To UBound(bodyFaces)
Dim candidateFace As SldWorks.Face2
Set candidateFace = bodyFaces(j)
Dim candidateFaceArea As Double
candidateFaceArea = candidateFace.GetArea
If Round(firstFaceArea, 5) = Round(candidateFaceArea, 5) Then
Set secondFace = candidateFace
Set secondBody = candidateFace.GetBody
flag = True
End If
If flag = True Then Exit For
Next
End If
If flag = True Then Exit For
Next
1. It is woefully inefficient if there are many bodies and faces;
2. If part is simple (say a rectangle extrusion or something) and has multiple splits, macro might latch on to another (non-touching) face that has the same area.
I tried comparing face center coordinates using https://www.codestack.net/solidworks-ap ... arameters/, but apparently however SW outputs these coordinates, makes it impossible to make such comparisons. And it still requires iteration through all bodies and faces.
Is there a simpler and better solution to find a touching face? Before you suggest it - I can't have the macro do the split itself (since then it would be easy to identify both bodies), because splits might be very complicated in actual parts.
Below is the whole macro code. Also attaching a sample part. To run the macro, select one of the faces from the split (use Select Other, or hide one of the bodies), and then run.
Code: Select all
Option Explicit
Const PI = 3.14159265358979
Const offset As Double = 0.0005
Const height As Double = 0.005
Const clearance As Double = 0.0001
Const draftDeg As Double = 10
Dim swApp As SldWorks.SldWorks
Dim swModel As SldWorks.ModelDoc2
Dim swPart As SldWorks.PartDoc
Dim firstFace As SldWorks.Face2
Dim firstBody As SldWorks.Body2
Dim secondFace As SldWorks.Face2
Dim secondBody As SldWorks.Body2
Dim sketchName As String
Sub main()
Set swApp = Application.SldWorks
Set swModel = swApp.ActiveDoc
Set swPart = swModel
SetObjectReferences
DrawFirstSketchAndFeature
DrawSecondSketchAndFeature
End Sub
Sub SetObjectReferences()
Set firstFace = swModel.SelectionManager.GetSelectedObject6(1, -1)
Set firstBody = firstFace.GetBody
Dim firstFaceArea As Double
firstFaceArea = firstFace.GetArea
Dim swBodies As Variant
swBodies = swPart.GetBodies2(0, False)
Dim flag As Boolean
Dim i As Integer
For i = 0 To UBound(swBodies)
If Not swBodies(i).Name = firstBody.Name Then
Dim bodyFaces As Variant
bodyFaces = swBodies(i).GetFaces
Dim j As Integer
For j = 0 To UBound(bodyFaces)
Dim candidateFace As SldWorks.Face2
Set candidateFace = bodyFaces(j)
Dim candidateFaceArea As Double
candidateFaceArea = candidateFace.GetArea
If Round(firstFaceArea, 5) = Round(candidateFaceArea, 5) Then
Set secondFace = candidateFace
Set secondBody = candidateFace.GetBody
flag = True
End If
If flag = True Then Exit For
Next
End If
If flag = True Then Exit For
Next
swPart.ClearSelection2 True
End Sub
Sub DrawFirstSketchAndFeature()
Dim swEntity As SldWorks.Entity
Set swEntity = firstFace
swEntity.Select4 False, swModel.SelectionManager.CreateSelectData
swPart.SketchManager.InsertSketch True
swPart.SketchOffsetEntities2 -offset, False, False
sketchName = swModel.FeatureByPositionReverse(0).Name
swPart.ClearSelection2 True
swPart.Extension.SelectByID2 firstBody.Name, "SOLIDBODY", 0, 0, 0, True, 8, Nothing, 0
swPart.FeatureManager.FeatureCut4 True, False, False, 0, 0, height, 0, True, False, False, False, draftDeg * PI / 180, 0, False, False, False, False, False, True, False, True, True, False, 0, 0, False, False
swPart.ClearSelection2 True
End Sub
Sub DrawSecondSketchAndFeature()
Dim swEntity As SldWorks.Entity
Set swEntity = secondFace
swEntity.Select4 False, swModel.SelectionManager.CreateSelectData
swPart.SketchManager.InsertSketch True
swPart.Extension.SelectByID2 sketchName, "SKETCH", 0, 0, 0, False, 0, Nothing, 0
swPart.SketchOffsetEntities2 clearance, False, False
swPart.ClearSelection2 True
swPart.Extension.SelectByID2 secondBody.Name, "SOLIDBODY", 0, 0, 0, True, 8, Nothing, 0
swPart.FeatureManager.FeatureExtrusion2 True, False, False, 0, 0, height - clearance, 0, True, False, False, False, draftDeg * PI / 180, 0, False, False, False, False, True, True, False, 0, 0, False
swPart.ClearSelection2 True
End Sub