Nested groups and export to file


I need some help understanding ruby. My topic might be here in another thread but show how I can’t locate it.

What I want is to export info from my drawings to a csv og excel file to be used later in other programs like ms project.
Right now am I using layers/tags for prising and time estimates and my plan is to use groups to create an hierarki of tasks for ms project. The idea is first group is building. In this group you would have nGroups floors. In floor group you would have groups like facades, ceiling and so on. You would also have nRoomgroups. In a roomgroup you would also have many subgroups like ceiling, floor, walls and so on.

So I will have a lot of groups. But the idea is one group also is a task. A task with sub tasks and so on. If I draw a gypsum bord I now have a price pr m2 and a time it takes to mount it in layers. This gypsum wall is placed in a room on a given wall. What I want to export this task to ms project to create a timeline of the project.

My issue at this state of understanding is not quit how these groups separate itself from other groups and in which nested group it belongs to. I would have separate names of rooms but the wall groups in each room will have the same name.

What I want is a loop that dives into main (building) group and creates a list of rooms walls ceilings and so on that I then can save to a file. As a start group name is just fine to be exported.

Even though I have many years with php, javascripts python I’m new to ruby and Sketchup programing. What i need is to see a loop if this is possible that would create search a list.

Would appreciate some help or advice to proceed with my project

Because the learning curve for Ruby and SketchUp extensions is so steep, I suggest first to learn to use attribute dictionaries.

You can assign custom dynamic attributes using the Dynamic Components dialogs, and/or special attributes in the Entity Info panel, and/or BIM attributes using the Classification toolbar.

Then, output a report file using File > Report Generator.

All of the above attribute types should be accessible in the Report Generator form.


After running a report, the “Download” button will ask you to save a CSV data file.
This file then can be imported into Excel, OpenOffice Calc, LibreOffice Calc, etc.

Then after you are familiar with using attributes, if you still need more customization, explore the possibility of using one of the export extensions that output cutlist, or costing or integrate with Excel.

It may be more affordable (and faster) for you to subscribe to an existing extension(s) than to expend the time and cost learning Ruby and SketchUp programming.

But if you really want to learn SketchUp Ruby programming, then be prepared to spend 6 months to a year in intensive learning, coding and testing.

There is also a quick helper for those comng from Python progrmamming:

Your project covers many topics. It would be better to break it down into coding tasks and search the forum for these specific tasks.

Your request here in this topic is too general. Lets start with 1 task …

This task’s first step is to find a group by name.

So we search this API forum category for “find a group by name” and we find quickly this topic:

It has several code examples I and other coders have posted.

This is the 2nd step of the task. This is called “walking the hierarchy” (note the correct spelling).

You can iterate through a group definition’s entities collection or reuse the “find by name” paradigm to search it for a specific named object.

The same “search” paradigm can be used to find objects that have a specifically named attribute dictionary attached to them (such as “Petor_Project” or whatever your extension name is.)

I know that there are already numerous forum topic threads on searching and walking entities collections of the model and of groups or component definitions.

This would be another task. The Ruby Core has several classes IO and it’s subclass File for writing and reading files.

Also the Ruby Standard Library has a dedicated CSV library for dealing with csv text files.

So basically object hierarchy is normal for organizing geometry.

Tagging is usually for controlling what is displayed or hidden and in what scene.

Marking with attributes is for attaching any kind of data both to be used internally (for extensions) or for external export.

1 Like

Recently I needed some “similar” things… however not dealing with csv.

These methods will give you and array of hashes (with nested array of hashes as a “children”, if applicable) with the name, persistent id of the groups and component instances.

I derived it for your needs (more or less) and giving this code snippet here, just to have something to think about. :wink:
( Without further explanation, because Dan doing that much better than me with my “funny Hunglish”…)

def get_instances(ents)
  #ents.grep(Sketchup::Group) + ents.grep(Sketchup::ComponentInstance)
  #Dans's advise: Better performance, see for details.

