Material Take Off using Ruby

Hi Everyone,
I wanted to generate data for Material Take Off from SketchUp models. Normally a user will do it using “Generate Report” option. From a thread in forum, I got to know that functionality of “Generate Report” isn’t supported by ruby API.

So I used below approach:

  1. Iterate through each definition (let’s say d) available in the model
  2. get instance count for the component having definition d (d.count_used_instances)
  3. Then use both the data and store it into an excel file.

Below is the function used to count the instances of different components:

def count_Instance( )
    model = Sketchup.active_model   
    puts "below are the definitions name and count"
    definitions = model.definitions    
    puts "--------------------------------------------"
        definitions.each{|definition|        
        puts definition.name 
        puts definition.count_used_instances
       }
end

I get 400 different components when I manually use “Generate Report” option, but when I use above function in a ruby script it provides more than 1400 components. It means the iteration happens more than 1400 times. So here I’m having more than 1000 definitions to ignore but I’m not sure on what basis should I do that for similar result.

Is there any way that I can only iterate through the components that are available in the data provided by “Generate Report” option.

Your suggestions are welcome.

Please update your profile information. It says you are using a Free Plan but you can’t use Ruby with it.
By the way think than you can have components inside your components so that’s the reason why you receive more entities.
Test their path or parent in order to filter them…

1 Like

We do not know what the report options are that you are using.

I suspect that the report is only set to a certain number of levels, whereas your script counts all definitions at all levels.

This is not actually true. The old “offline” report engine can be fired by a ruby call.

What is the forum topic you are referring to?

Thanks for your response @DanRathbun, I’ve tried to answer the best I can do for what you wanted to know. In case there’s anything else to be known, please let me know.

I’m using below sample template for report generation. If there’s any modifications required, kindly suggest me.

You can refer to this link for the reference of forum discussion:

Generate report from Ruby API - Developers / Ruby API - SketchUp Community

If there’s something I misunderstood, please let me know. It’ll help me to learn.

Hi @rtches ,
Thanks for the response.

It make sense that the additional definitions I’m getting, must be of nested entities.

I’m not an expert of SketchUp and it’s API. I’m exploring how can I “test their path or parent in order to filter them…”. If you could show me a code sample that would be a great help.
Thank you!

This way you can test if selected entity is nested in another component

model = Sketchup.active_model
sel = model.selection.first

if sel.parent.is_a?(Sketchup::ComponentDefinition)
  puts "Nested"
else
  puts "Not nested"
end

Well, your iteration will occur even when the definition has 0 instances and even with some instances will occur for definitions that have 0 used instances.

This iteration will skip definitions with no instances and no used instances:

def count_used_instances
  model = Sketchup.active_model
  puts "below are the definitions name and count"
  definitions = model.definitions
  those_used = []
  puts "--------------------------------------------"
  definitions.each { |definition|
    next unless definition.instances.size > 0
    num_used = definition.count_used_instances
    next unless num_used > 0
    puts "#{definition.name} : #{num_used}"
    those_used << [ definition.name, num_used ]
  }
  # those_used is an array of nested [name, qty] arrays;
  # return it as a hash with the name as the keys, qty as the value:
  those_used.to_h
end