How to find parent group in a model?


#1

In SketchUp Pro 2015, I’ve got a two ComponentInstances, contained within a group. When selecting a ComponentInstance, I want to be able to go up the heirarchy, looking at the parent groups. However, entity#parent is not working as I’d expect:

Sketchup.active_model.entities[0]
#<Sketchup::Group:0x000000086a2bd0>
Sketchup.active_model.entities[0].entities[0]
#<Sketchup::ComponentInstance:0x000000085a0bb0>
Sketchup.active_model.entities[0].entities[0].parent
#<Sketchup::ComponentDefinition:0x000000086a2c70>

As you can see above, the parent of a ComponentInstance gives me it’s definition instead of it’s parent. Is there another method for getting the container object?


Global bounding boxes
#2

Unfortunately, no simple way. SketchUp keeps track of outside-to-inside nesting because that’s what it needs to draw Entities, but not inside-to-outside, which the engine doesn’t need. Various people have tackled this problem, though none of the solutions are a simple one-liner. Perhaps one of them will chime in…


#3

Because definitions have entities collections, and instances do not.

What may be throwing you off (a bit) here, is that the Group class has an API “shortcut” method that is basically:

def entities()
  self.definition.entities
end

This is because groups are really “special” component instances, whose definitions are hidden from the listing in the Component Manager.
So groups (being instances) do not really own entities either. It is their definitions that “own” the entities collection.


Secondly, you are likely confounding two separate API methods of the same name. Just because they both use the name “parent” does not mean they do the same thing. (There is, at this time, at least 4 different “parent” methods in the API.)

So calling the parent upon an instance of the Sketchup::Entities collection class, can return different object references than calling the same method upon a Sketchup::Entity subclass instance. Likewise if called upon a Sketchup::AttributeDictionary object (which always returns an instance of a Sketchup::AttributeDictionaries collection.)


#4

All that being said, the easiest way to get the instance chain, is when the bottom instance is the active editing context.

Then you can use Sketchup::Model#active_path

But yet there is no way to (easily) set the current editing context in Ruby. The API defines a method to exit or back out of editing contexts, but not enter them.

So I believe that hacks are done .

You save the current selection, and the active context. Then use a system call to cause (simulate) a mouse click upon the object you want until the model.active_entities == target.definition.entities then get the active editing path from the method described above.

Afterward you do an undo n number of times, or back out of the editing context and restore the previous one.


#5

This may provide some ideas. There may be better methods, but I just map out the entire model.

This maps the entire model into an array of Instance Nodes which have a reference the ComponentInstance and its path (or parent Instances). From the path you can get to the parent instance, and also calculate the instance’s transformation in world coordinates.

Use a Hash instead of an Array for faster lookups. I included the Instance name to be able to find instances by name. You can include whatever data about the instances you need.

Example of a simple Node array:

[#<Node:0x0000000b6c7d60
  @ins=#<Sketchup::ComponentInstance:0x0000000b520430>,
  @name="Parent",
  @path=[]>,
 #<Node:0x0000000b6c74a0
  @ins=#<Sketchup::ComponentInstance:0x0000000b59acf8>,
  @name="Child 1",
  @path=[#<Sketchup::ComponentInstance:0x0000000b520430>]>,
 #<Node:0x0000000b6c6e10
  @ins=#<Sketchup::ComponentInstance:0x0000000b5d4390>,
  @name="Grand Child 1",
  @path=
   [#<Sketchup::ComponentInstance:0x0000000b520430>,
    #<Sketchup::ComponentInstance:0x0000000b59acf8>]>,
 #<Node:0x0000000b6c6938
  @ins=#<Sketchup::ComponentInstance:0x0000000b5a02e8>,
  @name="Child 2",
  @path=[#<Sketchup::ComponentInstance:0x0000000b520430>]>]


#6

In the parent instances array will be a component definition that is the group. The component definition will have the method group? set true. Since this is a top down lost of parents, the last item in the list should be the parent group if one is available.

group = entity.parent.instances[-1] if entity && entity.parent.typename == "ComponentDefinition" && entity.parent.group?

Should return the group, or nil if it isn’t in a group. Remove the entity.parent.group? if you want the parent component instead.

example:

e
#<Sketchup::Edge:0x00026066c089d8>
g = e.parent.instances[-1] if e && e.parent.typename == "ComponentDefinition" && e.parent.group?

#<Sketchup::Group:0x00026066c10c78>

#7

Side-note: avoid using .typename - it’s very slow. Prefer .is_a? instead.


#8

Cool Thanks