def object_hash(instance)
  object_hash = {}
  object_hash["name"] =
  object_hash["id"] = instance.persistent_id
  c_instances = get_instances(instance.definition.entities)
  if c_instances[0]
    object_hash["_children"] = []

def instances_hierarchy
  model = Sketchup.active_model
  ents = model.entities
  instances = get_instances(ents)
  objects_ary = []


Hi Dan
Thank you for your detailed reply. First of all I’m an architect not a programmer even though I know some I’m not spending too much time to become a ruby programmer. But I thought maybe I could use what I know so far to get something more out of Sketchup. And I’m Norwegian so my English grammar is there after :wink:

I managed to load a list of tags from a cvs file int to Sketchup pretty easy and created a “library” of chapters with related tags. So I thought the other way should be possible as well. We have a standard here in Norway of labeling and numbering different building parts which we use when we make a tender of the project. It’s pretty big so instead of manually write them each time, I now just load them.

I’m pretty sure this is universal, but we also use a list/library of all building parts and labor time, you can think of. Each item is listed with material cost pr unit, a work time per unit, CO2 and so on. Units can be pr m2, rm, pcs. For pricing I use Quantifier pro. On layers.

When I create a project, I only use a variety of groups since every unit from scratch is more or less unique. I only use components if I make building part like a lamp or fixed unit I want to save for use in other projects. Quantifier Pro is very nice since the product adjust its cost, work time with the push pull tool, based on either square or length which I use the most.

For me the Report generator is too simple, and so is the export function on Quantifier Pro. Specially if you would like to import this file into other software other than the Office programs you mentions.

I believe my topic was quite simple, but I probably didn’t explain it to good. But the sample dezmo showed us was exactly what I wanted out of this post. And it worked very well on the first run.

I will be able to work further with this to generate the file I hopefully can work with.

But thanks for the info

This was very good :+1: Will play with this further.

Thanks :beers:

1 Like

What he posted was only a set of methods. It is expected that you will wrap those within a specific extension submodule or your author/company module. (Ie. It is a no-no to really define methods at the top level within Object.)

Hi again.
I have to ask you again because I’m looking in the wrong area

Your id and name works fine, and I have added the “tag”

But it would be nice to the Length, height, and width (lenx, leny, lenz) of the instance

    object_hash["id"] = instance.persistent_id
    object_hash["name"] =
    object_hash["tag"] =
    #object_hash["material"] = instance.definition.material
    puts instance.definition.get_attribute("dynamic_attributes", '_lenx_formula').to_f.to_l

It feels like I have tried all tricks found in this forum but I always end up with 0m :frowning:
I also tried Dans read_dc_attribute() example, with no luck either. Just blank return…

Is it possible to get these values here or is that a different approach?

A material like paint added to one surface could also be nice if added.

… is not the attribute where the value for the “lenx” dynamic property is stored.
The formula is used by the DC extension to calculate the value.

It is saved into the instance’s "dynamic_attributes" dictionary if it differs from the definition (ie, if there are multiple instances and each can have different values,) … otherwise the value is saved in the definition’s "dynamic_attributes" dictionary.

A dynamic component instance may or may not have a "dynamic_attributes" dictionary. It may not if there are no instance specific values to be saved.

However, dynamic groups (nested within a DC component) always have all dynamic attributes attached to the group instance. (Ie, the group definition is not supposed to have a dynamic dictionary.)

So, anyway, … the standard paradigm is to check the instance first for a "dynamic_attributes" dictionary / attribute, and if it’s not a group, then check it’s definition’s "dynamic_attributes" dictionary.

But again you don’t check the hidden formula ("_lenx_formula",) you check for the "lenx" value attribute.

Here is a little test module that shows what I mean …

