Overview of SOLIDWORKS Assembly context and usage from API
All SOLIDWORKS entities in 3D models (parts and assemblies) can be presented in 2 different contexts:
- Model context - this is the context the entity is created in. For example feature created in the part document, dimension added in the part. Solid body with the faces generated by boss-extrude feature
- Assembly context - this is the context where the models (and all their entities) are instantiated. For example the same part can be added twice into the assembly, so the elements of this part would have two different sets of pointers in the assembly which correspond to the corresponding components.
It is important to use the correct contexts when working with elements from SOLIDWORKS API. When assembly in-context editing is performed all the pointers must be provided in the assembly context.
Adding features into part in the context of the assembly
It is required to always use the pointer to active assembly document (ISldWorks::ActiveDoc) while editing or adding new features in the feature tree even if component is in editing state.
For example to insert the extruded feature into the part document from the image above which is edited in the context the IFeatureManager::FeatureExtrusion2 must be called on the IModelDoc2 which is an active assembly but not the model of the component being edited.
Dim swApp As SldWorks.SldWorks Sub main() Set swApp = Application.SldWorks Dim swAssy As SldWorks.AssemblyDoc Set swAssy = swApp.ActiveDoc If Not swAssy Is Nothing Then Dim swComp As SldWorks.Component2 swAssy.InsertNewVirtualPart Nothing, swComp swComp.Select4 False, Nothing, False swAssy.EditPart Debug.Assert swComp.GetModelDoc2() Is swAssy.GetEditTarget() 'current editing model equals to the component's model Debug.Assert Not swComp.GetModelDoc2() Is swAssy 'component's model doesn't equal to the assembly model Dim swRefPlaneFeat As SldWorks.Feature Set swRefPlaneFeat = FindStandardPlane(swComp) Dim swSketchFeat As SldWorks.Feature 'Creating circle in the context of the current editing model via the main assembly model Set swSketchFeat = CreateCircle(swRefPlaneFeat, swAssy) 'Creating extrude in the context of the current editing model via the main assembly model CreateExtrude swSketchFeat, swAssy swAssy.EditAssembly swAssy.EditRebuild Else MsgBox "Please open assembly" End If End Sub Function FindStandardPlane(comp As SldWorks.Component2) As SldWorks.Feature Dim swCompModel As SldWorks.ModelDoc2 Set swCompModel = comp.GetModelDoc2 Dim i As Integer i = 1 Dim swRefPlaneFeat As SldWorks.Feature Do Set swRefPlaneFeat = swCompModel.FeatureByPositionReverse(i) i = i + 1 Loop While swRefPlaneFeat.GetTypeName2() <> "RefPlane" 'converting the pointer of the feature into the assembly context so it can be selected in the assembly Set FindStandardPlane = comp.GetCorresponding(swRefPlaneFeat) End Function Function CreateCircle(plane As SldWorks.Feature, model As SldWorks.ModelDoc2) As SldWorks.Feature plane.Select2 False, -1 model.SketchManager.InsertSketch True model.SketchManager.AddToDB = True Set CreateCircle = model.SketchManager.ActiveSketch model.ClearSelection2 True model.SketchManager.CreateCircleByRadius 0, 0, 0, 0.01 model.SketchManager.AddToDB = False model.ClearSelection2 True model.SketchManager.InsertSketch True End Function Sub CreateExtrude(sketch As SldWorks.Feature, model As SldWorks.ModelDoc2) sketch.Select2 False, 0 model.FeatureManager.FeatureExtrusion2 True, False, False, 0, 0, 0.01, 0.01, False, False, False, False, 0, 0, False, False, False, False, True, True, True, 0, 0, False model.ClearSelection2 True End Sub
Converting the pointers
SOLIDWORKS API provides the method to convert the pointers between contexts:
- IModelDocExtension::GetCorresponding converts the pointer from the assembly context into the underlying component's model context
- IComponent2::GetCorresponding converts the pointer from the underlying model context to the assembly context for this component.
Model operations in the context of the assembly
The following test cases will demonstrate different approaches and results while working with context in assembly. Download Sample Assembly. This assembly consists of a single virtual component (this can be an external components as well). There is a 3D Sketch (3DSketch1) with a point in the component's model. For simplicity another sketch called Reference is added to the assembly which displays current point coordinate.
The purposes of the following cases is to move the point in the 3D Sketch in XYZ by 10 mm from the assembly.
Test Case 1: Moving by acquiring the pointers directly from the assembly context
When assembly is opened pointer to any object retrieved directly from the assembly or from the component will have the active assembly context.
For example:
- ISelectionMgr::GetSelectedObject6 of the object selected in the component (e.g. face or feature) will be valid in the current assembly
- IComponent2::FirstFeature returns the pointer for the first feature in the component's model in the context of the assembly.
These pointers are safe to work with within the context of this assembly. For example face colour can be changed, feature can be renamed, point coordinate can be modified.
- Open downloaded sample assembly
- Select the 3DSketch1 feature in the tree
- Run the following macro
Dim swApp As SldWorks.SldWorks Sub main() Set swApp = Application.SldWorks Dim swAssy As SldWorks.AssemblyDoc Set swAssy = swApp.ActiveDoc If Not swAssy Is Nothing Then Dim swFeat As SldWorks.Feature Set swFeat = swAssy.SelectionManager.GetSelectedObject6(1, -1) MoveSketchPoints swFeat, swAssy 'exit edit in context model swAssy.ClearSelection2 True swAssy.EditAssembly Else MsgBox "Please open assembly document" End If End Sub Sub MoveSketchPoints(sketchFeat As SldWorks.Feature, editModel As SldWorks.ModelDoc2) Dim swSketch As SldWorks.Sketch Set swSketch = sketchFeat.GetSpecificFeature2 Debug.Print "Sketch Feature Selected: " & sketchFeat.Select2(False, -1) editModel.SketchManager.Insert3DSketch True Dim vSkPts As Variant vSkPts = swSketch.GetSketchPoints2() Dim i As Integer For i = 0 To UBound(vSkPts) Dim swSkPt As SldWorks.SketchPoint Set swSkPt = vSkPts(i) swSkPt.X = swSkPt.X + 0.01 swSkPt.Y = swSkPt.Y + 0.01 swSkPt.Z = swSkPt.Z + 0.01 Next editModel.SketchManager.Insert3DSketch True End Sub
As the result sketch point is moved by 10 mm in XYZ directions.
Test Case 2: Accessing the objects from the underlying model context in the context of the assembly
It is not always possible to retrieve the pointer to the required object directly from the assembly context. If out of context object (i.e. object which was retrieved or converted to the underlying component's model) is used within the assembly context this may produce unexpected results.
Using of out of context object equivalent of invoking the APIs on the invisible model. In some cases this will produce correct behaviour, in some cases it may fail or even cause the crash.
The following example demonstrates the result of using out of context pointers by converting the context from assembly to the underlying document via IModelDocExtension::GetCorresponding
Follow the steps from previous test case and run the following macro
Dim swApp As SldWorks.SldWorks Sub main() Set swApp = Application.SldWorks Dim swAssy As SldWorks.AssemblyDoc Set swAssy = swApp.ActiveDoc If Not swAssy Is Nothing Then Dim swFeat As SldWorks.Feature Set swFeat = swAssy.SelectionManager.GetSelectedObject6(1, -1) Dim swComp As SldWorks.Component2 Set swComp = swFeat.GetComponent Dim swCorrFeat As SldWorks.Feature Dim swCompModel As SldWorks.ModelDoc2 Set swCompModel = swComp.GetModelDoc2 Set swCorrFeat = swCompModel.Extension.GetCorresponding(swFeat) Dim swCorrFeatByName As SldWorks.Feature Set swCorrFeatByName = swCompModel.FeatureByName(swFeat.Name) Debug.Print "Pointers are equal: " & (swCorrFeat Is swCorrFeatByName) MoveSketchPoints swCorrFeat, swCompModel Else MsgBox "Please open assembly document" End If End Sub Sub MoveSketchPoints(sketchFeat As SldWorks.Feature, editModel As SldWorks.ModelDoc2) Dim swSketch As SldWorks.Sketch Set swSketch = sketchFeat.GetSpecificFeature2 Debug.Print "Sketch Feature Selected: " & sketchFeat.Select2(False, -1) editModel.SketchManager.Insert3DSketch True Dim vSkPts As Variant vSkPts = swSketch.GetSketchPoints2() Dim i As Integer For i = 0 To UBound(vSkPts) Dim swSkPt As SldWorks.SketchPoint Set swSkPt = vSkPts(i) swSkPt.X = swSkPt.X + 0.01 swSkPt.Y = swSkPt.Y + 0.01 swSkPt.Z = swSkPt.Z + 0.01 Next editModel.SketchManager.Insert3DSketch True End Sub
As the result sketch points are not moved despite the output window displays the success
The reason of this behaviour caused by the fact that sketch cannot be edited if the model is not opened in its own window.
Now, open the component in its own window
Activate the assembly and rerun the macro. Now slightly different result is displayed. Component is marked as modified and needs rebuilding. If model rebuilt sketch is updated accordingly.
Test Case 3: Converting the context of objects
In many cases the initial pointer is available in the context of the underlying model. And if modifications required in the context of assembly it is required to convert the pointer via IComponent2::GetCorresponding method.
- Close all models and reopen sample assembly
- Open the part component in its own window.
- Select the 3DSketch1 in the active part document
- Run the following macro
Dim swApp As SldWorks.SldWorks Sub main() Set swApp = Application.SldWorks Dim swModel As SldWorks.ModelDoc2 Set swModel = swApp.ActiveDoc If Not swModel Is Nothing Then Dim swFeat As SldWorks.Feature Set swFeat = swModel.SelectionManager.GetSelectedObject6(1, -1) Stop 'Activate assembly and select the component Dim swAssy As SldWorks.AssemblyDoc Set swAssy = swApp.ActiveDoc Dim swComp As SldWorks.Component2 Set swComp = swAssy.SelectionManager.GetSelectedObjectsComponent4(1, -1) Dim swCompFeat As SldWorks.Feature Set swCompFeat = swComp.GetCorresponding(swFeat) Dim swCompFeatByName As SldWorks.Feature Set swCompFeatByName = swComp.FeatureByName(swFeat.Name) Debug.Print "Pointers are equal: " & (swCompFeat Is swCompFeatByName) MoveSketchPoints swCompFeat, swAssy Else MsgBox "Please open assembly document" End If End Sub Sub MoveSketchPoints(sketchFeat As SldWorks.Feature, editModel As SldWorks.ModelDoc2) Dim swSketch As SldWorks.Sketch Set swSketch = sketchFeat.GetSpecificFeature2 Debug.Print "Sketch Feature Selected: " & sketchFeat.Select2(False, -1) editModel.SketchManager.Insert3DSketch True Dim vSkPts As Variant vSkPts = swSketch.GetSketchPoints2() Dim i As Integer For i = 0 To UBound(vSkPts) Dim swSkPt As SldWorks.SketchPoint Set swSkPt = vSkPts(i) swSkPt.X = swSkPt.X + 0.01 swSkPt.Y = swSkPt.Y + 0.01 swSkPt.Z = swSkPt.Z + 0.01 Next editModel.SketchManager.Insert3DSketch True End Sub
- Macro stops execution
- Activate the assembly (you can just close the part document)
- Select the component and continue the macro
Macro will convert the context and change the coordinate so the coordinates can be successfully updated in the context of the assembly
Summary
When adding or editing features of the components in the context of the assembly call IAssemblyDoc::EditPart2/IAssemblyDoc::EditAssembly to start/finish editing the component in the context
It is not required to explicitly set the Edit In Context state to perform certain operations (for example editing the sketch points location, deleting features etc.). The behaviour matches the user interface behaviour (i.e. if it is required to call Edit Part command to perform certain operation it is required to call corresponding API as well)
Do not use the pointer of the component's underlying model (IComponent2::GetModelDoc2) to perform the operation of the current editing target component. Use the pointer to top level document (i.e. active assembly)
Avoid using the incorrect context. This may result in unexpected behaviour.
Use ::GetCorresponding functions to convert the pointer between contexts when needed