You need to define which coordinates you are looking for. A component contains drawing elements that extend in space and thus have many coordinates. Most likely you mean the coordinates of the component origin.
You need to distinguish component definitions and component instances. An instance is a “clone” of the definition with a specific transformation and inside a specific parent entities collection. Since the entities collection itself may be contained inside a “parent” component definition (with multiple instances), a single component instance can have many occurences in the model – everywhere where the parent component has an instance. Thus refering to a component instance is ambiguous, we need to consider the whole instance path (array of nested parent component instances).
In your test you were probably calling bounds.center on the component definition, or you were comparing two occurences of the same component instance (inside two different instances of the parent component, like:
(component definition A contains an instance of definition B) [Model, A#1, B#1] [Model, A#2, B#1]
Then for both occurences of B#1, B#1 has the same transformation and origin. To get the global coordinates, you have to accumulate the transformations of all instances in the instance path.
Example to collect instance paths:
def collect_all_instance_paths(model, &condition)
instance_paths = []
contained_instances = {}
model.definitions.each{ |definition|
instances = definition.entities.grep(Sketchup::Group).concat(definition.entities.grep(Sketchup::ComponentInstance))
instances = instances.select(&condition) if block_given?
contained_instances[definition] = instances
}
instances = model.entities.grep(Sketchup::Group).concat(model.entities.grep(Sketchup::ComponentInstance))
instances = instances.select(&condition) if block_given?
queue = instances.map{ |instance| [instance] }
until queue.empty?
path = *(queue.shift)
instance = path.last
next if instance.nil?
contained = contained_instances[instance.definition]
instance_paths.push(path)
unless contained.empty?
contained.each{ |instance2|
queue.push(path + [instance2])
}
end
end
return instance_paths
end
# or
def collect_occurences(instance)
instance_paths = []
queue = [ [instance] ]
until queue.empty?
path = *(queue.shift)
outer = path.first
if outer.parent.is_a?(Sketchup::Model)
instance_paths << path
else
outer.parent.instances.each{ |uncle|
queue << [uncle] + path
}
end
end
return instance_paths
end
instance_paths = collect_occurences(some_instance)
Once you have an instance path, aggregate the transformations:
def get_transformation_for_instance_path(instance_path)
transformation = Geom::Transformation.new() # IDENTITY
instance_path.reject{ |noninstance| # Model or DrawingElement do not have a transformation.
!noninstance.respond_to?(:transformation)
}.each{ |instance|
transformation *= instance.transformation
}
return transformation
end
global_transformation = get_transformation_for_instance_path(instance_path)
Then apply the transformation to vertex positions of the geometry inside the most inner instance, or get the global position of the origin (which (0,0,0) when seen from inside the component definition):
is there this situation that the components have the same parent-path and the same definition. but visually the component instances are in different position.
Yes. The component can be nested inside of other components that are at different locations. The components would be duplicates that have the same relative coordinates nested inside another grouped object, but the copies of the other grouped object could be in different locations. The answer is no when the components are in the outer most entities collection, then they would be in world coordinates. Is there a Sketchup file that you could attach?
you know, i can get the instance’s local center by “bounds.center”. But now i can get the instance’s global transformation. how can i get the global center by the global transformation?
Here using definition.bounds because we have already included the instance’s transformation in the global transformation. Potentially you may have the wrong matrix and you have to invert it (inverse).
Matrix multiplication is not commutative, so A * B is not B * A. Sometimes I have the multiplication in wrong order. Or I have the matrix for local to global coordinates and wrongly use it for global to local.
John;
You posted a slightly different version of the model on:
I was able to determine that it has two section planes at:
a) Un-nested one at “.entities[2]”; and
b) Nested one at “.entities[0].entities[0]”.
Neither of them is displayed, and selecting “View…Hidden Geometry” does not display them. According to the Ruby console, they are both unhidden and both active. The model only has one layer, and there are no hidden layers for them to hide on. If I add an additional section plane, they show up as follows:
The larger orange section plane is the one I added. The grayed one is no longer active (item ‘a’) since I added the new one.
Why are there section planes that are unhidden and active that are not noticeable on this model? How did you achieve that?
My pick tool says it is at entities[1].entities[7], instance 2 of 3 (the other instances are not hidden). Contained within that component is a single Sketchup group object.
That doesn’t do anything, but instances = instances.select(&condition) if block_given? reduces the selection array to the instances that match a condition (like select{ |i| …}). One can leave that parameter away, it was just in the code where I copied this extract from.