Welcome to the Onshape forum! Ask questions and join in the discussions about everything Onshape.
First time visiting? Here are some places to start:- Looking for a certain topic? Check out the categories filter or use Search (upper right).
- Need support? Ask a question to our Community Support category.
- Please submit support tickets for bugs but you can request improvements in the Product Feedback category.
- Be respectful, on topic and if you see a problem, Flag it.
If you would like to contact our Community Manager personally, feel free to send a private message or an email.
Why is Multi-mirror heavier than individual mirror features?
EvanReese
Member, Mentor Posts: 2,135 ✭✭✭✭✭
I started making this feature a while ago and it got a great overhaul from @MBartlett21 that made it way more stable and concise. I noticed recently on a project using it that it had a 6 second regen time, but doing the same thing with the standard mirror feature, was a lot less. Anybody have any idea which area is causing this, and whether it can be optimized more? I love using it to keep my tree shorter and to not have to use like 8 individual mirror features, but in some cases, like the one above, the time cost is too much.
Here's a link to the feature
Here's a link to the feature
Evan Reese
0
Answers
Have you tried profiling the feature? it will definitely show you where and why it is taking so long. Just a thought.
In testing it out it seems that the opBoolean is the culprit. I was surprised by this since using the native mirror feature would execute just as many booleans, but the total time for those 12 mirrors was just 3.7 seconds against Multi-Mirror's 7.9. That got me thinking that it must have something to do with the fact that Multi-mirror's boolean sets were all of 4 bodies (since it's mirrored two ways), but the standard mirror features were each only a 2-part boolean. To confirm this, I tried using just 2 multi-mirrors with one axis each, and sure enough, the time came way down.
So, I think the thing to try is opBoolean in a for loop and only boolean pairs of bodies at once. @ilya_baran is that the path you'd take?
Thank you both for being willing to educate on something that must feel obvious to people using FS all the time.
To test the performance of Onshape's features, I find that copy-pasting the code from std into a new document and running the profiler on it works well.
IR for AS/NZS 1100
https://forum.onshape.com/discussion/9314/faster-patterns
Eduardo Magdalena C2i Change 2 improve ☑ ¿Por qué no organizamos una reunión online?
Partner de PTC - Onshape Averigua a quién conocemos en común
The reason it is still slow is because the booleans are not done in the same way as the mirror.
For instance, lets say you have the following two-way mirror:
Two mirrors (horizontal, then vertical) will do the following patterns and booleans:
Pattern 1: Part 1 => Part 2
Boolean 1: Part 1 + Part 2 => (Part 1+2)
Pattern 2: (Part 1+2) => (Part 3+4)
Boolean 2: (Part 1+2) + (Part 3+4) => END
The Multi-mirror feature
Pattern 1: Part 1 => Part 2, Part 3, Part 4
Boolean 1: Part 1 + Part 2 => (Part 1+2)
Boolean 2: (Part 1+2) + Part 3 => (Part 1+2+3)
Boolean 3: (Part 1+2+3) + Part 4 => END
IR for AS/NZS 1100
In profiling it, I found that this line (and a leftover debug) was taking up enough time to make it still slightly worse than just using standard mirror.
I got rid of it with apparently no ill effect. I don't understand what this is doing or whether I should keep it. Neither the description in the Standard nor a Google search made it clear to me. I assume @MBartlett21 put it there with good reason, but is it still important with my rewrite?
...and this (of course) doesn't even touch on the many repetitive model features / elements that are specific to my workflow and the parts that we make. When (if) I ever start making my own FS, Onshape will get even better!
Thanks @Evan_Reese, and thanks Onshape and this community!
Romeo
The journey of making subtle improvements to features is a long one!
See this discussion for why setExternalDisambiguation can be helpful:
https://forum.onshape.com/discussion/comment/64129/#Comment_64129
(EDIT: linked to correct comment in thread)
That said, I think iterating through those bodies explicitly is probably not needed in your feature in the first place. A single pattern with multiple bodies will handle disambiguation fine on its own, and I think the correct boolean behavior after a single pattern can be achieved by calling processNewBodyIfNeeded() (which mostly just calls opBoolean with targetsAndToolsNeedGrouping: true, enabling heuristics we use with standard features creating bodies, which help with performance and ensure we don't union preexisting bodies).
If you want to reuse even more code, it's possible both the pattern and the boolean can be done in a single call to applyPattern(). I'm seeing the boolean parameters of applyPattern are not documented, but reading the code, looks like the fields in booleanStepTypePredicate and booleanStepScopePredicate are handled properly.
I think if you add just after
loopBody = bodies[i];
, then, in the inside loop, useconst id = bodyId + j;
, instead ofconst id = topId + unstableIdComponent(i) + unstableIdComponent(j);
and then remove thesetExternalDisambiguation
in the inner loop, it should work ok.IR for AS/NZS 1100
Thanks so much for the detailed reply, and the breadcrumb trail of links back to other detailed replies. Thanks for taking the time to explain this stuff in so much detail. I read them all a few times! Since I've got this feature already functioning as I'd hope, I think I'll leave these kinds of optimizations for future features. I'll remember to reach for applyPattern() or processNewBodyIfNeeded() before opBoolean on the next one. I also understand the value of disambiguation at least a bit more now.
I recommend that you keep a written list of repetitive tasks unique to your workflow that are good candidates for custom features. That way if you get started you can just tick them off one at a time.