Question about temporary bodies

Programming and macros
laukejas
Posts: 209
Joined: Sun Sep 05, 2021 8:27 am
Answers: 0
x 45
x 116

Question about temporary bodies

Unread post by laukejas »

Hi, everyone, Merry Christmas. I got a question about temporary bodies. When I get a reference to Body2 in an assembly (from part type component) and call Body2.Copy2 to create a temporary body from it, where does that temporary body reside in? What is hosting it?

Since Copy2 call does not allow specifying target component for that temporary body, I thought it should be hosted by the same component where the original body is, especially because Body2.Display3 documentation also seems to imply this:
image.png
However... Bear with me here... After temporary body is created, it is out of position if the original body component and assembly origins do not match. To get it into position, you have to get Transform2 from that component and apply it to the temporary body to fix the position. This implies that the temporary body was created in the assembly coordinate system, so most likely it is hosted by the assembly itself, not the component that has the original body.

I also found that I can call Body2.Display3 and pass reference to ANY component in the assembly, even an unrelated one, and it still works and displays the temporary body. Temporary body remains visible even if I open that unrelated component document separately. Moving that component appears to move the temporary body too. This implies that the graphics of the temporary body are hosted by whatever component you pass as a parameter to Body2.Display3, but that might be just the graphics - the temporary body itself is probably hosted somewhere else. The coordinate issue implies that the temporary body is hosted by the assembly itself, but that contradicts the documentation.

I am totally confused. Can anyone please clarify how this works exactly?
User avatar
josh
Posts: 319
Joined: Thu Mar 11, 2021 1:05 pm
Answers: 17
x 23
x 541

Re: Question about temporary bodies

Unread post by josh »

I don't think it exists "in" anything. I think the Display3 wording may be a bit imprecise. I'm not entirely sure, but I think it should say "where you want to display this temporary body", not "where this temporary body exists". That's why displaying the body in the assembly shows it in assembly coordinates, and why you can make it display in whatever document or component you want. It won't actually exist "in" or really be "owned by" anything until you turn the temporary body into a feature.
laukejas
Posts: 209
Joined: Sun Sep 05, 2021 8:27 am
Answers: 0
x 45
x 116

Re: Question about temporary bodies

Unread post by laukejas »

josh wrote: Fri Dec 27, 2024 11:45 pm I don't think it exists "in" anything. I think the Display3 wording may be a bit imprecise. I'm not entirely sure, but I think it should say "where you want to display this temporary body", not "where this temporary body exists". That's why displaying the body in the assembly shows it in assembly coordinates, and why you can make it display in whatever document or component you want. It won't actually exist "in" or really be "owned by" anything until you turn the temporary body into a feature.
I can't test this theory with certainty because it is not possible to call Display3 while passing reference to a top-level assembly, it must be a component. I also suspect that temporary bodies are created in application-level. Especially because IModeler, the interface responsible for creating temporary bodies, is called from Sldworks, rather than from ModelDoc2. However, I found this post in the old forum where Artem says that a temporary body must have a container, which is whatever part is open in edit mode (EditPart2) when the body is created. But what if no part is in edit mode? Does that mean that the assembly itself is the container? Or is it like you said - there is no container at all?

I created a sample assembly and a macro for testing these things. Attaching to this post. It is an assembly with 3 components. First has it's origin matching the assembly origin, while the other 2 are moved. The third one also has the body away from the origin.
image.png
Macro code:

Code: Select all

Option Explicit

Dim swApp As SldWorks.SldWorks
Dim swAssy As AssemblyDoc

Sub main()
    Set swApp = Application.SldWorks
    Set swAssy = swApp.ActiveDoc
    
    Dim comp1 As Component2
    Dim comp2 As Component2
    Dim comp3 As Component2
    
    Set comp1 = swAssy.GetComponentByName("Comp1-1")
    Set comp2 = swAssy.GetComponentByName("Comp2-1")
    Set comp3 = swAssy.GetComponentByName("Comp3-1")
    
    Dim components As New Collection
    components.Add comp1
    components.Add comp2
    components.Add comp3
    
    Dim tempBodies As Collection
    Set tempBodies = CreateTempBodies(components)
    
    DisplayBodies comp1, tempBodies
    
    Debug.Print tempBodies(2).GetMassProperties(1000)(0)
    
    Stop
