Copy a Group within a Component in Ruby, preserve location
-
Hello All,
First off, sorry this is long-winded. I've found it hard to find other discussions on this (at least one's a mere mortal like myself could understand) hard to come by. Hopefully this will help someone else too!
Let's say you have a component definition called "WALL" and within that component you have 3 groups, each on their own layer. One of the groups is on a layer named "WALL_PRIMATIVES"
Now, say you have 3 instances of that component in a model, all with various locations, scales, etc.
What I would like to do is go into each component instance and copy the group on the "WALL_PRIMITIVES" layer to the root model context (I think this would be called Sketchup.active_model).
So, I have been able to successfully grab the target group using 2 the methods below, but neither one preserves the transformation (location, scale, etc.) of the group. Instead, what happens is that the copied groups end up in a position derived from the original definition, not the various instances they are pulled from.
Both methods use...
mod = Sketchup.active_model ent = mod.entities
failed method # 1 - COPYING THE GROUP:
mod.definitions.each{|d| next if d.image? || d.group? || d.name!="WALL" # skip images, groups, and any component not named "WALL" d.entities.each{ |wall_primative_group| if wall_primative_group.layer.name == "WALL_PRIMITIVES" # only proceed with groups on target layer group_copy = ent.add_instance(wall_primative_group.entities.parent, wall_primative_group.transformation) end } }
failed method # 2 - COPYING THE FACES:
temp_wall_primitives = ent.add_group # create an empty group to receive faces mod.definitions.each{|d| next if d.image? || d.group? || d.name!="WALL" d.entities.each{ |wall_primative_group| if wall_primative_group.layer.name == "WALL_PRIMITIVES" wall_primative_group.entities.each{ |wall_primative_group_entity| if wall_primative_group_entity.is_a? Sketchup;;Face puts wall_primative_group_entity new_face = temp_wall_primitives.entities.add_face(wall_primative_group_entity.vertices) end } end } }
I think this has to do with iterating through definitions rather than instances per this discussion. However, if I try to iterate through the actual instances placed in the model, I cannot figure out how to even get to the target group. See the ERROR or PROBLEM comments in the code below...
ent.each{ |all_ents| if all_ents.is_a? Sketchup;;ComponentInstance next if all_ents.definition.name!="WALL" #puts all_ents.definition.name #all_ents.entities.each{ |all_comps| #ERROR; undefined method `entities' for #<Sketchup;;ComponentInstance;0x007fb00ab02b08> #all_ents.each{ |all_comps| #ERROR; undefined method `each' for #<Sketchup;;ComponentInstance;0x007fb00ab02b08> all_ents.parent.entities.each{ |all_comps| #PROBLEM; just pops me back to the top level because the parent is the model! puts all_comps.definition.name } end }
Please help!
-
@hank said:
What I would like to do is go into each component instance and copy the group ...
You cannot "go into an instance" really, when you double-click manually you are actually editing the definition's entities collection. Instances do not have their own entities collection. The model engine just renders "display" copies using the definition's entities.
@hank said:
on the "WALL_PRIMITIVES" layer
You should come to understand that the originators of SketchUp chose a poor word "layers", as in SketchUp they are not geometric entity collections at all. Therefore no entities can be "ON" any layer.
The objects that SketchUp calls layers are just display property sheets can can be shared by multiple entities, so that all those objects "associated" / "assigned to" a layer will share the same display behavior(s).@hank said:
to the root model context (I think this would be called Sketchup.active_model).
The object reference of the root entities collection, is returned by:
Sketchup.active_model.entities
-
@sdmitch: Thank you. This worked mostly, successfully copying the groups out to the model, however the transformations did not seem to make it. Of the 3 test "WALL" components in my file, one group was the correct size but moved, the other two were the wrong size AND moved.
Also,
ent = @mod.active_entities
returned undefined method `active_entities' for nil:NilClass so I changed it to
ent = mod.active_entities
to get the script to run. Am I missing something about the @? Which I think means you are calling an "instance" variable?
@Dan Rathbun: Thank you. I am just using the layer as an easy selector for the groups I want within the component. Do you recommend another way?
-
If your start up method defines
mod=Sketchup.active_model
then that reference 'mod
' is only used inside that method - no other methods 'see' it.
Of course if you don't need multiple methods then a simple variable will suffice.But if your start up method defines
@mod=Sketchup.active_model
then that reference '@mod
' is then accessible in all other methods in that module/class, without having to define it again in each method. Used in more complex code where there can be several methods doing various operations that need to be 'coordinated'...A @variable is also remembered across uses of the same 'module' - so it's useful for remembering previous dialog entries during that session etc - as there is only one instance of the module per session...
However, since launching a 'class' always makes a new instance of itself, any @variable it defines only exists that one use - although it is accessible across that class's methods it vanishes as the code completes.
But there is another type - @@variable - which you set up in the class's code outside of any methods, so it is defaulted as the code is initially loaded, and then you use it inside methods, so in this way you can remember the class's variables across uses, e.g. to remember previous dialog entries during a session... although of course you wouldn't use it for the active_model as that can vary during a session and a @variable is more appropriate...
-
You were on the right track with method#1. Once you have the definition, you need to iterate the instances of that definition. When making the copy, you need to apply the transformations of both the component instance and the group in order to have the copy be the same as the original.
mod = Sketchup.active_model ent = mod.active_entities mod.definitions.each{|d| next if d.image? || d.group? || d.name!="WALL" # skip images, groups, and any component not named "WALL" d.instances.each{|ci| ci.definition.entities.each{ |wall_primative_group| if wall_primative_group.layer.name == "WALL_PRIMITIVES" # only proceed with groups on target layer group_copy = ent.add_instance(wall_primative_group.entities.parent, wall_primative_group.transformation*ci.transformation) group_copy.name = 'WALL_PRIMITIVES' end } } }
-
@hank said:
@sdmitch: Thank you. This worked mostly, successfully copying the groups out to the model, however the transformations did not seem to make it. Of the 3 test "WALL" components in my file, one group was the correct size but moved, the other two were the wrong size AND moved.
Also,
ent = @mod.active_entities
returned undefined method `active_entities' for nil:NilClass so I changed it to
ent = mod.active_entities
to get the script to run. Am I missing something about the @? Which I think means you are calling an "instance" variable?
@Dan Rathbun: Thank you. I am just using the layer as an easy selector for the groups I want within the component. Do you recommend another way?
Sorry about that. I always use @variables as a habit and just missed removing that one. Looks like I got the 'transformation' order wrong which had no effect on my un-rotated un-scaled test wall. Try this one.
mod = Sketchup.active_model ent = mod.active_entities mod.definitions.each{|d| next if d.image? || d.group? || d.name!="WALL" # skip images, groups, and any component not named "WALL" d.instances.each{|ci| ci.definition.entities.each{ |wall_primative_group| if wall_primative_group.layer.name == "WALL_PRIMITIVES" # only proceed with groups on target layer group_copy = ent.add_instance(wall_primative_group.entities.parent,ci.transformation*wall_primative_group.transformation) group_copy.name = 'WALL_PRIMITIVES_COPY' end } } }
-
-
@hank said:
**@Dan Rathbun:**I am just using the layer as an easy selector for the groups I want within the component.
This is fine. Ie, using the layer property as a filter.
@hank said:
Do you recommend another way?
I recommend rereading what I wrote. It was just general information (triggered by incorrect terminology you chose to use in an earlier post.)
Advertisement