Selecting Entities inside composite Entities
-
Hi all.... Me again (with a hard-to-put-in-text question, I'm afraid),
I'm trying to write a script that selects all Edges in a model that have exactly one Face attached to them. I've got the basics of the code right: it works fine, provided that the Edges that are being selected are in the same "hierarchical level" as the "level" that the call is being made from. That's possibly a confusing sentence; let me try to explain it by example. Suppose that I have selection = Sketchup.active_model.selection, and that top_level_entity = Sketchup.active_model.entities[0] is a Face. If I call selection.add top_level_entity, then there's no problem.
However, I seem to have a problem if I call selection.add nested_entity, where nested_entity is part of a composite Entity (e.g. Group, ComponentInstance). For example, if group_ent = Sketchup.active_model.entities[1] is a Group, then I'll have problems calling selection.add group_ent.entities[0] (suppose, just for the purpose of this example, that group_ent.entities[0] is a Face, but the behaviour is the same for any Entity). The call does "work" -- i.e., I don't get an error or a nil or anything. However, it exhibits some "weird" behaviour: in particular, Sketchup doesn't actually highlight the Face represented by group_ent.entities[0]; instead, it highlights "where the Face would be in the world coordinate system if you forgot to apply the Group's transformation". Again, trying to give an (overly simplified) example: suppose the Face is centered at [3,2,5] within the Group, and the Group itself is centered at [5,5,5], then this means that the the Face is actually located at [8,7,10] in the world coordinate system; however, selection.add is highlighting a "phantom Face" at [3,2,5] in the world coordinate system.
I haven't been able to figure out a way around this behaviour, programmatically. The only thing I have discovered is that selection.add seems to work if you're editing the deepest level Group/Component to which the Entity you want to select belongs. "Easy enough then," I figured. "All I have to do is programmatically tell Sketchup to edit the parent of the Entity I want to select." Unfortunately, although I found the call Sketchup.close_active, I can't seem to find the inverse method (something like Sketchup.active= or Sketchup.set_active).
I've looked in other places (including calling [Sketchup_class].methods on virtually every class in the Sketchup API that I've run across [fun exercise, but didn't produce what I wanted]), but I haven't found an answer to "is there an inverse to Sketchup.close_active?". More generally, I haven't seen a thread that deals with this "nested selection" problem. (I don't know if that's a bad sign or not.) I've thought of some other tricks to get Sketchup to select a nested Entity, but all of them are a little kludgey. For example, I've thought of creating a copy of the target Entity and adding that copy to the top-level model (maybe in a different Layer) and selecting that copy -- but now that means I've got duplicate Entities floating around. Other "solutions" I've come up with are similar slight-of-hand kludgey affairs.
If anyone has thoughts on either matter (nested selection in general, or Sketchup.set_active specifically), I'd be interested to hear them. Also, let me know if I need to elaborate on the description of the problem: it's one of those things that's really easy to describe if you're sitting next to the person, but comes out really incoherent when you try to explain it in text alone.
Thanks,
Kevin
-
You want to select all edges in the model that have just the one face.
###First; sort out basic geometry model=Sketchup.active_model ss=model.selection; ss.clear entities=model.entities entities.each{|e|ss.add(e) if e.typename=="Edge" and not e.faces[1]} ###Now; make a list of all groups and get any oner-edges groups=[]; entities.each{|e|groups.push(e) if e.typename=="Group"} ###Adds these to the selection. groups.each{|g|g.entities.each{|e|ss.add(e) if e.typename=="Edge" and not e.faces[1]}} ###Now go through the component definitions and do the same... instances=[]; entities.each{|e|instances.push(e) if e.typename=="ComponentInstance"} instances.each{|i|i.definition.entities.each{|e|ss.add(e) if e.typename=="Edge" and not e.faces[1]}}
You will note that this selects any edges in their 'original' location - rather than the current transformation... If you need that you need to delve into transformations a bit more...
-
Thanks very kindly for the reply, TIG.
I should maybe clarify a bit though.... I actually already have the "select all single-faced edges" part working (it's vaguely similar code to what you suggested, though with recursions to capture nested groups). As you noted though:
@unknownuser said:
You will note that this selects any edges in their 'original' location - rather than the current transformation... If you need that you need to delve into transformations a bit more...
That's actually exactly the question I was trying to get at in my original post (though in a very contorted way): I've been trying for about two weeks to get the Selection object to recognise and apply the transformation tree, but without any luck. I was therefore wondering if anyone had any clues how to get that part working.
Thanks again though, TIG.
Kevin
-
As an (unhappy) addendum to my original post, I've discovered that view.zoom nested_entity has similar behaviour. If you're editing the immediate parent to nested_entity when you call view.zoom, it works beautifully. However, if you call view.zoom nested_entity from any level higher than nested_entity's parent, Sketchup zooms in on what looks like a random location. It turns out, this "random" location is actually nested_entity's location within its Group/Component, without the transformations of the Group/Component having been applied.
Kevin
-
One you have got a list of a group's edges that have just one face why do you need to select them anyway ? You have them identified by their 'handle' and so you can manipulate them anyway - even when they are 'transformed'... e.g. e.erase! will erase them...
There seems to be no (easy) way to simulate the 'edit group' command, BUT you can set a shortcut e.g. 'Shift+Ctrl+Alt+G' to the 'edit group menu' item and then use 'win32ole.so' to run the key stroke(s) to make that group active and then edit its entities to make your selection and then close the group using close_active as you suggest... BUT it's pretty convoluted and would be PC dependant ?
-
Hi again TIG,
The selection is for visualisation purposes. That's a neat suggestion to use the win32ole library, although it's true that it would make it machine-dependent. Still, it might lead to spin-off thoughts. Meanwhile, I'll keep completely different visualisation solutions in mind.
Thanks again,
Kevin
-
For "visualisation purposes" you could try setting the view display to 'display edge by material', then get the edges' materials saved into a 2-part array, colouring them all say 'Orange' and then as you exit you'd loop back through and change them back to what they were before, and finally you set the view display as it started off ?
-
That's not a bad idea as an alternative, TIG. I've thought of something similar myself, though mine was admittedly less sophisticated. (I was just going to change the edge colours and throw away the original value.) I'll certainly add that to my growing list of fall-back plans.
Thanks again for all the input,
Kevin
Advertisement