End Sub

Function CreateTempBodies(components As Collection) As Collection
    Set CreateTempBodies = New Collection
    
    Dim component As Component2
    For Each component In components
        Dim bodies As Variant
        Dim bodiesInfo As swBodyInfo_e
        bodies = component.GetBodies3(swBodyType_e.swSolidBody, bodiesInfo)
        
        Dim body As Body2
        Dim i As Integer
        For i = 0 To UBound(bodies)
            Dim tempBody As Body2
            Set tempBody = bodies(i).Copy2(False)
            
            MoveBody component, tempBody
            CreateTempBodies.Add tempBody
        Next
    Next
End Function

Sub MoveBody(component As Component2, body As Body2)
    Dim compTransform As MathTransform
    Set compTransform = component.Transform2
    
    body.ApplyTransform compTransform
End Sub

Sub DisplayBodies(component As Component2, bodies As Collection)
    Dim body As Body2
    Dim i As Integer
    For i = 1 To bodies.Count
        Set body = bodies(i)
        
        body.Display3 component, RGB(255, 0, 0), 1
    Next
End Sub

Notice that when temporary bodies are created, they have to be moved in order to appear in correct positions (overlap the original bodies). Running this macro should give this:
image.png
However, if you comment out "MoveBody component, tempBody", then the temporary bodies end up at the assembly/first component origin:
image.png
This seems to imply that they are created using assembly coordinate system - meaning, the assembly is the container.

However, if you change "DisplayBodies comp1, tempBodies" to "DisplayBodies comp2, tempBodies", meaning that the graphics are hosted by the component that has a different origin, you get this:
image.png
It almost feels as if temporary bodies really do not exist until you call Display3 on them, which truly creates them in the model space, using the coordinates of whatever component you passed into Display3. However, applying transform prior to calling Display3 still moves them, which implies the opposite - they do exist somewhere.

Also, if after running this macro, you open Comp1 (which was passed to Display3), the temporary bodies are not visible there. Which implies that temporary body graphics are still hosted by the assembly..? This is really strange.


I also tried what Artem suggested: enter Edit Component mode in any of the components before calling this macro. It seems that in this case, nothing changes, temporary bodies do not change their positions, even if the edited component has it's origin off the assembly origin.
image.png
And if you open that component document separately (or any others), temporary bodies are not visible there. So again, this seems to imply that Edit Component does not change anything.

I also added a line at the end of the main method that prints the X coordinate of the temporary body created from Comp2. This coordinate (-0,465) matches what SW Mass Properties dialog shows in the assembly, which further seems to imply that temporary body container is the assembly.

Now, the weirdest thing... If you again change into "DisplayBodies comp2, tempBodies", which makes temporary bodies appear offset... GetMassProperties still reports X coordinate as (-0,465) !!!

This seems to imply that temporary body graphics and actual position are completely detached from one another. It appears that temporary body is hosted by the assembly and works in it's coordinate system, but it's graphics must be hosted by some specific component, using it's coordinate system... And yet opening that component separately shows that temporary body graphics are not there, which would imply that these graphics are also hosted in the assembly, at least in some sense..?

Now you can see why I'm so confused :D If anyone can explain what is going on here, I'd really appreciate it...

P.S. I just realized I have mis-interpreted what Artem meant there in that post, that Edit Component only matters for CreateFeatureFromBody3, which makes sense. So please disregard my comments about running Copy2 while in component edit mode. The other oddities remain though.
Attachments
TempBodiesTest.swp
(29.5 KiB) Downloaded 176 times
TestAssy.zip
(278.26 KiB) Downloaded 171 times
User avatar
josh
Posts: 319
Joined: Thu Mar 11, 2021 1:05 pm
Answers: 17
x 23
x 541

Re: Question about temporary bodies

Unread post by josh »

