Select all sub-components in a selection

Hello everybody!

Is it possible to select all sub-components present in a selection?

For example:

1- I select a furniture component present in SketchUp.

2- The method must select all sub-components in all nesting levels for this piece of furniture.

Thank you in advance for your help.

David

This is quite easy to do but in most cases a bad idea. The user will not expect entities outside of the active drawing context to be selected. In my view this should only be done in the extreme case when the whole point of the plugin is to be able to select outside the current drawing context. If the purpose of the plugin is something else itā€™s better to find another solution.

# Select an instance and run snippet to select all child instances.
def select_children(instance)
  children = instance.definition.entities.select { |e| e.respond_to?(:definition) }
  instance.model.selection.add(children)
  children.each { |c| select_children(c) }
end

select_children(Sketchup.active_model.selection.first)

Hereā€™s what happens if the user tries to move a component while at the same time moving its content and content of the content.

2017-11-02_15h18_08

1 Like

Itā€™s Dynamic :slight_smile:

Just FYI, this (above) will select both Sketchup::ComponentInstance and Sketchup::Group instances within SketchUp 2015 and higher. (Before that release Sketchup::Group did not have a definition method.)
But, this is usually want you want when dealing with Dynamic Components as they extensively use nested groups.

You cannot select sub-components for only one top level component instance. This is because instances do not ā€œownā€ entities or sub-component instances. Only definitions do. So if you select sub-components, you are selecting them in ALL of that furniture definitionā€™s instances.

You have asked a similar question [under another guise] over in SketchUcation.com !

As I explained some days agoā€¦ why do you need to add entities to the selection-set that span various entities contexts.
You can do nothing with them.
Working across contexts cross-threads things and a BugSplat will almost certainly resultā€¦

You can add entities you find across contexts into a ā€œcollectionā€ - say an array or a hash - and do something to them.

However, since a selection is intended to be applied to the active context, then using it across various contexts is a bad idea - unless perhaps you specifically intend the selection to temporarily show such objects, without changing them - e.g. you collect things to change in an array, and then add those things to a selection ā€˜momentarilyā€™, so when the user confirms the selection is cleared and the changes are effected in some other wayā€¦

3 Likes

Nor does SketchUp! It opens up a big can of potential worms.

2 Likes

Thank you Eneroth3, your method works perfectly and I ended up doing what I wanted.

My goal is to allow users of Click-Cuisine 2 to choose dynamic components to clean without affecting other models.

Your Eneroth3 method now allows me to remove all hidden subcomponents from selected dynamic components:

def select_children(instance)
    children = instance.definition.entities.select { |e| e.respond_to?(:definition) }
    instance.model.selection.add(children)
    children.each { |c| select_children(c);
    c.erase! if c.hidden?
    }
    end


def supprimer_sous_composants_masques_selection
    select_children(Sketchup.active_model.selection.first)
    end

I will try to apply this same method to remove the dynamic attributes of the parent and child components.

It certainly has simpler solution, but I achieve my goals with this method.

Thank you for all your interventions.

David

Looks like you are modifying the collection you are iterating. That can lead to issues.
Also, bulk select/erase is faster.

For instance:

# Don't do this. You are erasing from the collection you are iterating. 
entities.each { |e| e.erase! if e.hidden? }
# This is safer
entities.to_a.each { |e| e.erase! if e.hidden? }
# This is safer and faster
hidden = entities.select { |e| e.hidden? }
entities.erase_entities(hidden)

Similarly with modifying selections:

# This is slow
faces.each { |face| model.selection.add(face) }
# This is faster
model.selection.add(faces)

Itā€™s still not clear to me why you need to select the entities deep into the instances. Your code seems to be making a selection as well as erasing stuff. Why is it doing both?

Hello, tt_su

Youā€™re right, the selection is useless!

def select_children(instance)
    children = instance.definition.entities.select { |e| e.respond_to?(:definition) }
    children.each { |c| select_children(c);
    c.erase! if c.hidden?
    }
    end

    select_children(Sketchup.active_model.selection.first)	

With the entities.each {| e | erase! If e.hidden?} Method, I can not remove hidden components in all nesting levels.

Can you write all the method?

Thank you

I am not able to combine method 1 and method 2, to remove the dynamic attributes, components and sub-components of the selection.

def select_children(instance)
    children = instance.definition.entities.select { |e| e.respond_to?(:definition) }
    children.each { |c| select_children(c);
    c.erase! if c.hidden?
    }
    end
	
def methode1
    select_children(Sketchup.active_model.selection.first)
	end
		
def methode2
    m=Sketchup.active_model;
    m.start_operation("unDC");
    m.definitions.each{|d|d.attribute_dictionaries.delete("dynamic_attributes") if d.attribute_dictionaries and d.attribute_dictionaries["dynamic_attributes"];
    d.instances.each{|i|i.attribute_dictionaries.delete("dynamic_attributes") if i.attribute_dictionaries and i.attribute_dictionaries["dynamic_attributes"]}};
    m.commit_operation
    end	

