Copy a Group within a Component in Ruby, preserve location  Topic is solved

Copy a Group within a Component in Ruby, preserve location

Postby hank » Mon Apr 03, 2017 4:03 am

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...

Code: Select all
mod = Sketchup.active_model
ent = mod.entities

failed method # 1 - COPYING THE GROUP:

Code: Select all
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:

Code: Select all
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...

Code: Select all
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!
0

hank 
 

Re: Copy a Group within a Component in Ruby, preserve locati

Postby sdmitch » Mon Apr 03, 2017 3:10 pm

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.
Code: Select all
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
    }
  }
}
1
Last edited by sdmitch on Tue Apr 04, 2017 3:13 pm, edited 1 time in total.
Nothing is worthless, it can always be used as a bad example.

http://sdmitch.blogspot.com/
User avatar
sdmitch 
PluginStore Author
PluginStore Author
 

Re: Copy a Group within a Component in Ruby, preserve locati

Postby Dan Rathbun » Tue Apr 04, 2017 12:55 am

hank wrote: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 wrote: 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 wrote: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
1
    I'm not here much anymore. But a PM will fire email notifications.
    User avatar
    Dan Rathbun 
    PluginStore Author
    PluginStore Author
     

    Re: Copy a Group within a Component in Ruby, preserve locati

    Postby hank » Tue Apr 04, 2017 10:07 am

    @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,
    Code: Select all
    ent = @mod.active_entities

    returned undefined method `active_entities' for nil:NilClass so I changed it to
    Code: Select all
    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?
    0

    hank 
     

    Re: Copy a Group within a Component in Ruby, preserve locati

    Postby TIG » Tue Apr 04, 2017 12:49 pm

    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...
    1
    TIG
    User avatar
    TIG 
    Global Moderator
     

    Re: Copy a Group within a Component in Ruby, preserve locati  Topic is solved

    Postby sdmitch » Tue Apr 04, 2017 3:31 pm

    hank wrote:@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,
    Code: Select all
    ent = @mod.active_entities

    returned undefined method `active_entities' for nil:NilClass so I changed it to
    Code: Select all
    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.
    Code: Select all
    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
        }
      }
    }
    1
    Nothing is worthless, it can always be used as a bad example.

    http://sdmitch.blogspot.com/
    User avatar
    sdmitch 
    PluginStore Author
    PluginStore Author
     

    Re: Copy a Group within a Component in Ruby, preserve locati

    Postby hank » Wed Apr 05, 2017 3:43 pm

    @sdmitch: That was it! Thank you - makes sense now. Much appreciated!

    @TIG: Thank you for the detailed explanation!
    0

    hank 
     

    Re: Copy a Group within a Component in Ruby, preserve locati

    Postby Dan Rathbun » Wed Apr 05, 2017 5:50 pm

    hank wrote:@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 wrote: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.)
    0
      I'm not here much anymore. But a PM will fire email notifications.
      User avatar
      Dan Rathbun 
      PluginStore Author
      PluginStore Author
       

      SketchUcation One-Liner Adverts

      by Ad Machine » 5 minutes ago



      Ad Machine 
      Robot
       



       

      Return to Developers' Forum

      Who is online

      Users browsing this forum: No registered users and 2 guests

      Visit our sponsors: