Delete specific Group

I have a collection of boxes that belong to a layer called “Boxes”. This is the way I create every box:

        entities = model.active_entites
        model.active_layer = 'Boxes'
        gr = entities.add_group
        gr.name = "box_" + box_name
        entities = gr.entities
        # Here I define the faces of the box 

box_name is requested by a UI.inputbox. The boxes are correctly generated.

The question is, how to delete a specific group? I provide a name to the box, but I just don’t know how to have access to a group and remove it. Sorry, I’m new to the Ruby API.

Let’s assume you have a box named ‘box_123’.
Set a reference to that string, e.g.

gpname='box_123'

To find it [or all if there is more than one with that same name] use something like:

gps = model.active_entities.grep(Sketchup::Group).find_all{|g| g.name==gpname }

Now gps is an array containing nil [if no match], or one or more groups having that name.
Just to see if it works add this:

ss=model.selection
ss.clear
ss.add(gps)

To erase the group[s]

model.active_entities.erase_entities(gps) if gps[0]

Or to erase just one thing at a time - let’s say that it’s referenced as ‘group’:

group.erase!

2 Likes

That is exactly what I was looking for. It works perfectly, thanks!

I’m trying to step through the model and delete all groups named “plates”. The challenge is that these groups are nested in several components throughout the model. It looks like the code you posted only works for the active context. It doesn’t work if the group is nested inside of a component.

model=Sketchup.active_model
gpname='plates'
gps=model.active_entities.grep(Sketchup::Group).find_all{|g| g.name==gpname }
model.active_entities.erase_entities(gps) if gps[0]

Context: The model is an imported truss model. I don’t need the plates, so I’m trying to delete all the metal plates on each truss in order to speed up the model a bit. They are all in a group named “plates”.

What’s the best way to step through each component to check and delete the group “plates”?

a clue…

mod = Sketchup.active_model # Open model
defns = Sketchup.active_model.definitions
defns.each do |defn|
 p defn.name
end
1 Like
A simple solution ... if you can't figure it out from the clue ...
    def delete_truss_gussets(name = 'plates')
      dlist = Sketchup.active_model.definitions
      cdef  = dlist[name]
      if cdef && cdef.group?
        cdef.instances.each do |inst|
          inst.erase!
        end
        dlist.remove(cdef) rescue dlist.purge_unused
      end
    end
1 Like

I tried your solution, but it had no effect. Maybe it’s due to the model hierarchy. Does the Sketchup.active_model.definitions only look at components? or maybe I need to explode the main group that contains everything? I’ve attached screenshot to illustrate model hierarchy.

I, admittedly, am being lazy by asking for a solution instead of trying to figure it out myself. I appreciate your help on this :slight_smile:

EDIT: Link to model Dropbox - File Deleted

NO. This collection contains ALL definitions (ie, Component, Groups and Image definitions.)

So I added some informational statements to provide feedback in the console …

    def delete_truss_gussets(name = 'plates')
      dlist = Sketchup.active_model.definitions
      cdef  = dlist[name]
      puts "group definition \"#{name}\" : "<<cdef.inspect
      if cdef && cdef.group?
        count = cdef.instances.size
        puts "  Number of instances : #{count}"
        if count > 0
          cdef.instances.each do |inst|
            inst.erase!
          end
          dlist.remove(cdef) rescue dlist.purge_unused
        else
          puts "Nothing to remove nor purge."
        end
      else
        puts "Group definition could not be found."
      end
    end

… ran it on your model, and got the "Group definition could not be found." message.

So then went and inspected one of the trusses, and realized that the instances are named "plates" not the definitions.

This means we’ll need to add in a check to test for instance names.

Matt, that is a heavy model. It was too slow to work with on my ten year old computer, so I had to test it on one truss at first, but it does seem to work on the whole model if you give it a couple of minutes.

