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_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 -
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_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))
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_positions
first run
make_2_instances_nested_transformed
and thenfind_instances_and_print_global_positions
on 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_transformation
seems 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 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
-
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 theGroup
andComponentInstance
subclasses.) IE, they got erroneously added to ALLSketchup::Drawingelement
subclasses. 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::Group
andSketchup::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.
Advertisement