• Login
sketchucation logo sketchucation
  • Login
🤑 SketchPlus 1.3 | 44 Tools for $15 until June 20th Buy Now

Copy a Group within a Component in Ruby, preserve location

Scheduled Pinned Locked Moved Developers' Forum
8 Posts 4 Posters 1.9k Views 4 Watching
Loading More Posts
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • H Offline
    hank
    last edited by 3 Apr 2017, 03:03

    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!

    1 Reply Last reply Reply Quote 0
    • D Offline
      Dan Rathbun
      last edited by 3 Apr 2017, 23:55

      @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

      I'm not here much anymore.

      1 Reply Last reply Reply Quote 0
      • H Offline
        hank
        last edited by 4 Apr 2017, 09:07

        @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?

        1 Reply Last reply Reply Quote 0
        • TIGT Online
          TIG Moderator
          last edited by 4 Apr 2017, 11:49

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

          TIG

          1 Reply Last reply Reply Quote 0
          • sdmitchS Offline
            sdmitch
            last edited by 4 Apr 2017, 14:13

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

            Nothing is worthless, it can always be used as a bad example.

            http://sdmitch.blogspot.com/

            1 Reply Last reply Reply Quote 0
            • sdmitchS Offline
              sdmitch
              last edited by 4 Apr 2017, 14:31

              @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
                  }
                }
              }
              
              

              Nothing is worthless, it can always be used as a bad example.

              http://sdmitch.blogspot.com/

              1 Reply Last reply Reply Quote 0
              • H Offline
                hank
                last edited by 5 Apr 2017, 14:43

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

                @TIG: Thank you for the detailed explanation!

                1 Reply Last reply Reply Quote 0
                • D Offline
                  Dan Rathbun
                  last edited by 5 Apr 2017, 16:50

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

                  I'm not here much anymore.

                  1 Reply Last reply Reply Quote 0
                  • 1 / 1
                  1 / 1
                  • First post
                    1/8
                    Last post
                  Buy SketchPlus
                  Buy SUbD
                  Buy WrapR
                  Buy eBook
                  Buy Modelur
                  Buy Vertex Tools
                  Buy SketchCuisine
                  Buy FormFonts

                  Advertisement