ComponentInstance.explode
-
In an array of 4 component instances from one definition, the following snippet:
entities.each do |ent| if ent.is_a? Sketchup;;ComponentInstance ent.explode end end
explodes 2 of the 4 instances. However the next snippet will produce 4 exploded instances.
ci_ent=[] entities.each do |ent| if ent.is_a? Sketchup;;ComponentInstance ci_ent.push ent end end ci_ent.each do |ci| ci.explode end
Can anyone tell me why the first snippet doesn't work?
-
What happens is that you are running
.each
on the active (and very volatile) entity collection. That is ok, but when you explode the components, SketchUp is adding entities to the entitiy collection - while you are trying to iterate over the whole thing with the.each
method. SU does not keep track of what entities have been processed. My guess is that.each
processes the entities collection as a list and does not notice that the exploding might have jumbled the order of the list, and certain entities (like those 2 component instances) got moved around in the list to where they get skipped over.Try running
.each
on an array of the entities collection like this:entities.to_a.each do |ent|
or perhaps easier to read, but approsimately identical in practice:
ent_array = etities.to_a ent_array.each do |ent|
That takes the entities collection BEFORE anything is changed in the list of entities, turns it into an array (TIG has called it a "snapshot" of the entities collection before). But that array remains stable and orderly while the actual entities collection itself is getting jumbled up with new entities being added to it due to the exploding.
This is also why your 2nd example works. It iterates through the entities collection and makes an array of what to explode - it does not change do anything (like explode) that would mess up the oreder of the entities collection. Then once it's done iterating, it explodes those items.
Hope that helps,
Chris
-
Chris, I now recall discussions on the forum about changing entities. This is the first time its happened to me, thanks for the reminder.
-
To recap:
Never iterate through anentities
collection that you are changing - because the collection changes as you go through it and then weirdness happens.
Instead you should iterateentities.to_a
as that is a 'snap-shot' of the entities collection at the moment you make that array.
Another point is that if you are doing something like 'erase' inside the iteration use a test to see that the entitiy hasn't already gone -e.erase! if e.valid?
- for example if you erase an 'edge' then its 'face' will go too, so later when you get to that 'face' in the array it will raise an error and stop the code dead if you try to simplye.erase!
it because it's already gone !!! Another way is at the start of the iteration addnext if not e.valid?
so that entity is ignored. -
Thanks, gotit. Hope I don't forget!-)
Advertisement