I would like to allow the user to remove all the dynamic attributes of the components present in a selection.

Your help would be of great help to me.

Thank you in advance.

I am really confused of what you are trying to achieve. First you asked about selecting entities and now you are removing attributes? What is the purpose?

Also it would be easier to read and understand your code if you follows a style guide like this one: GitHub - rubocop/ruby-style-guide: A community-driven Ruby coding style guide

The first interest and lighten the weight of the kitchen when they are finished.

  • Remove hidden Dynamic components.
  • Purge dynamic attributes.

Can reduce by 50%, the weight of the models because the dynamic components, become simple components.

This offers many advantages:

  • Export of kitchens to other simplified software.
  • Faster file sharing.
  • Navigation in the improved project.

I could create a tool with delete functions for all the file, which would be much easier!

But this is not my wish because there are already very good plugins to perform this task.

I just want to clean up the 3D models offered by Click-Kitchen 2, without affecting the rest of the project.

Cordially

David

With a lot of persistence, I ended up finding a solution:

def selectionner_tous_les_sous_composants_selection(instance)
    children = instance.definition.entities.select { |e| e.respond_to?(:definition) }
    instance.model.selection.add(children)
    children.each { |c| selectionner_tous_les_sous_composants_selection(c);
    }
    end   
   
def supprimer_tous_les_attributs_dynamiques_selection
    mod = Sketchup.active_model
    sel = mod.selection
    sel.each{|s|s.definition.attribute_dictionaries.delete("dynamic_attributes");
    sel.grep(Sketchup::ComponentInstance).each{|i|i.attribute_dictionaries.delete("dynamic_attributes")}}
    end   
   
def desactiver_toutes_les_selections
    mod = Sketchup.active_model
    ent = mod.active_entities
    sel = mod.selection
    instances = sel.grep(Sketchup::ComponentInstance)
    sel.clear
    end      
   
selectionner_tous_les_sous_composants_selection(Sketchup.active_model.selection.first)
supprimer_tous_les_attributs_dynamiques_selection
desactiver_toutes_les_selections

I did not find how to purge the sub-components of their attributes without having to select them, but the method works.

Thank you to everyone who wanted to help me. :kissing_closed_eyes:

this code will clear all DC attributes from all components, not just yoursā€¦

and it fills the undo stack with hundreds of individual callsā€¦

it will also do very little to reduce the file size as you load 62Mb of images into the model.materials collectionā€¦

they are compressed but removing 00-COMMAND.skp will loose 42MB after a purgeā€¦

as you know what all yours are called, you should only target them by name, as we discussed beforeā€¦

john

2 Likes

Iā€™m a bit confused here. Removing attributes has nothing to do with selecting entities. The selection is a specific part of the user interface that is quite irrelevant here (except for the top level component that the user selects before running the script).

Iā€™ve been thinking for a while about making a plugin that turns dynamic components into regular components myself but never gotten around to di it. Not to save file size though, I donā€™t think it would make much difference, but to make the components easier to work with and to be able to call the plugin De-DC-ify (I find that name funny). However I ran into an Israeli fellow the other week (canā€™t remember the name, sorry) who had already made that plugin so now Iā€™m prioritizing other projects.

The biggest problem to overcome here is to make all components present inside the component to de-DC-ify unique so instances elsewhere in the model arenā€™t affected. Thatā€™s really the only thing that has to be solved to make the plugin.

You are definitely right!
Iā€™m going to do some testing and think about what Iā€™m going to do.

David the best solution would be to ā€˜lazy loadā€™ each set of materials ā€™ only ifā€™ the user wants itā€¦

at the moment you still dump them all at the start, and add more for each component type as wellā€¦

the model gets bogged down, long before the design is completeā€¦

john

Regarding your current code it would be much easier to understand it and help you if you styled it properly. With the end keyword not properly indented, closing curly bracket on its own line while the code block and open bracket share the same line, and arbitrarily placed semi-colons the code becomes really hard to read. It would also be easier to help you if you wrote method names in English instead of your local language so we could compare what the methods actually does with what you expect them to do (based on how youā€™ve named them).

You currently have 3 methods. This is what they currently do.

The first adds all components, groups and images in the selected group or component to the selection and calls itself recursively on them.

The second one makes every single component in the whole wide model un-dynamic. And it does it in individual operators which can add hundreds of operations to the undo stack.

The third method clears the selection.

Iā€™m not sure if this is the intended behavior.

I agree with you John!

Click-Kitchen 2, will propose a library of dynamic components present in a folder of the Plugin.

They will be loaded only if the user wishes.

For example, we have a handle model present in every piece of furniture that can be replaced with one click.

Thus we can offer a large choice of handle without weighing down the furniture.

The study of Ruby Scripte will revolutionize our tools. :slight_smile: