Is there an efficient way to convert a component instance to a group, keeping transformation and axes, that doesn’t involve exploding the entities to the parent context?
I need this on heavy geometry, and exploding takes ages.
I can do it efficiently in the UI by grouping everything in the component then explode it (only the group moves context, so it’s fast), but how can I replicate that through the API?
Why do you need a Group? If you can live with a Component, the #make_unique method on the ComponentInstance will do it (it creates a clone of the ComponentDefinition and attaches the ComponentInstance to it).
Alas, it seems like the API only provides the other direction: to make a component out of a group So one way or another you’d have to cobble it together from smaller steps.
It shows an script originally posted by TIG, but modified to avoid a bugsplat when the component included an arc or curve.
Dan R advised that its better to add the component instance to a new group, then explode the instance thats inside the group.
If the instance has just been created, then all of the logic to preserve attributes, layers, shadow characteristic, material, scale masks etc, may not be relevant.
But you still might want to purge the compoennt definition from appearing the in “In Model” component panel.
Since the only difference between a component instance and a group is a hidden flag in accessible to the API, you do need to go through all of this to accomplish the task unfortunately.
Also it would be nice if Model.import which results in a component had an option to import as a group. This would again avoid the need for conversion.
Was also going to post this link. (Barry beat me to it.)
Pay special attention to the last post by TIG, which explain a non-explode way.
(But you’ll still need to do the property and attribute copying part. Then erase the cinstance, a lastly the definition purge.)
And at one time this method (to_component) was bugged in that it dropped all the attribute dictionaries (perhaps other properties.) Was it ever fixed ?
Thanks guys.
I did see those threads, but I can’t get to the result I’m after.
Here’s my snippet so far :
def self.remove_subcomps(definition)
definition.entities.each{|e|
if e.is_a?(Sketchup::ComponentInstance)
self.comp_to_group(e, definition)
elsif e.is_a?(Sketchup::Group)
self.remove_subcomps(e.definition)
end#if
}
end#def
def self.comp_to_group(inst, parent_group_def)
entities = inst.definition.entities
group = parent_group_def.entities.add_group(entities.to_a)
inst.erase!
end #def
Sketchup.active_model.start_operation("Remove subcomponents", true)
self.remove_subcomps(Sketchup.active_model.selection[0].definition)
Sketchup.active_model.commit_operation
I attached a test model with the groups/comps hierarchy I’m working with. Check the outliner. comp_to_group.skp (126.4 KB)
I want to select the top-level group (“group_lvl1”) and convert all subcomponents to groups.
When I do select the top-level group and run the above snippet, new groups are created in the root context, not in the context of the subcomponents. (I don’t mind about the transformation at this point, I’ll resolve that later)
That’s why I came here.
Any idea what I’m doing wrong?
PS : Also, I get a bugsplat when I undo this operation.
Well the first issue is that you are violating the cardinal rule of collections. You cannot modify the collection at the same time you are iterating it.
Solution, create an array copy, and iterate the copy, so that the iteration reference will not loose it’s way, ie:
No, “inst” is nested in “parent_group_def”.
What you say would be true if I called self.comp_to_group(e, e.definition)
But I’m calling self.comp_to_group(e, definition)
“e” is part of “definition.entities”. It’s not an instance of “definition”.
Ok I see, but as TIG had explained (I thought) the group and the entities need to be in the same context, and they are not. The group and the parent of the entities are in the same context. So then, BugSplat would not be uncommon.
safely makes an empty group in ANY entities context.
You can then add objects into that group.entities context.
entities.add_group(entities_ary)
will only work if the entities reference is pointing to the model.active_entities.
It cannot point at some other entities context - even if the array of entities is in the same entities context as your new group…
You will get BugSplats.
Yes it would be so much simpler if the API had a to_group() instance method of the ComponentDefinition class, that would convert it to a group definition without all this rigmarole and exploding. All the definition’s instances then would become group instances, and there’d be no need to copy attribute dictionaries and native properties.
I’m not sure I understand. I do what I think you want all the time. When something is already a group or a component, select it and explode it. Without doing anything else first, now take the highlighted entities, right click and make them into the other, from a component to a group or vice versa. I rarely use components, only when I decide to build something and keep it for further use, like a table or door. If I just need things to stay separate, I use groups almost exclusively. Occasionally I regret having a group if I discover changes I hadn’t thought of, and now must change each group separately. Balusters for example would be drawn once as a group until all details are complete, then copy as many as you need. With components, you’d distribute the copies first, and finish the details later, but I prefer doing it the first way.