Again... They do not exist "in" anything. They exist in the aether. The void. The body's entities do have absolute coordinates, or they couldn't exist at all. Applying a transform to this before displaying will move the body, of course. "Display" doesn't even make the body exist in whatever you're displaying it in. It's still temporary. "Display" means "show me what it would look like if this body did exist in _____". Also, it doesn't show up in the part when you open it by itself because you did not display it in the PART. You displayed it in a COMPONENT. Components are a different thing entirely. If you dropped two of those pyramid parts into your assembly, they would be entirely separate components. I'm pretty sure if you then got a Component2 for one of them, and told SW to show a temporary body in it, the body would only show up in one of those instances.

What is it you're ultimately trying to achieve here?
laukejas
Posts: 209
Joined: Sun Sep 05, 2021 8:27 am
Answers: 0
x 45
x 116

Re: Question about temporary bodies

Unread post by laukejas »

josh wrote: Sun Dec 29, 2024 2:12 pm Again... They do not exist "in" anything. They exist in the aether. The void. The body's entities do have absolute coordinates, or they couldn't exist at all. Applying a transform to this before displaying will move the body, of course. "Display" doesn't even make the body exist in whatever you're displaying it in. It's still temporary. "Display" means "show me what it would look like if this body did exist in _____". Also, it doesn't show up in the part when you open it by itself because you did not display it in the PART. You displayed it in a COMPONENT. Components are a different thing entirely. If you dropped two of those pyramid parts into your assembly, they would be entirely separate components. I'm pretty sure if you then got a Component2 for one of them, and told SW to show a temporary body in it, the body would only show up in one of those instances.

What is it you're ultimately trying to achieve here?
Thank you for your further explanation. I think I get it. The wording in documentation really threw me off. In addition to what you said, I found that if instead of passing Component2 reference to Display3, I pass ModelDoc2 that I got from that component (IComponent.GetModelDoc2), then the temporary bodies are visible even when that component is opened as a separate document, which makes sense.

The reason why I wanted to figure this out without any ambiguity left is because I'm working on a project where I need to do lots of spacial manipulations (position and rotation) of bodies obtained from an assembly, modify their geometry and then move to very specific positions. Previously I only worked in part environment with temporary bodies; it was pretty clear there, and I developed an assumption that temporary bodies are contained in specific document instances rather than the "aether" as you described it, so it got a bit confusing when I tried the same in assembly. What you wrote cleared it up quite well though.

Side note, interesting that nearly 100 people downloaded these sample files I attached! I wonder if they were genuinely interested in testing this out too, or just macro hoarding (I do that too sometimes) :D
laukejas
Posts: 209
Joined: Sun Sep 05, 2021 8:27 am
Answers: 0
x 45
x 116

Re: Question about temporary bodies

Unread post by laukejas »

I have another related question, can't seem to figure it out: when there are a lot of temporary bodies that need displaying (either in assembly or in a part), running Display3 individually on each of them becomes very slow, because SW seems to be regenerating graphics after each Display3 call. Is there a way to display an array of temporary bodies at once, or somehow suspend graphics rebuild before the first Display3 call and re-enable it after the last one? I've been going through documentation but can't seem to find anything.
User avatar
SPerman
Posts: 2097
Joined: Wed Mar 17, 2021 4:24 pm
Answers: 14
x 2282
x 1921
Contact:

Re: Question about temporary bodies

Unread post by SPerman »

-
I may not have gone where I intended to go, but I think I have ended up where I needed to be. -Douglas Adams
laukejas
Posts: 209
Joined: Sun Sep 05, 2021 8:27 am
Answers: 0
x 45
x 116

Re: Question about temporary bodies

Unread post by laukejas »

SPerman wrote: Tue Jan 07, 2025 8:19 am Maybe this will help:

https://www.codestack.net/solidworks-ap ... cs-update/
Aha! So the graphics suppression call was hiding in ModelView... Thank you very much, this works amazingly well. For my test part with 100 complex temporary bodies, it cut down display from 8.7 seconds to 38 milliseconds. Far better than expected!
User avatar
josh
Posts: 319
Joined: Thu Mar 11, 2021 1:05 pm
Answers: 17
x 23
x 541

Re: Question about temporary bodies

Unread post by josh »

It seems like putting SW back and forth between modeling operations and display operations takes extra time. You may want to try creating all the bodies, then displaying them all at once.

