diff --git a/src/bonsai/bonsai/bim/module/style/operator.py b/src/bonsai/bonsai/bim/module/style/operator.py index efa0040dde..22dd98b7ba 100644 --- a/src/bonsai/bonsai/bim/module/style/operator.py +++ b/src/bonsai/bonsai/bim/module/style/operator.py @@ -882,7 +882,11 @@ class AddSurfaceTexture(bpy.types.Operator): class SaveUVToStyle(bpy.types.Operator, tool.Ifc.Operator): bl_idname = "bim.save_uv_to_style" bl_label = "Save UV To Style" - bl_description = "Save active object UV to it's IfcSurfaceStyle's IfcSurfaceTexture" + bl_description = ( + "Save active object UV to the IfcSurfaceStyle's IfcSurfaceTexture.\n\n" + "If object already has IfcSurfaceStyleWithTextures, then it will be used.\n" + "Otherwise operator will use currently selected surface style (style will be autoassigned)" + ) bl_options = {"REGISTER", "UNDO"} @classmethod @@ -890,9 +894,6 @@ class SaveUVToStyle(bpy.types.Operator, tool.Ifc.Operator): if not (obj := context.active_object) or not tool.Ifc.get_entity(obj): cls.poll_message_set("No IFC object selected") return False - if not obj.active_material or not tool.Ifc.get_entity(obj.active_material): - cls.poll_message_set("Object has no IFC style.") - return False return True def _execute(self, context): @@ -903,12 +904,25 @@ class SaveUVToStyle(bpy.types.Operator, tool.Ifc.Operator): # We need IFC material with a texture style since in IFC # UV indexing (IfcTextureCoordinate) requires some IfcSurfaceTexture. + material, style = None, None + style_is_assigned = False material = obj.active_material - assert material + if material: + style = tool.Ifc.get_entity(material) - # find active style item - style = tool.Ifc.get_entity(material) - assert style + if style: + style_is_assigned = True + else: + style_item = tool.Style.get_active_style_in_ui() + if not style_item: + self.report({"ERROR"}, "Object has no style and no style is selected.") + return {"CANCELLED"} + style = ifc_file.by_id(style_item.ifc_definition_id) + + texture_style = tool.Style.get_texture_style(style) + if not texture_style: + self.report({"ERROR"}, "IfcSurfaceStyle has no texture style.") + return {"CANCELLED"} def get_active_representation_items() -> list[ifcopenshell.entity_instance]: representation = tool.Geometry.get_active_representation(obj) @@ -923,7 +937,7 @@ class SaveUVToStyle(bpy.types.Operator, tool.Ifc.Operator): all_styled_items = set(tool.Style.get_styled_items(style)) active_representation_items = set(get_active_representation_items()) - if not active_representation_items.issubset(all_styled_items): + if style_is_assigned and not active_representation_items.issubset(all_styled_items): self.report( {"ERROR"}, "Not all items of the current representation are styled by the active style, not yet supported", @@ -943,11 +957,6 @@ class SaveUVToStyle(bpy.types.Operator, tool.Ifc.Operator): self.report({"ERROR"}, "Only 1 faceset item is supported.") return {"CANCELLED"} - texture_style = tool.Style.get_texture_style(material) - if not texture_style: - self.report({"ERROR"}, "No texture style found, not yet supported.") - return {"CANCELLED"} - mesh = obj.data assert isinstance(mesh, bpy.types.Mesh) uv_layer = mesh.uv_layers.active @@ -1016,6 +1025,10 @@ class SaveUVToStyle(bpy.types.Operator, tool.Ifc.Operator): uv_verts_list.TexCoordsList = uv_verts texture_coord.TexCoords = uv_verts_list + if not style_is_assigned: + with context.temp_override(selected_objects=[obj]): + bpy.ops.bim.assign_style_to_selected(style_id=style.id()) + self.report({"INFO"}, f"UV saved to the style '{style.Name}'.") return {"FINISHED"} diff --git a/src/bonsai/bonsai/tool/style.py b/src/bonsai/bonsai/tool/style.py index a4a3c99ea0..7ca8f4a4e9 100644 --- a/src/bonsai/bonsai/tool/style.py +++ b/src/bonsai/bonsai/tool/style.py @@ -103,6 +103,13 @@ class Style(bonsai.core.tool.Style): props = bpy.context.scene.BIMStylesProperties return bonsai.bim.helper.export_attributes(props.attributes) + @classmethod + def get_active_style_in_ui(cls) -> Union[bpy.types.PropertyGroup, None]: + props = bpy.context.scene.BIMStylesProperties + if len(props.styles) > props.active_style_index >= 0: + return props.styles[props.active_style_index] + return None + @classmethod def get_active_style_type(cls) -> str: return bpy.context.scene.BIMStylesProperties.style_type @@ -432,22 +439,30 @@ class Style(bonsai.core.tool.Style): return attributes @classmethod - def get_surface_rendering_style(cls, obj: bpy.types.Material) -> Union[ifcopenshell.entity_instance, None]: - style_elements = cls.get_style_elements(obj) + def get_surface_rendering_style( + cls, blender_material_or_style: Union[bpy.types.Material, ifcopenshell.entity_instance] + ) -> Union[ifcopenshell.entity_instance, None]: + style_elements = cls.get_style_elements(blender_material_or_style) return style_elements.get("IfcSurfaceStyleRendering", None) @classmethod - def get_texture_style(cls, obj: bpy.types.Material) -> Union[ifcopenshell.entity_instance, None]: - style_elements = cls.get_style_elements(obj) + def get_texture_style( + cls, blender_material_or_style: Union[bpy.types.Material, ifcopenshell.entity_instance] + ) -> Union[ifcopenshell.entity_instance, None]: + style_elements = cls.get_style_elements(blender_material_or_style) return style_elements.get("IfcSurfaceStyleWithTextures", None) @classmethod - def get_external_style(cls, obj: bpy.types.Material) -> Union[ifcopenshell.entity_instance, None]: - style_elements = cls.get_style_elements(obj) + def get_external_style( + cls, blender_material_or_style: Union[bpy.types.Material, ifcopenshell.entity_instance] + ) -> Union[ifcopenshell.entity_instance, None]: + style_elements = cls.get_style_elements(blender_material_or_style) return style_elements.get("IfcExternallyDefinedSurfaceStyle", None) @classmethod - def get_surface_shading_attributes(cls, obj: bpy.types.Material) -> dict[str, Any]: + def get_surface_shading_attributes( + cls, blender_material_or_style: Union[bpy.types.Material, ifcopenshell.entity_instance] + ) -> dict[str, Any]: data = { "SurfaceColour": { "Name": None,