SU terminate during group explode

Dear Friends,
Attached you can find SU file. Inside we have a group named Rail and have some subgroups. We wish to explode all subgroups. When I run the following codes SU terminates. When I try to explode subgroups by SU, SU terminates again!!! When I delete the first 2 subgroups, code and SU work well. Do you have any idea why it happens? Your help will be highly appreciated. Also, please let me know if you don’t have this problem.

grp1 = nil
Sketchup.active_model.active_entities.grep(Sketchup::Group) do |g|
  grp1 = g if g.name == "Rail"
end
grp1.entities.grep(Sketchup::Group) do |g|
  g.explode
end

Untitled.skp (5.1 MB)

Your code does not violate the rule that you should not delete members from a collection whilst iterating that collection.

Ie, we normally use Enumerable#to_a to make an Array copy of the collection if a loop will be deleting members from the collection.

In your case Sketchup::Group#explode will cause the destruction of the members of the Sketchup::Entities collection, which is effectively the same as deletion.

But your code is using Enumerable#grep which is creating a separate array, so this should not be the cause of the application crash.


Are you wrapping this exploding code in an undo operation ?

model = Sketchup.active_model
ents = model.active_entities
grp1 = ents.grep(Sketchup::Group).find { |g| g.name == "Rail" }
if grp1 # nil if not found by #find
  subgrps = grp1.entities.grep(Sketchup::Group)
  if !subgrps.empty?
    model.start_operation("Explode Nested Groups",true)
      subgrps.each { |g| g.explode }
    model.commit_operation
  end
end

EDIT: Testing your model (SU2021) with the code I just posted (with the top level model as the active entities context,) causes SketchUp to go into “Not Responding” mode. This indicates it is trying to do a bunch of work. And then it indeed crashes silently. Likely a memory stack overflow. (I’ll check for a WER file.)

ADD: No I do not find a Windows Error Reporting report for this crash, which is troubling.

@majid866 please open an API crash issue in the official issue tracker at GitHub.
(And do not forget to attach the test file to the issue.)

Even without using any code it indeed crashes. I mean if you using the UI to manually explode the groups inside “Rail”, that will hang silently too.

2 Likes

Hmm. Working via the GUI on my Mac, I am getting long stalls, but not experiencing crashes.

There is a lot of very small smoothed geometry in the model, especially in the details of the posts:

There are also places where one part passes inside another without having the intersections generated in the model:

My theory is that when the groups are exploded, these issues force SketchUp to do a tremendous amount of analysis to find where the now loose edges and faces intersect, and to clean up the small edges that result. This is both taking a long time and causing either a stack overflow, an excess of some implicit limitation in SketchUp (e.g. we’ve seen implications that there is a limit of 10,000 edges in some operations), or hitting some other limit. My experience is that when SketchUp vaporizes without a BugSplat, it is usually because the code itself called an abort due to trapping an error from which it can’t recover.

I know it isn’t what you were asking, but I would also note that the model is poorly constructed. The main group within Rails (the posts, railings, and all but the circles) contains a lot of repeated structures that would benefit from being nested components instead of all loose edges and faces. Then there are something like 33 other nested groups that likewise repeat the same structure for each set of circles.

2 Likes

Thank you for your theory. It is a good point to start. When I run Dan’s code, I check my PC CPU, GPU, and memory usage, it was 23%, 0%, and 31%. Then I started to delete groups one by one. When I kept 3 biggest groups I received the following alert.

You can see a face in the following picture, I push-pull it, rotate the upper face, and repeat it. In this way, I made a beautiful volume. For sure I could use a box instead of this volume but I didn’t do anything wrong to create it.

I deleted parts that pass. SU terminated the same as before. I can have intersection lines but I doubt it is my problem.

I agree you. Drawing such a complex rail by code that can make the right rail in any condition and any size is not an easy job and need many times reviewing. You give me some ideas and I will do some changes to the codes. SU problem exists and limits us to have more complex parts.

Your codes are so rich and always teach us something valuable. Would you please let me know why you used “model.start_operation”?

More precisely:

model.start_operation("Explode Nested Groups",true)
                                                ^

I guess, the the key question here is the second parameter of #start_operation method :

  • disable_ui (Boolean) (defaults to: false)

if set to true, then SketchUp’s tendency to update the user interface after each geometry change will be suppressed. This can result in much faster Ruby code execution if the operation involves updating the model in any way.

2 Likes

… Yes what Dezmo said, but more fundamentally outside an operation the undo stack will have individual entries for every little bitty geometric change.

1 Like

I check it. Not important your poles are groups or components. You cannot explode them. As I understood also the performance of your PC is not important. I think SU has limitations for group size. I.E. we cannot have 20 of such poles in one group not important how you make poles.

In this case he uses .grep with a block, so there is not intermediate array created. It’s yielding as it iterates.

To use grep with a loop that mutates the collection one would have to use:

grp1.entities.grep(Sketchup::Group).to_a.each do |g|
  g.explode
end
2 Likes

Actually, my .to_a might be redundant;

grp1.entities.grep(Sketchup::Group).each do |g|
  g.explode
end

That .each invocation should be on the returned Array. I’ve been bitten the by the subtlety of entities.grep(Sketchup::Group).each and entities.grep(Sketchup::Group) {} a few times…

Thank you for the information.

I agree because the C always returns the array …

               static VALUE
enum_grep(VALUE obj, VALUE pat)
{
    VALUE ary = rb_ary_new();
    struct MEMO *memo = MEMO_NEW(pat, ary, Qtrue);

    rb_block_call(obj, id_each, 0, 0, rb_block_given_p() ? grep_iter_i : grep_i, (VALUE)memo);

    return ary;
}

Yes I see now that the iteration is weirdly done against the whole enumerable obj whilst (I think) doing a comparison against a temporary struct, rather than against the ary object.

I again agree #each is a safer bet, ensuring the copy is made before the iteration.


I’ve opened a new issue to explore the possible benefits of a batch explode method:

1 Like