Find the definitions of all the entities nested at the last level

Hello everyone! :smiley:

I have a question that will seem to you to be stupid after all the way we have traveled together hand in hand.

To find all the definitions of the entities present in the selection, we can write this:

def all_entities(ents)
  ents.grep(Sketchup::ComponentInstance).each do |e|
    p e.definition.name
    all_entities(e.definition.entities)
  end
end  
    	
mod = Sketchup.active_model
sel = mod.selection
selection = sel.grep(Sketchup::ComponentInstance)
all_entities(selection)

This method displays all the definitions in all nesting levels.

But I only want to display the names of the entities that are nested at the deepest level in the parent component.

Do your know how to do this?

Thank you.

David

Definitions are not nested, … instances are.
And your “search” method is not efficient as it iterates over the same definitions and entities multiple times.

There is no “easy” way. You’ll have to walk the instance nesting tree.
This is one of the basic programming tasks. There should be info on it at wikibooks programming.
https://en.wikibooks.org/wiki/Subject:Computer_programming

you need to add conditional behaviour to your method…

#grep returns an array, so you can check if the array is #empty? or not…

john

1 Like

I think I’ll never understand that Dan. :grin:

If you say so, it must be true!

I do not agree because I found an easy way:

def last_nested_entity(ents, defname)
  ents.grep(Sketchup::ComponentInstance).each do |e|
    e.definition.entities.grep(Sketchup::Face).each do |f|
      defname << f.parent.name
    end
	 last_nested_entity(e.definition.entities, defname)
  end
end  

defname = []    	
mod = Sketchup.active_model
sel = mod.selection
selection = sel.grep(Sketchup::ComponentInstance)
last_nested_entity(selection, defname)
p defname.uniq
nil

The array of entities is not empty because a list is given with my previous method. :wink:

f.parent.name == e.definition.name

and if you have a thousand faces you’ll push the parent name 1000 times…

try this…

def all_entities(ents)
  ents.each do |e|
    dents = e.grep(Sketchup::ComponentInstance)
    if dents.empty?
      p e.definition.name
    else
      all_entities(dents)
    end
  end
end  
    	
mod = Sketchup.active_model
sel = mod.selection
selection = sel.grep(Sketchup::ComponentInstance)
all_entities(selection)

john

I’m not certain I fully understand what you are looking for, but I think you need to test your code out on more examples. I find that it lists any definition that contains a face, not just the most deeply nested “leaf” instances.

And John is right about the high level of inefficiency when using faces to look for nested instances.

Very good comment john :slight_smile:

Surprisingly my method is still very fast with thousands of faces!

The parent method, returns the closest parent!
Try my method and you will see that only the last nested entities are returned.

String comnparisions are slow in Ruby. First it checks if the first characters is the same. If it is Ruby checks if the next is the same. If it is Ruby checks the one after and so on.

I would use:

f.parent == e.definition

David without you supplying a model, we would each have to find or create our own with your nesting, that we don’t know…

john

I wouldn’t use it either, in code…

I was showing David that he was still doing the same thing as his first example…

john

1 Like

My example works for all components so no need to provide 3D models to test.

If you think otherwise, please provide a template on which my example does not work.

The subject can be closed because the solution is found.

Thank you for your participation.

David

Slightly easier to read and understand with the same results.

def last_nested_entity(ents, defname)
  ents.grep(Sketchup::ComponentInstance).each do |e|

    # Add definition.name if the component.definiton.entities contains any faces.
    # All of David's dynamic components conform to this design requirement
    #   i.e. faces only exist on the terminal leaves
    defname << e.definition.name if e.definition.entities.grep(Sketchup::Face).length > 0

    last_nested_entity(e.definition.entities, defname)
  end
end  

defname = []    	
mod = Sketchup.active_model
sel = mod.selection
selection = sel.grep(Sketchup::ComponentInstance)
last_nested_entity(selection, defname)
p defname
p defname.length
nil

Try it on this model and tell me if it gets what you expected - it does not get what I thought you wanted!

nest.skp (44.5 KB)

but this assumes the user hasn’t added any geometry into the David’s nesting…

and David’s code often assumes his are the only components in the model…

but the user may be adding many kitchens to their tower block…

what happens to defame then?

he also knows the names of all his components, and has seen many examples of targeting those…

john

Very good case Slbaumgartner!
Yes I get what I wanted because each of the facades directly refer to the superior component name.

I agree!
There are many ways to write a method and we can always make things easier and clearer.
But the main one and that method works. :stuck_out_tongue_winking_eye:

If the user create components their definitions names will be included in the array.
If facades or lines are added in the dynamic components, the parent components are quoted several times but purged thanks to “defname.uniq”!

But at no time does the method fail.

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