module GM
  module DeletePlates

    extend self
    
    def find_groups(entities)
      all_groups = []
      entities.each do |entity|
        if entity.is_a?(Sketchup::Group) || entity.is_a?(Sketchup::ComponentInstance)
          all_groups << entity
          all_groups.concat(find_groups(entity.definition.entities))
        end #if
      end # entities.each
      return all_groups
    end #find_groups

    def remove_plates
      model = Sketchup.active_model
      ents = model.entities
      model.start_operation('Delete Truss Plates', true)
      groups = find_groups(ents)
      groups.select!{|g| g.definition.group?}.select!{|g| g.name == "plates"}
      puts ("Removing  #{groups.size} plates group(s).")
      groups.each do |g|
        g.erase! unless g.deleted?
      end #groups.each
      model.commit_operation
    end #remove_plates

    this_file = __FILE__
    unless file_loaded?(this_file)
      menu = UI.menu("Plugins").add_item("Delete Plates") {self::remove_plates}
      file_loaded(this_file)
    end #unless

  end #DeletePlates  
end #GM

DeletePlates.rb (1.0 KB)

Edit: Added Undo

1 Like

Here is my final … it takes a few minutes to delete the groups inside an operation.

EDIT: Actually, made a change. debug is now a named argument.

(Note SketchUp itself is purging the unused group definitions from the Definitions collection because they no longer have any instances. We have no control over this.)

    def delete_truss_gussets(inst_name = 'plates', debug: false)
      gussets_deleted = []
      groups_deleted = 0
      model = Sketchup.active_model
      dlist = model.definitions
      puts
      puts "Begin Truss Gusset Purging"
      model.start_operation('Purge Gusset Groups',true)
        #
        dlist.each do |cdef|
          next unless cdef.group? && cdef.instances.size > 0 &&
            cdef.instances[0].name == inst_name
          papa = cdef.instances[0].parent
          if papa.name.start_with?('T') && papa.instances.size > 0 &&
            papa.instances[0].layer.name.start_with?('Trusses')
            cname = cdef.name
            puts " Processing gusset group defintion: \"#{cname}\"" if debug
            cdef.instances.each_with_index do |inst,i|
              if inst.name == inst_name
                puts "  Deleting \"#{inst_name}\" instance index #{i}" if debug
                gussets_deleted << cname if cdef.instances.size == 1
                inst.erase!
                groups_deleted += 1
              end
            end
          end
        end
        puts "Number of gusset group instances deleted: #{groups_deleted}"
        puts "Number of gusset group definitions to purge: #{gussets_deleted.size}"
        puts
        puts " ... please wait, Purging ..."
        puts
        #
      model.commit_operation
      #
      orphans = []
      dlist.each do |cdef|
        if !cdef.group? && !cdef.image? && cdef.instances.size == 0
          orphans << cdef
        end
      end
      if orphans.size > 0
        puts "Number of orphaned definitions that can be purged: #{orphans.size}"
        names = orphans.map {|cdef| cdef.name }
        puts names.inspect if debug
        choice = UI.messagebox("Purge #{orphans.size} Gusset Components ?",MB_YESNO)
        if choice == IDYES
          model.start_operation('Purge Gusset Components',true)
            #
            if dlist.respond_to?(:remove)
              orphans.each {|cdef| dlist.remove(cdef) }
            else
              dlist.purge_unused
            end
            #
          model.commit_operation
        end
      end
      puts "Done\n"
    end
1 Like

Thank you for both your help @DanRathbun & @McGordon. I got it to work!

why when i explode group, i can acces it from

Sketchup.active_model.definitions.find_all{|e| e.group?}

but i cannot erase! it after it exploded. sorry my english

Because usually:

  • the group’s definition still has some instances in use by the model entities or some other definition’s entities collection,

… or possibly

  • if the group’s definition has no more instances, but Ruby’s garbage collection has not yet run and cleaned up the group’s definition object.

Of course not, because the #erase! method only applies to group instances, not their definition object. If called upon a definition, this exception will be raised:

Error: #<TypeError: Cannot determine parent of entity>

To remove a definition (SU2018+), you use the DefinitionList#remove method …

deflist = Sketchup.active_model.definitions
deflist.remove(gdef) if gdef.valid?

Removing a definition (of any kind) will erase all of it’s instances (in any entities context.)