Question about edit_transform
- 
 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
- 
 The Outliner would let a user dig straight into any instance - without going through each step. The edit_transformis 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
- 
 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? 
- 
 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. 
- 
 Thanks ThomThom, let me know what you find out. Dan 
- 
 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 theprint_geometrymethod 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 outSketchup.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))
 enddef 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(', ')}]"
 enddef print_transformation(name, t) 
 puts "#{name} = #{t.origin}"
 enddef 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`
- 
 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_positionsfirst run make_2_instances_nested_transformed
 and thenfind_instances_and_print_global_positionson any active contextthis only works if instances are unique, this is just an idea 
 for depth greater than 2 I do not think it works,local_transformationseems uncertain when this within instances of interest ...
 (google translator)
- 
 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? 
- 
 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]
 okHowever, 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]
 okIf 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 correctSketchup.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 incorrectSketchup.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
- 
 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
- 
 @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 theGroupandComponentInstancesubclasses.) IE, they got erroneously added to ALLSketchup::Drawingelementsubclasses. Those methods are meaningless with respect to primitive entity classes likeEdge.They should (and may in the future,) be defined within a mixin module, and then mixed ONLY into Sketchup::GroupandSketchup::ComponentInstanceclasses.@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_transformsand$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. 
Advertisement


 
                             
                             
                             
                             
                             
                             
                            