Efficient way to retrieve all materials used within a ComponentDefinition

According to the documentation, materials can be applied to Drawingelements. Thus, a material can be applied to an instance, a group, a face, etc.

I’m asking myself about the best way to retrieve all the materials applied to a specific definition. The simplest idea is iterating over all the faces and retrieve both back and front materials, but this process may be slow with high polygon objects.

We can find materials at different levels, for example at instance level (objects with one single material) or at group level (group of faces with a single material) that can help making the process faster. On the other hand, edges are also Drawingelements, so theoretically we should also iterate over them to obtain possible materials, which may make the process even slower.

Most common drawing-element material use is:

  • edge.material
  • face.material
  • group.material
  • component_instance.material

A component_instance can only have one material at a time.
I suspect what you are trying to say is ‘all materials used by any drawing-element within a component_instance.definition’ ??
Something like this snippet ?

### for ALL elements in the instance's definition - which have materials applied to them
materials=[]
component_instance.definition.entities.find_all{|e|
  e. respond_to?:material
}.each{|e|
    materials << e.material if e.material
    ### OR do something else, e.g. e.material=nil if e.material ?
}
###
### for any back-faces add
component_instance.definition.entities.grep(Sketchup::Face).each{|e|
    materials << e.back_material if e.back_material
    ### OR do something else, e.g. e.back_material=nil if e.back_material  ?
}
### note how 'grep' here is used to filter the entities to just faces, 
### or you could for example grep to remove materials from just the edges etc...
###
### finally remove duplicates if desired
materials.uniq!
###
### now you either have an array of all used materials in that definition - OR depending on what you decide they've been removed...
1 Like

You are right, I meant all materials within a definition (edited the question already). Instances share materials no matter how many of them you have in the scene.

The second loop is the method I was using so far for both front and back materials. The first one is the one I was looking for, which covers any drawingelement within a definition.

That looks nice, I am going to test it. Still I guess it will be slow for components with a high number of edges/faces, but I can start thinking of an optimization after making sure that everything works fine. Thanks.

This might not be that bad. (But as always, time and profile if performance is critical.)

For the record, in the following scenario the materials array is empty using that solution:

image

This is a nightstand with two group of faces, one for the base and one for the shelve. We need to include the same search for Groups inside the component, i.e.:

  object.entities.grep(Sketchup::Group).each do |group|
    group.entities.find_all { |e| e.respond_to?(:material) }.each { |e| materials << e.material if e.material }
    group.entities.grep(Sketchup::Face).each { |e| materials << e.back_material if e.back_material }
  end