Find the global position of a Vertex in a Group/Component
-
@jessejames said:
There is no difference in finding the "world coordinate" of a vertex contained in a collection whether or not the "collection" is "open" or "closed". If it's nested yes, but only a minor difference in the form of recursion.
SU changes the co-ordiates when you open a group/component. When a group or component is open SU returns global co-ordinates for the entities in that context.
-
@gbabcock said:
The problem is how to get the parents starting from an edge without walking the entire Group/Component/Model from the top-down.
The only time you can avoid that is if you're making a Tool using the PickHelper to pick out the entity. PickHelper also return the path to that entity.
But if you're not making a point and click tool - then the only way is to traverse the entire model. It's one of the major complaints about the SketchUp API.
-
jessejames, thats not quite what I was after, but thanks for the post!
thomthom, thanks for the feedback. I'll check out PickHelper in any case, sounds interesting.
BTW, the code snippet I posted does work, I was testing it last night, and it doesn't traverse the model. The only caveat was that I had to use group.make_unique on copies of groups due to the bug discussed on this forum.
Glenn
-
@gbabcock said:
BTW, the code snippet I posted does work, I was testing it last night, and it doesn't traverse the model.
What was your testcase? With group or components? Did you try with scaled instances as well?
@gbabcock said:
The only caveat was that I had to use group.make_unique on copies of groups due to the bug discussed on this forum.
Which one was that? Getting the correct parent for a group?
http://forums.sketchucation.com/viewtopic.php?f=180&t=19765 -
I'd avoid making groups unique. I some times get models made by others where groups have been used as components. Provided the groups have not been made unique I can still recover them, by using Selection Toys.
-
@thomthom said:
What was your testcase? With group or components? Did you try with scaled instances as well?
I tested Groups, nested Groups, scaled Groups, rotated Groups, translated Groups, Group copies, Components (single only). Works for all of them.
I've updated my Position Explorer tool, see attached. I'll post the update in the Plugins forum.
@thomthom said:
Which one was that?
http://forums.sketchucation.com/viewtopic.php?f=180&t=14062&p=105782
Glenn
-
@thomthom said:
I'd avoid making groups unique. I some times get models made by others where groups have been used as components. Provided the groups have not been made unique I can still recover them, by using Selection Toys.
So how do I work around the bug? If I make a copy of a group and immediately try to get it's position I get the original's transformation.
Glenn
-
@unknownuser said:
#returns an array of Point3d objects that equal the global position of the vertices in an edge
#currently only gets the first parent instance, components may have many instancesYou're not dealing with components with many instances? You only pick the first instance?
-
@thomthom said:
You're not dealing with components with many instances? You only pick the first instance?
I am, I just haven't gotten that far with the tool yet!
-
@gbabcock said:
@thomthom said:
You're not dealing with components with many instances? You only pick the first instance?
I am, I just haven't gotten that far with the tool yet!
Well, that is a key major problem. Getting the correct instance. It's why traversing the parent won't work, as you only get the definition, but no way of getting the right instance.
If you make components work, then you make groups with group copies work. They are the same thing under the hood. -
Thanks, that's helpful. I'll play around with that.
-
@thomthom said:
Well, that is a key major problem. Getting the correct instance...
OK, I see now. It's not a true hierarchy, since an element (vertex, face, edge, etc.) can be in more than one instance. Parent only gets you the Definition, with no way to get the correct Instance, as you said.
Thanks for helping me understand!
-
Only way is to map the whole model, going from Model and up. Which is just a brute force way to do it.
-
@thomthom said:
SU changes the co-ordiates when you open a group/component. When a group or component is open SU returns global co-ordinates for the entities in that context.
It seems Tim Toady is more prevalent that i had originally feared!
PS: Before some hot shot notices i made a mistake in accessing the origin using
collection..transformation[-1]
Since the transformation is a 16 element array an NOT a 4 element array of 4 element sub arrays that code will only return the last float.
-
@thomthom said:
Only way is to map the whole model, going from Model and up. Which is just a brute force way to do it.
Not really true. Its certainly non-trivial but LightUp does it . ie LightUp needs to find the transform of every instance of a Component called PointLightSource. Clearly starting at the top and walking down is "one way" buts its incredibly inefficient. Better is to get each instance (trivial) then work your way back up concatenating transforms as you go - and dealing with the fact that there can be many instances of Components as thomthom points out. Took a fair amount of head scratching but its all in lightcache.rb if you want to take a butchers.
Its invoked by
list = LightCache.flat(LightCache.walk(ent, ent.transformation))
which gives you back a list of transforms.Adam
-
Very interesting Adam. I'm glad to be proven wrong.
I will for sure poke about that code of yours. Is it ok with you if I adapt it to a generic method and add it to my generic library shared between my plugins?
-
@adamb said:
Clearly starting at the top and walking down is "one way" buts its incredibly inefficient. Better is to get each instance (trivial) then work your way back up concatenating transforms as you go - and dealing with the fact that there can be many instances of Components as thomthom points out. Adam
Exactly what I'm trying to do! Thanks, Adam, I'll check this out.
-
OK, I think I'm getting a clearer picture now. Let me sum it up to make sure.
Since we can have multiple instances of a Group/Component, there is a One-to-Many relationship between a Vertex and Transformations:
Vertex->ComponentDefinition->ComponentInstances->ComponentInstance->Transformation
Therefore, to get the global position of a Vertex you need BOTH the Vertex (which is in ComponentDefinition) AND the specific ComponentInstance you are evaluating. From there you can walk UP the hierarchy of ComponentInstances and get their Transformations to apply to the Vertex.So in Ruby we have:
Sketchup.active_model #top of model
Sketchup.active_model.definitions #returns DefinitionList
Sketchup.active_model.definitions[n] #returns ComponentDefinition[n] from array
Sketchup.active_model.definitions[n].instances[n] #returns ComponentInstance[n] from arrayYou can get a quick picture of this in SU with:
Sketchup.active_model.definitions.each {|definition| puts "#{definition} contains #{definition.instances}\n" }
-
Adam, that code returns the transformation of all the copies of that instance? But no way to track back a single path to the model, like you get with PickHelper?
-
@gbabcock said:
From there you can walk UP the hierarchy of ComponentInstances
Well, not quite...
The Parent of a ComponentInstance is a ComponentDefinition, which can exist in more than one ComponentInstance (for example, if you have multiple instances of a Component that has nested Components). So you can't even walk up the hierarchy of ComponentInstances.
But walking down works well! My use case is where I have selected a Group/Component (but not opened it) and need the global position of every Vertex. With limited testing performed, this code seems to give an accurate position report:
#get vertices def Start #get vertices verts=[] #initialize vertices array trans_h=[] #initialize transformation array use to store hierarchy of transformations verts=createVerticesArray(sel,trans_h,verts) end def createVerticesArray(sel,trans_h,verts) sel.each{|ent| if (ent.is_a? Sketchup;;Group) || (ent.is_a? Sketchup;;ComponentInstance) trans_h.push(ent.transformation) #push the Group/Component tranformation onto the array ents=ent.definition.entities #get the entities in this Group/Component instance verts=createVerticesArray(ents, trans_h, verts) #recurse elsif (ent.is_a? Sketchup;;Edge) ent.vertices.each{|vert| #begin analysis of vertices in this edge puts vert if @debugFFD #get global position of the vertex by applying the hierarchy of transformations v_gpos=vert.position #returns local Point3d position of vertex puts v_gpos if @debugFFD flat_t=flatten(trans_h) #get the flattened transformation for the hierarchy puts flat_t if @debugFFD v_gpos.transform! flat_t #transform the vertex to get the global position vert.set_attribute("vert","gpos",v_gpos) verts.push(vert) } end } #verts now contains redundant verts. remove duplicates. verts.uniq! return verts end #thanks to Adam for the idea! def flatten(trans_h) #returns a flattened transformation from an array of transformations for the instance hierarchy flat_t=Geom;;Transformation.new #create an entity transformation object #apply the hierarchy of transformations to the entity transformation trans_h.each{|t| flat_t=flat_t* t } return flat_t end
It performs well too, though I'm sure it could be improved. I have used it on a component with ~8400 entities and 1720 vertices, and get the results back in 0.25 seconds consistently.
Glenn
Advertisement