I use this in Sketchup 7, and it's very quick. In 2015. Painfully slow. Why so slow?

I use this in Sketchup 7, and it’s very quick. I use the same plugin in Sketchup 2015, and it’s painfully slow. Any Ideas? Remove Materials Mine.rb (928 Bytes)

What is it for? Why do you use it? You can purge materials that you do not use.

Yes, your correct. But this adds a toolbar item and icon, and then the script selects all, removes all materials from the front and back faces, and then purges all the materials from the model. I do this a lot, so I made this. In Sketchup 7 it’s almost instant, but in Sketchup 2015, the script can take a couple of minutes to work.

toolbar = UI::Toolbar.new “Remove All Mats”

cmd = UI::Command.new(“Remove All Mats”) {

model = Sketchup.active_model
model.selection.add( model.active_entities.to_a )

model.entities.each { |e|
  e.material = nil if e.respond_to?( :material )
  e.back_material = nil if e.respond_to?( :back_material )
}
model.definitions.each { |d|
  next if d.image?
  d.entities.each { |e|
    e.material = nil if e.respond_to?( :material )
    e.back_material = nil if e.respond_to?( :back_material )
  }
}

len=model.materials.length.to_s

model.materials.purge_unused
puts "Materials “+len+” >>> "+model.materials.length.to_s

}

cmd.small_icon = “No Mats.png”
cmd.large_icon = “No Mats.png”
cmd.tooltip = “Remove All Mats”
cmd.status_bar_text = “Removing All Materials”
cmd.menu_text = “Remove All Mats”
toolbar = toolbar.add_item cmd
toolbar.show

as this is your own code I move this to the Ruby forum…

you have poor structure and a couple of un-needed lines…

# you shouldn't wrap it all in the cmd
cmd = UI::Command.new(“Remove All Mats”) {
# why do add to the selection
model.selection.add( model.active_entities.to_a )
# and then use 
model.entities.each
# also why have menu text without a menu item
cmd.menu_text = "Remove All Mats"

since v8 there is materials #remove, but it wasn’t bug free until v14…

# wrap the logic in a method
def remove_mats
  model = Sketchup.active_model
  ents  = model.active_entities.to_a
  mats  = model.materials
  len   = mats.length
  # check version
  if Sketchup.version.to_i >= 14
    mats.to_a.each{|mat|mats.remove(mat)}
  else
    ents.each do |e|
      e.material = nil if e.respond_to?( :material )
      e.back_material = nil if e.respond_to?( :back_material )
    end
    model.definitions.each do |d|
      next if d.image?
      d.entities.each do |e|
        e.material = nil if e.respond_to?( :material )
        e.back_material = nil if e.respond_to?( :back_material )
      end
    end
    mats.purge_unused
  end
  puts "Materials: #{len} >>> #{mats.length}"
end

# call the logic as your comand
cmd = UI::Command.new("Remove All Mats") { remove_mats }

toolbar = UI::Toolbar.new "Remove All Mats"

cmd.small_icon = cmd.large_icon = "No Mats.png"
cmd.tooltip = "Remove All Mats"
cmd.status_bar_text = "Removing All Materials"
# cmd.menu_text = "Remove All Mats"
tb = toolbar.add_item cmd
# allow toolbar to be turned off
tb.get_last_state == -1 ? tb.show : tb.restore

john

Thank you but, I get this response…

Error Loading File Remove Materials Mine.rb
Error: #<NameError: undefined local variable or method tb' for main:Object> C:/Users/Mark/AppData/Roaming/SketchUp/SketchUp 2015/SketchUp/Plugins/Remove Materials Mine.rb:38:in <top (required)>’

No, this is just snippets of code I get from reading forums and such. I barely understand any of it. (Obviously).

I just deleted the line…

allow toolbar to be turned off

toolbar.get_last_state == -1 ? tb.show : tb.restore

And that did it. Thank you very much !!!

I edited the toolbar to work…

john

Thank you again. I wish I understood this stuff, so I wouldn’t have to ask such dumb questions.

Given that, a few thoughts…

You use .respond_to? in your code, but you’re checking the read-only attributes, :material & :back_material. It would be better to check the write attributes, :material= & :back_material=. Obviously, we know that these attributes are read/write, but…

One item that would not typically be the source of large performance issues (especially in SU), but everything adds up…

.respond_to? checks a rather large list of attributes/methods, as all that are in the inheritance chain are checked. From the docs, either at File: SketchUp Ruby API — SketchUp Ruby API main or http://ruby.sketchup.com/, you’ll see only two classes with the .material attributes, Sketchup::Drawingelement & Sketchup::Face. The docs for Face say that the .material attributes are inherited from Drawingelement.

You can check this with the following, which shows only the attributes & methods defined for an ‘instance’ of the Class/Module, with no inherited items (the false parameter does that, omit it or change to true, and all items are shown).

puts Sketchup::Face.public_instance_methods(false).sort

It shows that material is not a native attribute of Face. Also, from the docs, the back_material attributes only exists in Face.

Hence, rather than e.respond_to?(:material), you could use e.is_a?(Sketchup::Drawingelement). Likewise, e.respond_to?(:back_material) could be replaced with e.is_a?(Sketchup::Face).

I haven’t benchmarked the differences (probably very small unless you have a lot of entities), and SU could totally change the API tomorrow (unlikely), but typically, with a shorter list, the search time will decrease.

And finally, it may be easier (and quicker?) to replace the ents.each and d.entities.each blocks with:

ents.grep(Sketchup::Drawingelement).each { |e| e.material = nil }
ents.grep(Sketchup::Face).each { |e| e.back_material = nil }

Just some ideas. Lighting guy? A long time ago, I used to be Vari-Lite trained/certified…

I’m sure what your saying here has value. But, I don’t really understand any of it. I’m able to copy and paste, and fumble to kinda make a working plugin. That’s my skill level in Ruby for Sketchup. Yes. A lighting guy here. The last “known” show I did was Phantom (of the Opera) in Las Vegas. We had VL3k’s, 2416’s, and four VL5b’s. Thanks for the advice on Ruby here. With the decision to make Sketchup a web only application, eventually, I’m not sure how much more of life Ruby has.

Maybe i’m missing something, but i can’t see anything like start_operation and commit_operation in your code.
Try adding
model.start_operation("removeMats", true)
right after the line
model = Sketchup.active_model
and a
model.commit_operation()
before your last closing curly brackets.

Michael

1 Like

This topic was automatically closed 91 days after the last reply. New replies are no longer allowed.