Every 3D model is built up from vertices (points), edges and faces. In the SOLIDWORKS API, we name these objects Entities. They all implement the IEntity interface because they share common properties and methods.
This is the complete list of all interfaces that implement IEntity:
I think these five objects are the building blocks of geometry:
I don’t fully understand why loops and features are in the list of entities yet. And because the SOLIDWORKS API docs never explain what an object is, just what it does, we’ll have to figure that out ourselves. This is how I understand it now:
I haven’t used ILoop2 in my six years of SOLIDWORKS programming, so you probably won’t need them unless you are creating your own geometry. But from what I have read, SOLIDWORKS creates loops from a list of edges and/or vertices. Even one vertex can make up a loop.
So they create loops from edges and vertices, then create faces from these loops. Every face has at least one loop, but it can have more than one. A face with two holes in it has three loops, one being the outer loop.
I have only looked at features as the items in the feature tree. But I think features are included in the list of entities because a feature might create a bunch of faces. An extruded circle creates three faces, for example. And when you call IFeature.GetFaces on a draft feature, SOLIDWORKS returns an empty array because a draft feature creates no new faces.
According to the SOLIDWORKS Object Model PDF, that you can download here, IFeature doesn’t even implement IEntity. But I think that is a mistake in the docs.
Because all the interfaces above implement IEntity, you can cast (aka convert) the detailed object back to an entity to make use of IEntity properties and methods (aka members). In VBA:
dim swFace as Face2
set swFace = something 'Get the face from somewhere
dim swEntity as Entity
set swEntity = swFace 'This is called casting the face to an entity. This works because IFace2 implements IEntity
dim selected as Boolean
selected = swEntity.Select4(false, Nothing) 'This works in VBA and C#
'Alternative method: call the Entity method directly
selected = swFace.Select4(false, Nothing) 'This works in VBA, although it does not compile. It also doesn't compile in C# because IFace2 has no Select4 method.
In C#, you have to make explicit casts when casting to and from entities:
IEntity entity = x; //get an entity from somewhere
var face = (Face2) entity; // cast an entity to a face
var entity2 = (IEntity) face; // cast a face to an entity
var entity3 = face as IEntity; // also works
Normally, when working in C#, you can cast implicitly when a type implements an interface. But the SOLIDWORKS API is different, and they talk about it here. I still don’t fully understand their explanation because they are talking about three programming languages in one post. My main takeaway is that SOLIDWORKS isn’t written in C# and inheritance works differently in C++ (I think it’s written in C++, at least). That is also why we have to use Interop (interoperability) DLLs to talk to SOLIDWORKS.
All selectable objects in the SOLIDWORKS API have a Persistent Reference ID. I call them Persistent IDs for short. I explain them in detail in Persistent ID, sketch segment ID in the SOLIDWORKS API and I keep a list of all available ID types in All identifiers and IDs in the SOLIDWORKS API.
Names of features, faces and edges are great, but users can often change them. So we need an ID that stays the same, that is persistent. That’s when the Persistent ID comes into play. It consists of an array of bytes (so numbers of zero to 255) with a length of 16 (sometimes), 20 (often) or way more, like 491 bytes (occasionally). An example:
You can store the persistent ID in a variable so that you can retrieve that object again at a later time. You can’t trust it 100%, though. To quote myself from my blog post about IDs:
Each ID value is unique within a model and it generally stays the same, even across SOLIDWORKS sessions. There is a remark in the docs, though, that it can change with rebuilds, but I don’t remember that actually becoming a problem in my software.
For a complete list of ways to access an entity, check out the Accessors list on the IEntity page.
If you don’t understand entities, you’re going to have a hard time selecting them. Because IFeature is the only interface that has its own Select2 method.
For all other entity types, you need to cast the object to an entity, then call IEntity.Select4. You can pass null as an argument for the SelectData when you are doing simple selection work. If you want to set a mark, you need to pass a SelectData object.
An entity might not exist after a rebuild, as it is transient, short-lived. Just as a persistent ID may not always survive a rebuild.
Safe Entities do survive, though. So if you have an entity, need to call a rebuild and want to use that entity again, you need to get a safe entity via IEntity.GetSafeEntity. This returns a new entity object that will remain valid until you delete all pointers/references to the object. A safe entity does not persist between SOLIDWORKS sessions, though.
You can attach data to any entity, and we do that via attributes. Attributes are features, so they appear in the feature tree unless you explicitly hide them. They have a name and can even be suppressed.
Attributes can be added to:
We add an attribute to the active model in our drawing automation add-in Drew to store two strings with extra data.
You can add multiple Parameters to an attribute, and a parameter can be any of the following parameter types:
Only basic variable types, essentially. If you create a double, you can even set a default value. There are some weird quirks, though, like not being able to store a negative integer value.
Attributes are special objects, it seems. So, to create an attribute, you need to jump through some hoops:
Because attributes are features, you can retrieve them in similar ways:
If you already have an entity object, you can call IEntity.FindAttribute directly. A few caveats, though:
You have to understand the scope of entities. Because you cannot just get an entity from a part, then try to use it again while the part is in an assembly. That entity does not exist there.
Models are basically documents, files. A model can be a part, assembly or drawing document and it is represented by IModelDoc2. These models can create geometry from scratch:
But once you add a part to an assembly, we call it a component and the API represents it as IComponent2. You can access the underlying model via IComponent2.GetModelDoc2. Be careful, though, because this returns null when the component is suppressed or when it is loaded as lightweight. So if you need access to all models in an assembly, you first need to call IAssemblyDoc.ResolveAllLightweightComponents.
The assembly itself is called the root component and the other components are its children. Each child can have its own children. This structure creates the tree of parts and (sub)assemblies that you see in the feature tree.
Since you can have multiple instances of the same part, each component has its own geometry and its own entities. Because an assembly-level hole should not appear in every part instance.
Since drawings are secretly assemblies, every view creates its own instance of the model you are showing. So that creates even more geometry. To bridge the gap between assemblies and drawings, the SOLIDWORKS API has the IDrawingComponent interface. You can get the visible drawing components in a view with IView.GetVisibleDrawingComponents and you can get the underlying Component2 object via IDrawingComponent.Component.
Unless you are doing fancy stuff with drawings, you will not need drawing components. Even in Drew, I hardly use them. I had been making add-ins for years before I discovered them 😄
This all leads up to an important conclusion: an entity is only valid in a certain context. A part entity only works within that part and an assembly entity only works within that assembly.
If you let a user select a part face in an assembly, you cannot use that entity directly to select a face when you have the part open. But you can convert them! I’ll explain that now.
Say you create a part and you want to use reference a face when this part is used in an assembly. You select a face and get the selected object, you don’t need to use the underlying entity. This all happens in the Model Context.
Now switch to an assembly that contains this part. We’re now working in the Assembly Context. To request the same face, you call IComponent2.GetCorresponding2 on the assembly component and pass the part’s face as an argument. This method returns a new face that belongs to the assembly context, or null if the input was incorrect. You can test it by calling the Select4 method because that method only selects the face if the context is correct.
This method works on any object with a persistent ID, by the way, so not just entities.
If you have a face that belongs to a component and you want to get the face that belongs to the underlying part, you need to call IModelDocExtension.GetCorresponding on the part’s model extension and pass the component face as an argument. You have now gone from the assembly context to the model context.
This method also lets you convert a face in a drawing view to a part face.
If you have a face that belongs to a part and you want to use it in a drawing view, you call IView.GetCorresponding and pass the part face as an argument.
To learn more about these contexts, CodeStack also has a blog post about assembly context with a few API examples.