module AndersHolm
  module DataExporter
    extend self

    EXT_NAME ||= Module.nesting[0].name.gsub('::',' ')
    DC_DICT  ||= 'dynamic_attributes'
    MB_ICON_INFO ||= 64
    MB_ICON_QUES ||= 32
    MB_ICON_WARN ||= 48

    def get_dc_property(inst, prop)
      inst.get_attribute(DC_DICT, prop) ||
      inst.definition.get_attribute(DC_DICT, prop)

    def get_lenx(inst)
      get_dc_property(inst, 'lenx')

    def get_leny(inst)
      get_dc_property(inst, 'leny')

    def get_lenz(inst)
      get_dc_property(inst, 'lenz')

    def command_get_property(name)
      model = Sketchup.active_model
      inst = model.selection.grep(Sketchup::ComponentInstance).first
      unless inst
        UI.messagebox( "Nothing selected!", MB_ICON_WARN )
      result = case name
      when 'LenX' then get_lenx(inst)
      when 'LenY' then get_leny(inst)
      when 'LenZ' then get_lenz(inst)
      else return
      UI.messagebox( "#{name} : #{result}", MB_ICON_INFO )

    if !defined?(@loaded)
      submenu ='Plugins').add_submenu(EXT_NAME)
      submenu.add_item('LenX') { command_get_property('LenX') }
      submenu.add_item('LenY') { command_get_property('LenY') }
      submenu.add_item('LenZ') { command_get_property('LenZ') }
      @loaded = true

1 Like

Thanks for the code.

‘_lenx_formula’ just followed my cut’n paste when I wrote the post. I tried all other possibilities found with the same result. ‘lenx’ was one of them.

Your code somewhat worked, but only on a component and not on groups. You also had to select the component to make it work. If not, we got the error message. But I also did not get anything else than blank xyz’s.

I know it can be done because other extensions are doing this, but they are so rigged with very limited configuration so have not found a win win situation with these for my project. So that’s why I try to come up with a solution on my own. Quantifier Pro is very good for setting up prices but lacks information about child or parent groups. But it does pull out xyz’s in any depths.

dezmos code snip worked perfect on ID, name and layer. I assume persistent_id is unique for the group. Since name is not, is it possible to use this id to pull out lenx,y,z’s?

Is there a trigger to a group that you can do on the drawing board or creation that would give the group a “dynamic_attributs” which I belive is required?


Persistent id is perfect to “pull out” entities :

Finds and returns entities by their persistent id.

I do not have that much knowledge about Dynamic Components (which is a closed source extension).
Perhaps Dan, who have experienced much much more, can give you some more thoughts.
Beside that there is a lot of discussion about it:

It is meant for demonstration purposes.

First of all … the ‘lenx’ attribute is only associated with dynamic components. Not normal components. And the component must actually have that attribute. Ie, the dynamic component author must have added it manually when creating the component.

So this means you must add the ‘lenx’ (and the ‘leny’ and ‘lenz’) attribute(s) via the Component Attributes authoring dialog to your components.

It works fine for sample dynamic components that come with SketchUp.

So if you have a component that it does not work, then post it here and we can take a look.

Dynamic groups must be children to a dynamic component.

You might be going down the wrong road. A dynamic component is just one that has special behavior using the Dynamic Components extension. It is a proprietary closed source Trimble extension.

Most 3rd party extension do not “hack” into this extension’s components and just use components and groups that do not have the “dynamic_attributes” dictionary. (They might use their own extension dictionaries.)

So there are ways to get the position, size and scale of normal components and groups via their transformation.

Learning Ruby and the SketchUp API is hard enough without starting right out trying to “hack” at a closed source dictionary and extension.

Thank you for your post.

Yes, I was looking down the wrong road. Based on your previous recommendation of using the built in Report generator for my task, which uses LenX,LenY I thought this was a reachable variable to use. And I was not aware of me hacking the Sketchup system, trying to retrieve info already create on the drawing board.

Anyway, I found a solution that work as I wanted through the .bounds So things look ok for now.

Next task is to get color or material out of the instant in the loop.

1 Like