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

    Question about edit_transform

    Scheduled Pinned Locked Moved Developers' Forum
    11 Posts 4 Posters 1.8k 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.
    • D Offline
      danmacumber
      last edited by

      I have some questions about edit_transform that I have never been able to
      fully figure out. I work on a plug-in that uses multiply nested groups. I
      keep track of the edit_transform each time the active_path changes
      using ModelObserver.onActivePathChanged.

      Initially, I assumed that the active path could only change one path at a
      time (e.g. either a push or a pop relative to the current active path).
      However, I have found that sometimes the active path can change multiple
      steps at a times with no intermediate calls to
      ModelObserver.onActivePathChanged. For example:

      [Group1, SubGroup1] to []

      or

      [Group1, SubGroup1] to [Group2, SubGroup2]

      I keep track of an array of edit transforms and would really like to be
      able to recreate the edit transform given the active path. Is that
      possible? If so is there a way to get an array of edit transforms
      correspond to the active path array (i.e. the edit transform for each entry
      in the active path)?

      In case I am asking too much, any better description of what the edit_transform is would be very helpful. The SketchUp API documentation is not really complete enough for me especially with respect to nested groups.

      Thanks a lot,
      Dan

      1 Reply Last reply Reply Quote 0
      • thomthomT Offline
        thomthom
        last edited by

        The Outliner would let a user dig straight into any instance - without going through each step.

        The edit_transform is the total of the transformation for all the open instances.

        If you need into about each step in the path you can inspect model.active_path:
        http://www.sketchup.com/intl/en/developer/docs/ourdoc/model#active_path

        Thomas Thomassen — SketchUp Monkey & Coding addict
        List of my plugins and link to the CookieWare fund

        1 Reply Last reply Reply Quote 0
        • D Offline
          danmacumber
          last edited by

          Thanks ThomThom, I still don't quite see how to solve my problem. When I am editing a group, the transformation returned for each group (current group or any parent) in the active_path is identity. So if I am editing a group how can I get its parent's transformation?

          1 Reply Last reply Reply Quote 0
          • thomthomT Offline
            thomthom
            last edited by

            Ah, I see what you mean... even those transformations are being transformed when you open the groups... hm... I'd have to consult with the core team on this one.

            Thomas Thomassen — SketchUp Monkey & Coding addict
            List of my plugins and link to the CookieWare fund

            1 Reply Last reply Reply Quote 0
            • D Offline
              danmacumber
              last edited by

              Thanks ThomThom, let me know what you find out.

              Dan

              1 Reply Last reply Reply Quote 0
              • D Offline
                danmacumber
                last edited by

                Here is my best attempt to clearly illustrate my problem. Load the Ruby code attached at the bottom of this post. Run the method make_geometry, this will clean everything in your model and create two groups Group 1 and Group 2, Group 2 is nested inside of Group 1. Group 1 is translated 10 m in the X direction, Group 2 is translated 10 m in the Y direction. Run the print_geometry method from the top level, then from within Group 1, then from within Group 2. You will see this output:

                ` print_geometry
                active_path = []
                Group 1 transformation = (393.700787", 0", 0")
                Group 2 transformation = (0", 393.700787", 0")
                Edit transformation = (0", 0", 0")

                print_geometry
                active_path = [Group 1]
                Group 1 transformation = (0", 0", 0")
                Group 2 transformation = (393.700787", 393.700787", 0")
                Edit transformation = (393.700787", 0", 0")

                print_geometry
                active_path = [Group 1, Group 2]
                Group 1 transformation = (0", 0", 0")
                Group 2 transformation = (0", 0", 0")
                Edit transformation = (393.700787", 393.700787", 0")`

                At the top level, I can figure out the local transformation for both Group 1 and Group 2. At the second level (inside Group 1), I can get Group 1's transformation from the edit transform and I can get Group 2's transformation by applying the inverse of Group 1's transformation. However, from the third level (inside Group 2) there is information lost. I cannot figure out which part of the edit transform comes from Group 1's transformation and which part comes from Group 2's. Is there a solution to get transformations for both groups when we are inside of Group 2? I had been storing data in my own array in an onActivePathChanged observer. However, this falls apart when the active path changes by more than a single step.

                I have not seen a good answer to this question in any other post: http://sketchucation.com/forums/viewtopic.php?f=323%26amp;t=30067, http://sketchucation.com/forums/viewtopic.php?f=180%26amp;t=26212. Is there just no solution for this?

                ` def make_geometry

                clear everything out

                Sketchup.active_model.entities.clear!

                add the parent group

                $group1 = Sketchup.active_model.entities.add_group
                $group1.name = "Group 1"

                set parent’s transformation

                $group1.transformation = Geom::Transformation.translation(Geom::Point3d.new(10.m, 0, 0))

                add some points to the parent group

                $group1.entities.add_cpoint(Geom::Point3d.new(0.m, 0.m, 0.m))
                $group1.entities.add_cpoint(Geom::Point3d.new(5.m, 5.m, 3.m))

                add the child group

                $group2 = $group1.entities.add_group
                $group2.name = "Group 2"

                set child’s transformation

                $group2.transformation = Geom::Transformation.translation(Geom::Point3d.new(0, 10.m, 0))

                add some points to the child group

                $group2.entities.add_cpoint(Geom::Point3d.new(0.m, 0.m, 0.m))
                $group2.entities.add_cpoint(Geom::Point3d.new(5.m, 5.m, 3.m))
                end

                def print_active_path()
                result = []
                active_path = Sketchup.active_model.active_path
                active_path.each {|p| result << p.name} if active_path
                puts "active_path = [#{result.join(', ')}]"
                end

                def print_transformation(name, t)
                puts "#{name} = #{t.origin}"
                end

                def print_geometry
                print_active_path()
                print_transformation("Group 1 transformation", $group1.transformation)
                print_transformation("Group 2 transformation", $group2.transformation)
                print_transformation(" Edit transformation", Sketchup.active_model.edit_transform)
                nil
                end`

                1 Reply Last reply Reply Quote 0
                • D Offline
                  dacastror
                  last edited by

                  tip: never use global variables ($)

                  I think something like this is what you want

                  
                  def overall_transformation(instance)
                    model = Sketchup.active_model
                    path = model.active_path ? model.active_path ; []
                    indi = path.index(instance)
                    if indi
                      return model.edit_transform if indi == path.size-1
                      tr = path[0].local_transformation
                      for i in 1..indi
                        tr = path[i].local_transformation * tr
                      end
                    else
                      tr = instance.transformation
                      while (instance.parent.class != Sketchup;;Model)
                        instance = instance.parent.instances[0]
                        tr = instance.transformation * tr
                      end
                    end
                    return tr 
                  end
                  
                  def find_instances
                    instancias = []; instancias.clear
                    mod = Sketchup.active_model
                    definitions = mod.definitions
                    for definition in definitions
                      instances = definition.instances
                      if instances.length > 0
                        entity = instances[0]
                        attr = entity.get_attribute "dic", "key"
                        instancias << entity if attr
                      end
                    end
                    return instancias
                  end
                    
                  def make_instance(entities,transformation)
                    p1 = [0,0,0]; p2 = [50,50,50]
                    group = entities.add_group
                    group.entities.add_line p1, p2
                    group.transform! transformation
                    return group
                  end
                  
                  
                  def make_2_instances_nested_transformed
                    model  = Sketchup.active_model
                    return "had been previously created" if find_instances.size>0
                    tr1    = Geom;;Transformation.translation [100,0,0]
                    tr2    = Geom;;Transformation.translation [0,100,0]
                    ents1  = model.entities
                    group1 = make_instance(ents1,tr1)
                    ents2  = group1.entities
                    group2 = make_instance(ents2,tr2)
                    group1.set_attribute "dic", "key", "info"
                    group2.set_attribute "dic", "key", "info"
                    "ok"
                  end
                  
                  def find_instances_and_print_global_positions
                    instances = find_instances
                    group1 = instances[0]; group2 = instances[1]
                    origin1 = overall_transformation(group1).origin
                    origin2 = overall_transformation(group2).origin
                    puts "Group 1 global origin -> " + origin1.to_a.inspect
                    puts "Group 2 global origin -> " + origin2.to_a.inspect
                    "ok"
                  end
                    
                  #make_2_instances_nested_transformed
                  #find_instances_and_print_global_positions
                  
                  

                  first run make_2_instances_nested_transformed
                  and then find_instances_and_print_global_positions on any active context

                  this only works if instances are unique, this is just an idea
                  for depth greater than 2 I do not think it works, local_transformation seems uncertain when this within instances of interest ...
                  (google translator)

                  1 Reply Last reply Reply Quote 0
                  • D Offline
                    danmacumber
                    last edited by

                    Thank you dacastror, local_transformation seems to work. Does anyone have any information about local_transformation since it does not seem to be in the docs, http://www.sketchup.com/intl/en/developer/docs/methods#index_l? This post indicates that this method is provided by the Dynamic Components extension, http://sketchucation.com/forums/viewtopic.php?f=180%26amp;t=33182%26amp;start=15#p293542. Is there any documentation for the Dynamic Components extension?

                    In our plug-in, we only ever have two levels of nested groups and all groups are unique instances. So I guess this should work for us? As long as the SketchUp team doesn't remove the method?

                    1 Reply Last reply Reply Quote 0
                    • D Offline
                      danmacumber
                      last edited by

                      I have played around with dacastror's solution and I think there is still an underlying issue in SketchUp when the active_path changes more than one level at a time. I extended dacastror's code to include additional groups and components for testing. I also added some "handle" groups under each group and component that can be selected in the outliner to immediately make the parent context active. Under most situations find_instances_and_print_global_positions returns the correct value:

                      @unknownuser said:

                      Group 1 global origin -> [100.0, 0.0, 0.0]
                      Group 2 global origin -> [100.0, 100.0, 0.0]
                      Instance 3 global origin -> [100.0, -100.0, 0.0]
                      Group 4 global origin -> [-100.0, 0.0, 0.0]
                      Group 5 global origin -> [-100.0, 100.0, 0.0]
                      Instance 6 global origin -> [-100.0, -100.0, 0.0]
                      ok

                      However, if I start at the top level of the model, then make Instance 3 active by selecting the handle group 'Group 1->Instance 3 <Definition 3>->handle' in the outliner, find_instances_and_print_global_positions returns:

                      @unknownuser said:

                      Group 1 global origin -> [0.0, 0.0, 0.0]
                      Group 2 global origin -> [100.0, 100.0, 0.0]
                      Instance 3 global origin -> [100.0, -100.0, 0.0]
                      Group 4 global origin -> [-100.0, 0.0, 0.0]
                      Group 5 global origin -> [-100.0, 100.0, 0.0]
                      Instance 6 global origin -> [-100.0, -100.0, 0.0]
                      ok

                      If I start at the top level, then enter Group 1, then enter Instance 3, I get the correct result.

                      @unknownuser said:

                      when entering Group 1, then Instance 3, local_transformation of Group 1 is correct

                      Sketchup.active_model.active_path
                      [#Sketchup::Group:0x0000000d876d80, #Sketchup::ComponentInstance:0x0000000d8756d8]
                      Sketchup.active_model.active_path[0].local_transformation.to_a.inspect
                      [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 100.0, 0.0, 0.0, 1.0]

                      when jumping from top level to Instance 3, local_transformation of Group 1 is incorrect

                      Sketchup.active_model.active_path
                      [#Sketchup::Group:0x0000000d876d80, #Sketchup::ComponentInstance:0x0000000d8756d8]
                      Sketchup.active_model.active_path[0].local_transformation.to_a.inspect
                      [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0]

                      I get similar results if I switch between other levels of the hierarchy in odd ways. I wonder if the implementation of local_transformation depends on the active path observer? I only seem to get these issues if I change the active path multiple elements at time.

                      def overall_transformation(instance)
                        model = Sketchup.active_model
                        path = model.active_path ? model.active_path ; []
                        
                        parents = []
                        parent = instance.parent
                        while (parent.class != Sketchup;;Model)
                          parents << parent
                          if parent.class == Sketchup;;ComponentDefinition
                            parent = parent.instances[0]
                          else
                            parent = parent.parent
                          end
                        end
                        
                        indi = path.index(instance)
                        
                        # if instance is in path
                        if indi
                          
                          # if instance is last entry in path
                          return model.edit_transform if indi == path.size-1
                          
                          # compute transformation up to and including instance
                          tr = path[0].local_transformation
                          for i in 1..indi
                            tr = path[i].local_transformation * tr
                          end
                          
                        else
                          # initialize with instance transformation
                          tr = instance.transformation
                          while (instance.parent.class != Sketchup;;Model)
                            # get parent
                            if instance.parent.class == Sketchup;;ComponentDefinition
                              instance = instance.parent.instances[0]
                            else
                              instance = instance.parent
                            end
                            
                            # is parent in path
                            indi = path.index(instance)
                            if indi
                              # when parent is in active path, it's transformation is just identity right?
                              #puts "parent found #{instance.transformation.to_a.inspect}"
                              tr = instance.transformation * tr
                            else
                              tr = instance.transformation * tr
                            end
                          end
                        end
                        
                        return tr
                      end
                      
                      def find_instances
                        instancias = []; instancias.clear
                        mod = Sketchup.active_model
                        definitions = mod.definitions
                        for definition in definitions
                          instances = definition.instances
                          if instances.length > 0
                            entity = instances[0]
                            attr = entity.get_attribute "dic", "key"
                            instancias << [attr, entity] if attr
                          end
                        end
                        # sort by key
                        instancias.sort {|x,y| x[0] <=> y[0]}
                        return instancias
                      end
                       
                      def make_group(entities,transformation,group_name)
                        p1 = [0,0,0]; p2 = [50,50,50]
                        group = entities.add_group
                        group.name = group_name
                        group.entities.add_line p1, p2
                        group.transform! transformation
                        return group
                      end
                      
                      # this group is not really of interest, just gives us a handle in the outliner to make parent active 
                      def make_handle_group(entities)
                        p1 = [0,0,0]; p2 = [50,50,50]
                        group = entities.add_group
                        group.name = "handle"
                        edge = group.entities.add_line p1, p2
                       	edge.visible = false
                        return group
                      end
                      
                      def make_instance(entities,transformation,definition_name,instance_name)
                        p1 = [0,0,0]; p2 = [50,50,50]
                        definition = Sketchup.active_model.definitions.add(definition_name)
                        definition.entities.add_line p1, p2
                        make_handle_group(definition.entities)
                        instance = entities.add_instance(definition, transformation)
                        instance.name = instance_name
                        return instance
                      end
                      
                      def make_instances
                        model  = Sketchup.active_model
                        return "had been previously created" if find_instances.size>0
                        model.definitions.purge_unused
                        tr1    = Geom;;Transformation.translation [100,0,0]
                        tr2    = Geom;;Transformation.translation [0,100,0]
                        tr3    = Geom;;Transformation.translation [0,-100,0]
                        group1 = make_group(model.entities,tr1,"Group 1"); make_handle_group(group1.entities)
                        group2 = make_group(group1.entities,tr2,"Group 2"); make_handle_group(group2.entities)
                        instance3 = make_instance(group1.entities,tr3,"Definition 3","Instance 3")  
                        group1.set_attribute "dic", "key", "Group 1"
                        group2.set_attribute "dic", "key", "Group 2"
                        instance3.set_attribute "dic", "key", "Instance 3"
                        
                        tr4    = Geom;;Transformation.translation [-100,0,0]
                        tr5    = Geom;;Transformation.translation [0,100,0]
                        tr6    = Geom;;Transformation.translation [0,-100,0]
                        group4 = make_group(model.entities,tr4,"Group 4"); make_handle_group(group4.entities)
                        group5 = make_group(group4.entities,tr5,"Group 5"); make_handle_group(group5.entities)
                        instance6 = make_instance(group4.entities,tr6,"Definition 6","Instance 6")
                        group4.set_attribute "dic", "key", "Group 4"
                        group5.set_attribute "dic", "key", "Group 5"
                        instance6.set_attribute "dic", "key", "Instance 6"
                        "ok"
                      end
                      
                      def find_instances_and_print_global_positions
                        instances = find_instances
                        instances.each do |instance|
                          origin = overall_transformation(instance[1]).origin
                          puts "#{instance[0]} global origin -> " + origin.to_a.inspect
                        end
                        "ok"
                      end
                       
                      #make_instances
                      #find_instances_and_print_global_positions
                      
                      1 Reply Last reply Reply Quote 0
                      • D Offline
                        danmacumber
                        last edited by

                        For reference this is the issue that this causes users of OpenStudio:

                        https://unmethours.com/question/1625/wall-flying-every-where/
                        https://github.com/NREL/OpenStudio/issues/1350

                        1 Reply Last reply Reply Quote 0
                        • Dan RathbunD Offline
                          Dan Rathbun
                          last edited by

                          @danmacumber said:

                          This post indicates that this method is provided by the Dynamic Components extension.

                          Correct.

                          However, those methods that are listed as added to Sketchup::Drawingelement, that have to do with transformations, should not have been added at that level of the class hierarchy (in order to just add them to the Group and ComponentInstance subclasses.) IE, they got erroneously added to ALL Sketchup::Drawingelement subclasses. Those methods are meaningless with respect to primitive entity classes like Edge.

                          They should (and may in the future,) be defined within a mixin module, and then mixed ONLY into Sketchup::Group and Sketchup::ComponentInstance classes.

                          @danmacumber said:

                          Is there any documentation for the Dynamic Components extension?

                          Not at this time.

                          @danmacumber said:

                          I only seem to get these issues if I change the active path multiple elements at time. ... I get similar results if I switch between other levels of the hierarchy in odd ways.

                          I wonder if the implementation of local_transformation() depends on the active path observer?

                          I do "believe" it does. I think it does similar to what you described. It (the "DCX") saves transforms into hashes (using the object reference as the key.) I think they are global collection objects named $local_edit_transforms and $global_edit_transforms.

                          So you could write some watcher code into your tests that watch those collections. (Just do not write code that changes them or the DCs could stop working.)

                          @danmacumber said:

                          In our plug-in, we only ever have two levels of nested groups and all groups are unique instances. So I guess this should work for us? As long as the SketchUp team doesn't remove the method?

                          This would require that your users have the DC extension loaded, or your extension might have to require the dc loader script explicitly.

                          I'm not here much anymore.

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

                          Advertisement