Question about temporary bodies
Question about temporary bodies
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:
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?
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:
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?
Re: Question about temporary bodies
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.
Re: Question about temporary bodies
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?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 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.
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
However, if you comment out "MoveBody component, tempBody", then the temporary bodies end up at the assembly/first component origin:
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:
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.
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 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
Re: Question about temporary bodies
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?
What is it you're ultimately trying to achieve here?
Re: Question about temporary bodies
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.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?
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)
Re: Question about temporary bodies
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.
Re: Question about temporary bodies
-
I may not have gone where I intended to go, but I think I have ended up where I needed to be. -Douglas Adams
I may not have gone where I intended to go, but I think I have ended up where I needed to be. -Douglas Adams
Re: Question about temporary bodies
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!SPerman wrote: ↑Tue Jan 07, 2025 8:19 am Maybe this will help:
https://www.codestack.net/solidworks-ap ... cs-update/
Re: Question about temporary bodies
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.
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.
Re: Question about temporary bodies
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).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.
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.
Re: Question about temporary bodies
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
https://help.solidworks.com/2024/englis ... Redirect=1