Count sub-components with the definition "TOTO"

@eneroth3 is correct.

My eyesight failed me again. I mistook a single & for a double ampersand (&&), so I read the entire statement as a compound boolean expression.

@dynamiqueagencement David, nevermind anything I wrote. (Deleting all my posts.)

1 Like

Dan I find it a shame because it is always interesting to have 2 different approaches!

Am I getting closer to the solution?

  ["Handles"].each do |liste2|
	b = /#{liste2}/
    qut = []	
    mod = Sketchup.active_model
	defi = mod.definitions.each do |d| 
    d.instances & d.entities.grep(Sketchup::ComponentInstance).each do |e|
	  qut << e unless e.visible?
	lg = qut.length if e.definition.name =~ b
 if lg.to_i>1
    e.erase! unless e.visible?
    end
  end

end
end

Your help would be really welcome!

Hello David,
I’ve tested my own example, seems to work fine in case if I understood the task correctly.
Method “_ ** defs.to_a.select {| d | ** _” does not “select” entities visually in SketchUp model (i.e. it does not put entities into an active selection in an active model) it only returns an array with entities, which match selection condition (again if I understood your question correctly). In case if “approp_defs” array appears to be empty, then it means that active model does not contain any definitions with names specified in “approp_names” array.
So my example searches for definitions with appropriate names, then iterates through all appropriate definitions and searches for specified instances nested inside of found definitions and erases all visible instances except one. Maybe it’s not what you actually expected, it is how I understood the task.

I’m frankly quite confused what you are trying to achieve. I know it has to do with counting component instances but do you want to:

a) count the number of instances of a certain definition within another certain definition,
b) count the number of instances of a certain definition within the selection,
c) count the number of instances of a certain definition within another certain definition, within the selection or
d) something else.

Also note that there can be several instance counts of the same definition. Imagine you create a definition named “Bed” and inside it create another definition called “Pillow” and then copy the component “Bed” so you have to instances of it. Technically there is still only one instance of the component named “Pillow”, the one that resides in the “Bed” definition. pillow_definition.instances.size returns 1. Still you can visually see 2 pillows in the model and when selecting the pillow Entity Info will report 2 instance. This is because there are 2 instance paths, one going to the first Bed instance and one going through the second Bed instance, both leading to the same single Pillow instance. If you want to count instances, which count are you interested in?

As Kirrill mentioned the select method has nothing to do with adding entities to the selection (highlight them and let the user interacts with them). The select method is a Ruby core method that exists in all Ruby environments, even outside of SketchUp. The select method is filter out only the elements in a collection that matches a certain condition.

Instead of writing this:

matches = []
my_array.each do |element|
  matches << element if some_condition
end
matches

you can write this:

my_array.select { |e| some_condition }

It means the same but the latter is easier top read which makes the code easier to work with easier to dind bugs in and easier to add new features to.

Regarding code readability if would help drastically if you payed more attention to indentation. Indent with two spaces, only increase indentation when a new code block is opened (on if, unless, def, do, { etc) and only decrease indentation when a code block is closed (end and }). If a line neither opens or closes code blocks it should line up with the line above.

In this code I struggle to read that the reference to e in “e.erase! unless e.visible?” is the e defined in “grep(Sketchup::ComponentDefinition).each do |e|” becase it looks like the code block opened by do is already closed at erase!.

Without being able to parse the code I can’t say if it works.

Hi kirill200777,

Indeed your code works but it does not do what wishes.

Thank you for the explanation regarding the selection.

Can I use the 50/50 of Who Wants to Be a Millionaire??

More seriously, I think answer A is what I want to do.

Here are more details in your example:

Bed = 2 Pillows.

Bed # 1 = 3 Pillows.

Bed # 2 = 4 Pillows.

Condition A: 2 pillows are allowed for each bed.

Action B: The method removes, “1 Pillow to Bed # 1”, “2 Pillow to Bed # 2” and do nothing to “Bed”.

Condition C: The pillows are removed only if they are hidden.

_

I tested your changes in my base code, and I get the following error messages in the ruby console:

Error: #<SyntaxError: <main>:6: syntax error, unexpected &, expecting keyword_end
         qut &lg;&lg; e unless e.visible?

Thank you

David

The difficulty is to count the sub-components for each parent component.

Here is a method I wrote that:

1- List the instances in the model.
2- Extract all entities with their definitions.
3- Counts the entities.

mod = Sketchup.active_model.definitions.each do |d|
	inst = d.instances.each do |i|
	       d.entities.grep(Sketchup::ComponentInstance).each do |e| 
     puts "#{i.definition.name} - #{e.definition.name} Qut: #{e.definition.instances.length}"
    end
  end 
end	

I do not understand why, instances and entities are listed multiple times by the ruby console?

It’s been too long since I’m stuck with this challenge, way too complex for my current level in Ruby.

I have no choice but to work around the problem in another way.

This challenge will have at least allowed me to progress a little more in Ruby.

Thank you to everyone who tried to help me.

See you.

David

I took the liberty to fix the indentation to make the code easier to read. I also purged unused variables being assigned.

Sketchup.active_model.definitions.each do |d|
  d.instances.each do |i|
    d.entities.grep(Sketchup::ComponentInstance).each do |e| 
      puts "#{i.definition.name} - #{e.definition.name} Qut: #{e.definition.instances.length}"
    end
  end 
