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
Posts: 3,055 PRO
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
0
Answers
-
@Evan_Reese
Have you tried profiling the feature? it will definitely show you where and why it is taking so long. Just a thought.0 -
I don't do a ton of coding, so I'm not sure what that means. Do you mean set up some timers for each section and see what's taking the longest? I'll play with that
0 -
I would imagine Jacob meant the FeatureScript profiler -- see the video here: https://forum.onshape.com/discussion/6102/improvements-to-onshape-march-24th-2017 and the docs here: https://cad.onshape.com/FsDoc/debugging-in-feature-studios.html#profiling-regeneration-timingsIlya Baran \ VP, Architecture and FeatureScript \ Onshape Inc0
-
Ah, I've never really known what that was! thanks for pointing it out.
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.0 -
@Evan_Reese
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.
1 -
-
@Evan_Reese You can take a look to this old post of @NeilCooke about performance in patterns and boolean features
https://forum.onshape.com/discussion/9314/faster-patterns
Un saludo,
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ún0 -
Well I tried doing each boolean one at a time with a loop and it's slightly worse, but you can also see how much better it is to use the native mirror feature a ton of times. So the profiling has helped me find what's taking so long, but I still don't understand why and my best guess seems to have been wrong. Any other ideas or pointers?

0 -
@Evan_Reese
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:Part 1 | Part 2 --------+-------- Part 3 | Part 4
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 => END1 -
Thanks, that does make sense. I've thought on it more last night and this morning and have another idea to try.0
-
Ok! I reworked it again with much better results. Here are regen times as used on a fairly complex project recently. Thanks!

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.setExternalDisambiguation(context, id, loopBody);
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?
0 -
@Evan_Reese - it's great having an industrial designer thinking about custom FS! You're solving my problems too...your FeatureScripts often precisely address element(s) of my workflow that are repetitive, error-prone, and present on most of my parts. It's only after I find one of your FSs that I realize some of the time saving opportunities there are in my workflow.
...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!
Romeo0 -
@Evan_Reese
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.1 -
@Evan_Reese
I think if you addconst bodyId is Id = topId + unstableIdComponent(i); setExternalDisambiguation(context, bodyId, loopBody);
just afterloopBody = bodies[i];, then, in the inside loop, useconst id = bodyId + j;, instead ofconst id = topId + unstableIdComponent(i) + unstableIdComponent(j);and then remove thesetExternalDisambiguationin the inner loop, it should work ok.2 -
@kevin_o_toole_1
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.0 -
Thanks! I'll give this a go.MBartlett21 said:@Evan_Reese
I think if you addconst bodyId is Id = topId + unstableIdComponent(i); setExternalDisambiguation(context, bodyId, loopBody);
just afterloopBody = bodies[i];, then, in the inside loop, useconst id = bodyId + j;, instead ofconst id = topId + unstableIdComponent(i) + unstableIdComponent(j);and then remove thesetExternalDisambiguationin the inner loop, it should work ok.0 -
Thanks, Romeo! I'm honestly either just writing the features I've always wanted, or thinking up a project that is interesting to me, marginally handy, and not too ambitious so I can learn Featurescript.romeograham said:@Evan_Reese - it's great having an industrial designer thinking about custom FS! You're solving my problems too...your FeatureScripts often precisely address element(s) of my workflow that are repetitive, error-prone, and present on most of my parts. It's only after I find one of your FSs that I realize some of the time saving opportunities there are in my workflow.
...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
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.1






