You can’t talk about assemblies long without talking about mating. Consequently, if we’re going to automate assembly creation then we better have a darn good strategy for automating the mating process. While I can’t say that automating mating is easy, it is definitely possible. Best of all, several options are available to us to pull it off. Before we look at those options, however, lets consider what steps are actually necessary to add mates via the API:
1. Finding the entities used in the mate
2. Selecting those entities using IEntity::Select4 or IModelDocExtension::SelectByID2
3. Creating the mate with IAssemblyDoc::AddMate3
Note that step 2 is necessary because IAssemblyDoc::AddMate3 requires that the entities be selected.
The first step is quite possibly the most difficult, or at least the most intimidating. Let’s say we need to mate two flanges together. This will require a coincident and concentric mate. Since each of those mates requires two entities, we will need to programmatically find four entities total for mating. Here’s four ways to do that.
Search for geometry/topology
If finding entities is analogous to cracking someone’s password, we might call this method the “brute force attack”. If we need to locate a face, for example, our code needs to search every single face in a component until it finds one that matches a particular geometric criteria. Considering the above example, coming up with a criterion is pretty easy: the largest cylindrical face on each component. Eyeing the flange, it isn’t obvious whether that face is the inside face or the outside face, but the great thing is that it doesn’t matter. Both are concentric about the same axis, so either one would work. Next, for the coincident mates, we need to locate the hub face that extends ever slightly past the flange. It is pretty easy to see that this face is the second largest planar face on the component, so that will be our criterion.
Pros: Doesn’t require any additional work on the part of the designer to prepare the part for mating.
Cons: Makes many assumptions about the component geometry. Our code may work fine if we keep using flanges of roughly the same proportions, but if your code needs more versatility then check out the next option.
Note that this is the method used to mate handles to a drawer front in Lesson 5.1 of our VBA course.
Search for named entities
If the first approach is not practical, an excellent alternative is to have the part designer or part automation macro name the entities used to create the mates. (Tip: To manually name an entity such as an edge or face, just right click, go to Edge/Face Properties, and specify a name. To programmatically name an entity, use IPartDoc::SetEntityName.) For example, in our flange example, the circular faces could be named “concentric” since they are used to create the concentric mate. The assembly automation macro can then traverse all edges/faces in a component until it finds the edge/face with the name “concentric”. This is done using IModelDoc2::GetEntityName.
Pros: Greater reliability during the mating process than searching geometry/topology.
Cons: Requires additional work for the part designer or the programmer who is creating the part automation macro. Moreover, existing parts will require modification before they can be used in the assembly automation process.
Note that this is the method used to mate the handle to the arm in the “99 Must Know Members of the SolidWorks API” video tutorial.
Get named reference geometry
This approach is similar to the second approach, or could be used in combination with any of the other approaches. If one or more of the mate entities could be reference geometry, then the second step of finding the mate entity can be eliminated entirely by using IModelDocExtension::SelectByID2. Consider our flange example. Inside of creating a concentric mate between the faces, center axes with known names could be used instead. So, for example, if this axis is called Axis1 then steps two and tree are accomplished in one line:
swModel.Extension.SelectByID2 "Axis1", "AXIS", 0, 0, 0, False, 0, Nothing, 0
Pros: Simpler code, greater reliability than searching geometry/topology.
Cons: More work on the part of the designer.
Get mate reference entities
This approach is similar to the second except the entities necessary for mating are found in the mate references. Extracting this data is somewhat complex, which is why I would not recommend this approach unless the assembly automation process involves a large number of existing parts with the needed entities contained in the mate references. See this example for a macro that could form the basis for mate automation using mate references.
Also note that programmatically inserting a component with mate references does not cause it to instantly “snap” into place, which happens sometimes when such a component is manually inserted and a possible entity match for the mate reference is found.
Pros: No advantage over the earlier techniques, unless mate references already exist in the part or the other techniques aren’t an option.
Cons: Complex code.
Transforms + fixing
“Wait a second… I thought we were only covering four mating techniques?” That’s because the fifth technique doesn’t involve mating but might still solve your problem. A lot of engineers mate components together not because they actually care about the mate relationships themselves but just because they need to get components in a particular position quickly so it looks in a drawing or a rendered image. If that’s the case, mates might be overkill. After all, adding and rebuilding is very performance instensive, plus mates make the assembly file MUCH larger. So why not consider this option: instead of using the cumbersome IAssemblyDoc::AddMate3 to position components, why not use transforms to move them in position and then fix them in place using IAssemblyDoc::FixComponent? Your likely answer is, “Because I don’t know how to use transforms!” Well, head on over to Lesson 5.3 and change that. You’ll end up with a macro that finishes much faster. This approach also has the advantage of not requiring you to search for entities anymore. Instead, transforming a component only requires its IComponent2 pointer, which is very easy to get using IAssemblyDoc::GetComponentByName.
Pros: Faster automation process, less bulky assembly files, faster rebuild times.
Cons: Complex code. Doesn’t actually add mates, which might be necessary.
Another issue encountered in mating automation is proper alignment. Alignment is controlled in IAssemblyDoc::AddMate3 through the AlignFromEnum argument, which gives us three options: swMateAlignALIGNED, swMateAlignANTI_ALIGNED, and swMateAlignCLOSEST. The last, as I understand it, will simply default to the easiest alignment solution depending on the current rotation of the components, although this has no value in assembly automation. Using the swMateAlignALIGNED option, then, our code to add a coincident mate between two selected planar faces looks like this:
Dim swApp As SldWorks.SldWorks
Dim swModel As SldWorks.ModelDoc2
Dim swAssy As SldWorks.AssemblyDoc
Set swApp = Application.SldWorks
Set swModel = swApp.ActiveDoc
Set swAssy = swModel
swAssy.AddMate3 swMateCOINCIDENT, swMateAlignALIGNED, False, Empty, Empty, Empty, _
Empty, Empty, Empty, Empty, Empty, False, Empty
Try running this code on two components. Did you get the alignment you wanted? If not, then you must need swMateAlignANTI_ALIGNED, so you would modify the above code. This is pretty standard procedure for programming macros that automate mating: test what works and modify the code accordingly. This procedure has two significant assumptions, however. First, it is assumes that we know the direction (e.g., +Y) of the base extrude. If this assumption is unreliable, however, then we can’t consistently use the same alignment and expect good results.
The solution, then, is to programmatically determine whether the alignment was correct. For example, let’s consider our flange example again. If IAssemblyDoc::AddMate3 executed and both mating faces were pointing in the same direction then those face normals would have the exact same values. If we wanted the X axis going through the center of the flanges, then both flanges would have normal values of <1,0,0> or <1,0,0>, whereas if our alignment was correct then one should have <1,0,0> and the other should have <1,0,0>. So what we need is code that tests the normals of those faces, and if they are identical in the X direction, flips the alignment of the coincident mate.
To get the face normal we use IFace2::Normal. However, that gives us the normal in part coordinates. We need to use transforms to convert it to assembly coordinates. Once we’ve ran a comparison showing that the X values are identical, we need to use IAssemblyDoc::EditMate2 to flip the mate alignment. If you want to see a step-by-step tutorial on mating and alignment automation then check out Lesson 5.1 of our course Automating SolidWorks With VBA. Here is a clip of that macro in action. Note that if I did not have the code in place to flip the alignment, the handle would have been upside down the second time I ran the macro.