end	

First the code iterates over all definitions in the model. Within that loop, once for each definition there is, it iterates over all the instances. Within that loop it prints definition specific information to the console.

As you are only printing data related to the definitions, not every individual instance, you can delete “d.instances.each do |i|” and its corresponding “end”. Also you need to change “i.definition.name” to “d.name” as you then no longer has i as a reference.

After doing this the the information will only be printed once for each definition.

Counting instances can be misleading, as instances might be used by definitions that themselves’ have no instances in the model.

So there are two API methods to get component counts:

1 Like

These two methods account for all instances in SketchUp and not in a component or group.

In the model at all levels, yes, this is true. (It was for related information, not specific to your case.)

My attempt to get around the problem failed!

I therefore have to find a solution to finalize Click-Cuisine 2.

New idea:

If I select “Furniture A” and “Furniture B”.

Is there a way to import a handle, only for furniture that does not have a handle?

Example:

  array = []
  mod = Sketchup.active_model
  sel = mod.selection

["Handles"].each do |n1|
  match = /#{n1}/		
  path = Sketchup.find_support_file("#{n1}.skp","Plugins/TNT_ClickCuisine2/Components/")

  defs = mod.definitions	  
  definition = defs.load(path)
     
  sel.grep(Sketchup::ComponentInstance).each{ |s|
  s.definition.entities.grep(Sketchup::ComponentInstance).each{ |e| array << e if e.definition.name=~match }}

    if array.length < 1
      sel.each do |s|
        point = Geom::Point3d.new(0, 0, 0)
        transformation = Geom::Transformation.new(point) 
        instance = s.definition.entities.add_instance(definition, transformation)
      end	
    end
  end

This method counts all the handles in the selection.

So if one of the 2 furniture has a handle, the method no longer loads the handles.

Should the problem be solved in another way?

Your help would be of great help to me.

Thank you

David

:arrow_right: [How to] Colourize code on the forum? (pinned topic)

If you want anyone to be able to read your code, please make sure the indentation is correct.

Hello, eneroth 3
I edited my post to save his presentation.
Is it more readable now?
When you’re new to ruby, it’s easy to follow all the rules.

It is still not correctly indented.

The contents of every doend and {} block should be indented. So that the start line of code is lined up with the end line and the indent guidelines are unbroken.

The indent guidelines in my Ruby lexing style (Notepad++ editor) are set to cyan color. See how the first do aligns at the same indent as it’s end, with all the subordinate code indented 1 ident.
Then again, the if is aligned with it’s own end and it’s subordinate code indented.
And again, the inner doend block is indented. And so on,… and so forth …

It will often help when you are coding a block to create the end line immediately after typing the starting line. Then go back up and insert the code between the lines. (Some code editors can do this “automagically”.)


Nor is it color lexed correctly. Again see

[How to] Colourize code on the forum? (pinned topic)

1 Like

I use “Notepad ++” how to adjust the indentation in automatic mode?

How to adjust the color of texts according to the conventions of the ruby script?

I edited my code to correct the indent following your remarks Dan.
Thanks for these informations.

Concerning my problem, I ended up finding a solution that works.

Instead of looking in “Furniture A” and “Furniture B”, if there is a sub-component “Door”.

I control the value of a dynamic attribute inside each piece of furniture, which informs whether the door is present or not.

If the attribute says that the door is not in the furniture, it is imported if not “nil”.

So I can have as much furniture as I want in my selection and apply the method only for furniture without doors. :wink:

It is better than is was, but still not totally correct … ie …

  sel.grep(Sketchup::ComponentInstance).each {|s|
    s.definition.entities.grep(Sketchup::ComponentInstance).each {|e|
      array << e if e.definition.name=~match
    }
  }

… and for the THIRD time …

READ THIS! :arrow_right: [How to] Colourize code on the forum? (pinned topic)

Settings (menu) > Preferences… (dialog) > Language (panel)

Tab Settings (group) > ruby (choice)

  1. uncheck “Use default value”
  2. set “Tab size” to 2
  3. check “Replace by space”

You can also switch on “Auto-Completion” but you may need to get an autocomplete xml file for Notepad++. @tt_su made one at one time. You may be able to use the stubs at the SketchUp GitHub repo: > GitHub - SketchUp/ruby-api-stubs: Auto-generated stubs for the SketchUp Ruby API. Useful for IDE intellisense and auto-complete.
(This is a complex issue and there are other threads on this. We are going too far off-topic as it is.)

Notepad++ has it’s own forums where you should ask questions:
Home | Notepad++ Community

Settings (menu) > Style Configurator… (dialog) > Language (picklist)

  1. choose “Ruby”
  2. choose a style from the “Select theme:” drop down control
    (You can further modify the chosen style afterward.
    My style is based on “Deep Black” with certain feature color changes, such as I changed “INSTRUCTION”, which are keywords to a bright orange.)
  3. You must also make some global changes to the “Global Styles” (at top of “Language” picklist,) and it will apply to all coding languages. (I myself set “Consolas” as the global font for all coding.) Many of the global style features cannot be set per language.
  4. press “Save & Close” button when done.

Sorry to answer so late but I had to take a break.

Tomorrow I will follow step by step your settings.

Thank you for these explanations Dan.

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