To test this, I wrote some code to generate 3000 surface body spheres of diameters from 0 to 10 in a cube space 100x100.
First I used the Modeler to generate all the bodies and added them to a collection. This took apx 11s.
Then I looped through the collection doing nothing but Display3 for each body. This took apx 8 seconds. This was without disabling graphics update!!! Graphics regeneration happened when it was done.
Total runtime a little under 20 seconds.

Then, I ran the exact same code except I set EnableGraphicsUpdate = False and ran Display3 on each body as it was created. At the end of the loop, I set EnableGraphicsUpdate = true and called GraphicsRedraw2. This time, the generate plus display loop took a little over 20s (longer than the individual loops above), plus the GraphicsRedraw2 call at the end took almost an additional 8 seconds.

Exponentially worst performance was displaying each body during creation without disabling graphics update. It began popping spheres in one at a time, regenerating graphics each time. It ran for more than five minutes, getting slower each sphere. I interrupted execution.

I’m not sure what kind of operations you can put between calls to Display3 that will make SW regen the graphics each time, but I would recommend trying to put all your Display3 calls back-to-back if possible.
laukejas
Posts: 209
Joined: Sun Sep 05, 2021 8:27 am
Answers: 0
x 45
x 116

Re: Question about temporary bodies

Unread post by laukejas »

josh wrote: Tue Jan 07, 2025 9:51 am It seems like putting SW back and forth between modeling operations and display operations takes extra time. You may want to try creating all the bodies, then displaying them all at once.

To test this, I wrote some code to generate 3000 surface body spheres of diameters from 0 to 10 in a cube space 100x100.
First I used the Modeler to generate all the bodies and added them to a collection. This took apx 11s.
Then I looped through the collection doing nothing but Display3 for each body. This took apx 8 seconds. This was without disabling graphics update!!! Graphics regeneration happened when it was done.
Total runtime a little under 20 seconds.

Then, I ran the exact same code except I set EnableGraphicsUpdate = False and ran Display3 on each body as it was created. At the end of the loop, I set EnableGraphicsUpdate = true and called GraphicsRedraw2. This time, the generate plus display loop took a little over 20s (longer than the individual loops above), plus the GraphicsRedraw2 call at the end took almost an additional 8 seconds.

Exponentially worst performance was displaying each body during creation without disabling graphics update. It began popping spheres in one at a time, regenerating graphics each time. It ran for more than five minutes, getting slower each sphere. I interrupted execution.

I’m not sure what kind of operations you can put between calls to Display3 that will make SW regen the graphics each time, but I would recommend trying to put all your Display3 calls back-to-back if possible.
Thank you very much for running this test! This is very interesting. I just realized that Display3/regen behavior differs depending on whether you run the code as a VBA macro, or a stand-alone EXE program that connects to SW (my use case is the second one). With a macro, running Display3 on an array of temporary bodies (with nothing in between) indeed results in a single graphics update after the focus is returned to SW. However, doing the same from a stand-alone app results in each body popping in one by one, taking a lot of time. However, suspending graphics update with IModelView.EnableGraphicsUpdate = false in a standalone application results in very fast performance, comparable to macro (difficult to say exactly since VBA code editor doesn't have proper debug tools to measure performance).

In my use case generating temporary bodies and displaying them are two distinct and unrelated actions that happen very far apart, so running Display3 back-to-back is very easy.

I suspect that the difference between macro and stand-alone behavior is because macros are integrated and can freeze SW, never giving a chance for it to do automatic regens, whereas stand-alone is much more detached, and SW is able to run it's own internal stuff in between API calls, including graphics regen. Which is why EnableGraphicsUpdate = false is so important here.
User avatar
josh
Posts: 319
Joined: Thu Mar 11, 2021 1:05 pm
Answers: 17
x 23
x 541

Re: Question about temporary bodies

Unread post by josh »

I don't use standalone EXEs, but I'm always up to learn something - Have you ever used CommandInProgress? I wonder if setting that to True before Display3-ing all of the bodies would suspend the graphics regen like it does for VBA macros? Might improve performance for your code in other areas too.

https://help.solidworks.com/2024/englis ... Redirect=1
Post Reply