@@ -71,20 +71,98 @@ def invoke(self, context, event):
7171 return self .execute (context )
7272
7373 def execute (self , context ):
74- material = tool .Ifc .get ().by_id (self .material )
75- core .select_by_material (tool .Material , tool .Spatial , material = material , should_unhide = self .should_unhide )
74+ # Determine the layer index hint from the explicit material prop, if any.
75+ # When the user clicks a specific layer in the UI, self.material is that
76+ # layer's IfcMaterial. We find its index so we can pull the same layer
77+ # from every other selected object's layer set.
78+ layer_index = None
79+ if self .material :
80+ ref_mat = tool .Ifc .get ().by_id (self .material )
81+ layer_index = self ._get_layer_index (ref_mat )
82+
83+ materials = {}
84+ for obj in context .selected_objects :
85+ element = tool .Ifc .get_entity (obj )
86+ if not element :
87+ continue
88+ mat = ifcopenshell .util .element .get_material (element )
89+ if not mat :
90+ continue
91+
92+ resolved = self ._resolve_material (mat , layer_index )
93+ if resolved :
94+ materials [resolved .id ()] = resolved
95+
96+ # Fall back to the explicit material prop if selection yields nothing
97+ if not materials and self .material :
98+ materials = {self .material : tool .Ifc .get ().by_id (self .material )}
99+
100+ if not materials :
101+ return {"FINISHED" }
76102
77- # copy selection query to clipboard
78- if material .is_a ("IfcMaterialLayerSet" ):
79- material_name = material .LayerSetName
80- else :
81- material_name = material .Name
82- result = f'material="{ material_name } "'
103+ for mat in materials .values ():
104+ core .select_by_material (tool .Material , tool .Spatial , material = mat , should_unhide = self .should_unhide )
105+
106+ result = " + " .join (f'material = "{ self ._get_name (m )} "' for m in materials .values ())
83107 bpy .context .window_manager .clipboard = result
84108 self .report ({"INFO" }, f"({ result } ) was copied to the clipboard." )
85109
86110 return {"FINISHED" }
87111
112+ def _get_layer_index (self , material ):
113+ """Return the 0-based layer index if material is an IfcMaterial inside a layer set."""
114+ if not material .is_a ("IfcMaterial" ):
115+ return None
116+ ifc = tool .Ifc .get ()
117+ for layer in ifc .get_inverse (material ):
118+ if not layer .is_a ("IfcMaterialLayer" ):
119+ continue
120+ for layer_set in ifc .get_inverse (layer ):
121+ if not layer_set .is_a ("IfcMaterialLayerSet" ):
122+ continue
123+ layers = list (layer_set .MaterialLayers )
124+ if layer in layers :
125+ return layers .index (layer )
126+ return None
127+
128+ def _resolve_material (self , mat , layer_index ):
129+ """Resolve an assigned material to the specific entity to select/name by.
130+
131+ When layer_index is set, drills into the layer set and returns the
132+ IfcMaterial at that index (or None if the set has fewer layers).
133+ Otherwise returns the layer set / profile set / constituent set itself.
134+ """
135+ if mat .is_a ("IfcMaterialLayerSetUsage" ):
136+ mat = mat .ForLayerSet
137+ elif mat .is_a ("IfcMaterialProfileSetUsage" ):
138+ mat = mat .ForProfileSet
139+
140+ if layer_index is not None and mat .is_a ("IfcMaterialLayerSet" ):
141+ layers = list (mat .MaterialLayers )
142+ if layer_index < len (layers ):
143+ return layers [layer_index ].Material
144+ return None
145+
146+ return mat
147+
148+ def _get_name (self , material ):
149+ if material .is_a ("IfcMaterialLayerSet" ):
150+ if material .LayerSetName :
151+ return material .LayerSetName
152+ names = [l .Material .Name for l in (material .MaterialLayers or []) if l .Material and l .Material .Name ]
153+ return ", " .join (names ) if names else material .is_a ()
154+ if material .is_a ("IfcMaterialProfileSet" ):
155+ if material .Name :
156+ return material .Name
157+ names = [p .Material .Name for p in (material .MaterialProfiles or []) if p .Material and p .Material .Name ]
158+ return ", " .join (names ) if names else material .is_a ()
159+ if material .is_a ("IfcMaterialConstituentSet" ):
160+ if material .Name :
161+ return material .Name
162+ names = [c .Material .Name for c in (material .MaterialConstituents or []) if c .Material and c .Material .Name ]
163+ return ", " .join (names ) if names else material .is_a ()
164+ return getattr (material , "Name" , None ) or material .is_a ()
165+
88166
89167class EnableEditingMaterial (bpy .types .Operator ):
90168 bl_idname = "bim.enable_editing_material"
0 commit comments