Sketchup Ruby API - Create a component from selection or Array

Good day Community,

I am working on a plugin to create a custom component from a template. The template is a dynamic object with Component options for manipulating size. Once manipulation is complete there is a function to add custom attributes and save as a file with a derived file name.

Current blockage:
Creating a component from an Array (created by exploding the template component).

Is there a function or process in the API that accepts an Array as an argument and creates a new ComponentInstance? I have read about the .to_group method, but the script requires a component. Once all the parts are a component, the current script can handle the rest.

parts.class
=> Array

parts.to_component
Error: #<NoMethodError: undefined method to_component' for [#<Sketchup::ComponentInstance:0x00000243f6c08a78>, #<Sketchup::AttributeDictionaries:0x00000243f6c08a50>, #<Sketchup::AttributeDictionary:0x00000243f6c08a28>, #<Sketchup::AttributeDictionary:0x00000243f6c08a00>, #<Sketchup::AttributeDictionary:0x00000243f6c089d8>] :Array> (eval):1:in
SketchUp:in `eval’
=> nil

Thanks in advance for any advice.

If you already have a component, why do you want to create the component again?

Doesn’t it work for you to make it unique?

The template has exposed dynamic attributes that should not be exposed in the final component. Also looking to remove the the ‘function’ based sizing elements from the template once editing is complete. Currently when I attempt to expose the new dynamic attributes, the geometry of the item reverts to its original template size.

Before running attribute script

After Script

After exposing one attribute

The other reason is to bring down file size and complexity of the final component. These components are then imported to another file via a different extension.

First of all, the word template refers to a SKP file that is used to create a new model with certain scene pages, rendering styles and materials pre-seyup.


It sounds like you are wanting to use a base dynamic component to set it’s configuration, then
de-DCify it making it a normal non-dynamic component thereafter. @eneroth3 has such an extension already posted somewhere, either here, the Extension warehouse or the SketchUcation PluginStore.

Search on the term “de-DCify” or “deDCify”

Basically, to do this you remove the "dynamic_attributes" dictionary from both the instance and its parent definition. So as Rafael says, you must first make the instance unique which creates a clone definition for the instance you are about to change. (This prevents making changes to the “base” definition.)

Apologies for the term ‘Template’. Yes, I am referring to a base dynamic model.

Your assumption is correct. I have a multi layered Dynamic component that needs to be boiled down to its base entities (lines and faces). Once that is done it will be built as a new dynamic component with predetermined attributes and saved to a new file.

Copy on the precautionary tactic of making it unique first. This makes good sense.

Will check out @eneroth3 extension! Do you know if it drills down the component tree? I have several DC components that make up a single item.

I am hoping to automate the process so that less experienced users can build items quickly. Is there an API process to select all visible items and create a component?

The only difference between a dynamic component and a “dumb” component is the presence of an "dynamic_attributes" dictionary attached to the definition and conditionally the instance (if any attribute values differ from the defaults in the definition’s "dynamic_attributes" dictionary.)

It may be better to just clear the attributes from the "dynamic_attributes" dictionaries (definitions and instances) rather than remove the dictionaries.

I cannot remember offhand. But it is not very difficult, you just need to make unique as you drill down.

You can search the current active entities context for all object’s whose visibility property is true. But it can also be complex with regard to tag visibility.

Hence the Model#drawing_element_visible? method which requires that you know the path to the instance objects. (ie, Model.active_path)

What I am trying to get across is that exploding is just complicating the issue. The desired objects are already a component. Exploding in order to remove attribute dictionaries is way overkill.

But yes there is a kind of rigmarole that might do this.

model = Sketchup.active_model
active = model.active_path
active = [] if active.nil? # in case at top-level
ents = model.active_entities
objs = ents.find_all { |ent| model.drawing_element_visible?(active << ent) }
grp  = ents.add_group(objs)
inst = grp.to_component

Much appreciated Dan!

I do tend to make things complex and I may need to revisit the methodology on this one.
But as to getting a method to create a dumb component you have brought me to this, which serves the current purposes.

def self.regroup
  model = Sketchup.active_model
  active = []
  ents = model.active_entities
  model.active_entities.each {|e| active << e}
  grp = ents.add_group(active)
  inst = grp.to_component
end
1 Like

… except that …

active = []

… will not be true unless model.active_entities == model.entities
Ie, you cannot be within any nested active edit context.

However, my previous post did not (originally) take into account that when at the top-level model.entities, that the Model#active_path method returns nil. We did complain about this (when it was first implemented). Most fell it should have returned an empty array.

So, the paradigm really should be something like:

active = model.active_path
active = [] if active.nil?

… or a one-liner (after setting ents = model.active_entities) like:

active = ents == model.entities ? [] : model.active_path

[I inserted the first choice into the snippet in my previous post.]

Another point.

… is actaully the same as:

active = model.active_entities.to_a

Ie, it does not do any filtering by visibility.

So, you’d just as well do:

def self.regroup
  ents = Sketchup.active_model.active_entities
  ents.add_group(ents.to_a).to_component
end

… which should return a reference to the new “dumb” instance object.

Thanks Dan!
For my purposes there is only one item / object / representive model in the file. So I do not need to worry about what component is selected because of the current workflow… Though I may have a rethink about this in a moment.

def self.regroup
ents = Sketchup.active_model.active_entities
ents.add_group(ents.to_a).to_component
end

I do appreciate this refactor though. It’s very clean.

Okay, but please realize how you then led me astray with:

I do see that now. Did not realize it at the time. It was unintentional, but helpful. I was unaware of the active_path and drawing_element_visible? methods.

1 Like