Delete a list of components by their definitions.
-
@tntdavid said:
Your method works very well and offers new benefits.
It is TIG's method with a few extra "bells and whistles".
@tntdavid said:
I noticed a small problem:
How to avoid deleting the texture of 'CUBE', if it is used elsewhere in SketchUp?I'll look at it today a bit and see if there is an issue.
EDIT: Okay, YES I see the issue. The method does not check the model level entities collection for used materials (on primitive entity objects.)
-
# To test; # purge_comps('CUBE','TOTO','LOLA') # ... or; # del = ['CUBE','TOTO','LOLA'] # purge_comps(del) # # ver; 2.0 def purge_comps(*cnames) # return false if cnames.empty? cnames.flatten! # match = /#{cnames.join('|')}/ # model=Sketchup.active_model # collect matching definitions defstogo=model.definitions.find_all{|d| d.name =~ match } return 0 if defstogo.empty? # collect materials. matstogo=[] defstogo.each{|d| # first used by instances d.instances.each{|i| matstogo << i.material unless matstogo.include?(i.material) } # now used by its entities d.entities.each{|e| matstogo << e.material unless matstogo.include?(e.material) ( matstogo << e.back_material unless matstogo.include?(e.back_material) ) if e.is_a?(Sketchup;;Face) } } matstogo.compact! matstogo.uniq! # now check if materials used elsewhere defsNOTtogo=model.definitions.find_all{|d| ! d.name =~ match } # collect materials. matsNOTtogo=[] defsNOTtogo.each{|d| # first used by instances d.instances.each{|i| matsNOTtogo << i.material unless matsNOTtogo.include?(i.material) } # now used by its entities d.entities.each{|e| matsNOTtogo << e.material unless matsNOTtogo.include?(e.material) ( matsNOTtogo << e.back_material unless matsNOTtogo.include?(e.back_material) ) if e.is_a?(Sketchup;;Face) } } # now used by model entities model.entities.each{|e| matsNOTtogo << e.material unless matsNOTtogo.include?(e.material) ( matsNOTtogo << e.back_material unless matsNOTtogo.include?(e.back_material) ) if e.is_a?(Sketchup;;Face) } matsNOTtogo.compact! matsNOTtogo.uniq! # now reduce matstogo as necessary... matstogo.clone.each{|e| matstogo.delete(e) if matsNOTtogo.include?(e) } # defsgone = defstogo.size matsgone = matstogo.size # start and operation to ensure Garbage Collection works... model.start_operation('Purger', true) # now delete the selected entities defstogo.each{|d| d.entities.clear! } # now delete the unneeded materials matstogo.each{|m| model.materials.remove(m) } # clear the arrays of references to deleted objects; matstogo.clear defstogo.clear # commit model.commit_operation msg = "#{defsgone} definitions purged\n#{matsgone} materials purged" puts msg UI.messagebox(msg,MB_OK) return defsgone end
-
**Thanks for your reactivity Dan.
Your solution works in the most by cases, but not all the time.
The texture applied to TOTO should not be removed because it is used by the 4 Rectangle to Left:
This mistake this product on my Click-Cuisine 2 furniture, and therefore makes the method unusable.
Here's the SKP file:
If you test your code on other examples the problem will not exist!
For this reason the problem is strange and requires an investigation.
Thank you in advance for your help.
David**
-
@tntdavid said:
For this reason the problem is strange and requires an investigation.
I agree. Sounds like a good learning experience for you.
I'll let you do the investigation, and fix it.@tntdavid said:
Thank you in advance for your help.
I've given you enough help for now.
Your turn to do some of the work.
-
**Hello,
You are right Dan, for the moment I still have not found a solution.
I'm stubborn and I'd end up finding it!
Thanks for your example Dirven
I have tested your code and the components are all removed from the SketchUp scene but nothing is purged.
Is this normal?
Edite:
The Ruby console returns this message when I trigger your method.
Error; #<NameError; undefined local variable or method `i' for Teste;Module> C;/Users/David/AppData/Roaming/SketchUp/SketchUp 2017/SketchUp/Plugins/TNT_Teste/logic.rb;60;in `block in purge_comps_n_mats' C;/Users/David/AppData/Roaming/SketchUp/SketchUp 2017/SketchUp/Plugins/TNT_Teste/logic.rb;56;in `each' C;/Users/David/AppData/Roaming/SketchUp/SketchUp 2017/SketchUp/Plugins/TNT_Teste/logic.rb;56;in `purge_comps_n_mats' C;/Users/David/AppData/Roaming/SketchUp/SketchUp 2017/SketchUp/Plugins/TNT_Teste/logic.rb;75;in `purge_comps' C;/Users/David/AppData/Roaming/SketchUp/SketchUp 2017/SketchUp/Plugins/TNT_Teste/logic.rb;85;in `block in singleton class' SketchUp;1;in `call'
Thank you**
-
edited my example...
line 55 i is now item...
john
-
another way is to Hash the materials and set values for each...
def purge_comps_n_mats(*args) model = Sketchup.active_model defs = model.definitions sel = model.selection view = model.active_view ents = model.active_entities mats = model.materials # add a hasj for materials and entities mats_h = Hash[mats.zip([1] * mats.size)] # this means you don't have to get Regexp right yourself names = Regexp.union(args) # this is similar to defs.to_a.dup.flatten list = defs.find_all { |d| d } # we will still only use one operation as v17 will error model.start_operation('mats') list.each do |defn| defn.instances.each do |i| ###################### # optional 'showtime' for testing sel.add(i) view.refresh sleep 0.2 ###################### dents = defn.entities if defn.name =~ names # get rid of the comps checking their materials mats_h[defn.material] = 3 unless defn.material.nil? mats_h[i.material] = 3 unless i.material.nil? dents.to_a.each do |item| mats_h[item.material] = 3 if item.respond_to? ;material mats_h[item.back_material] = 3 if item.respond_to? ;back_material end # delete the instance ents.erase_entities(i) else mats_h[defn.material] = 2 unless defn.material.nil? mats_h[i.material] = 2 unless i.material.nil? dents.to_a.each do |item| mats_h[item.material] = 2 if item.respond_to? ;material mats_h[item.back_material] = 2 if item.respond_to? ;back_material end end end end ents.to_a.each do |item| ###################### # optional 'showtime' for testing sel.add(item) view.refresh sleep 0.2 ###################### mats_h[item.material] = 2 if item.respond_to? ;material mats_h[item.back_material] = 2 if item.respond_to? ;back_material end mats_h.each { |k, v| mats.remove(k) unless k.nil? || v != 3 } model.commit_operation # end purge_comps_n_mats('CUBE', 'TOTO', 'LOLA')
john
-
**Thank you driven, your solution works well but encounters the same problem as that of TIG enhanced by Dan.
The materials applied to the "subcomponents" are not seen by the 2 methods.
To be more precise, here is an example in image:
The goal is that the texture "CUBE" is not deleted because it is used by "Nested component".
Perhaps the solution would be to ask both methods to explore all the subcomponents in SketchUp and collect the materials so as not to delete them?
How to write this in ruby?
I could find a solution by modifying the components of Click-Cuisine 2, but the ideal would be to solve the problem with the code.
If you want to try, here is the SKP file of the example:
Thank you**
-
you must have changed something because it does work for me...
did you read the code?
it collects all nested materials from 'everything' before removing any materials...
click image to see gif:
attach your test code...
john
-
**Yes I read your code driven and am surprised that it does not work for me.
You are right in my last SKP example, your method works.
Make a test with this example:
You will see that the texture of "TOTO" will be deleted.**
-
**I can not understand why the texture applied to "TOTO" is purged.
If I go through "purge_unused" the texture "TOTO" is not deleted.
So I'll get around the problem with another method.
To delete a list of materials, I can write this:
mat_names = ['TOTO','LOLA','CUBE'] materials = Sketchup.active_model.materials mat_names.each{|mnj| materials.remove(mnj)}
Can we do the same with "purge_unused", so that the unused materials of the list are deleted?
Thank you for your help.**
Advertisement