bim.save_uv_to_style - support saving uv to objects without a style

There was a problem with assigning uv workflow if object wasn't originally from IFC - saving uv requires object to have IfcSurfaceStyle but assigning IfcSurfaceStyle would reload representation discarding UV.

So, the current workflow for saving non-ifc objects uv to ifc:
1) Assign class to ifc object
2) Create IfcSurfaceStyle with a texture (currently also requires a rendering style)
3) Use "Save UV To Style"

Example - https://imgur.com/a/GZqo38M
This commit is contained in:
Andrej730
2024-08-21 12:33:18 +05:00
parent e5d0eb13bf
commit ef835e43b8
2 changed files with 49 additions and 21 deletions
+27 -14
View File
@@ -882,7 +882,11 @@ class AddSurfaceTexture(bpy.types.Operator):
class SaveUVToStyle(bpy.types.Operator, tool.Ifc.Operator): class SaveUVToStyle(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.save_uv_to_style" bl_idname = "bim.save_uv_to_style"
bl_label = "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"} bl_options = {"REGISTER", "UNDO"}
@classmethod @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): if not (obj := context.active_object) or not tool.Ifc.get_entity(obj):
cls.poll_message_set("No IFC object selected") cls.poll_message_set("No IFC object selected")
return False 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 return True
def _execute(self, context): 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 # We need IFC material with a texture style since in IFC
# UV indexing (IfcTextureCoordinate) requires some IfcSurfaceTexture. # UV indexing (IfcTextureCoordinate) requires some IfcSurfaceTexture.
material, style = None, None
style_is_assigned = False
material = obj.active_material material = obj.active_material
assert material if material:
style = tool.Ifc.get_entity(material)
# find active style item if style:
style = tool.Ifc.get_entity(material) style_is_assigned = True
assert style 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]: def get_active_representation_items() -> list[ifcopenshell.entity_instance]:
representation = tool.Geometry.get_active_representation(obj) 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)) all_styled_items = set(tool.Style.get_styled_items(style))
active_representation_items = set(get_active_representation_items()) 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( self.report(
{"ERROR"}, {"ERROR"},
"Not all items of the current representation are styled by the active style, not yet supported", "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.") self.report({"ERROR"}, "Only 1 faceset item is supported.")
return {"CANCELLED"} 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 mesh = obj.data
assert isinstance(mesh, bpy.types.Mesh) assert isinstance(mesh, bpy.types.Mesh)
uv_layer = mesh.uv_layers.active uv_layer = mesh.uv_layers.active
@@ -1016,6 +1025,10 @@ class SaveUVToStyle(bpy.types.Operator, tool.Ifc.Operator):
uv_verts_list.TexCoordsList = uv_verts uv_verts_list.TexCoordsList = uv_verts
texture_coord.TexCoords = uv_verts_list 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}'.") self.report({"INFO"}, f"UV saved to the style '{style.Name}'.")
return {"FINISHED"} return {"FINISHED"}
+22 -7
View File
@@ -103,6 +103,13 @@ class Style(bonsai.core.tool.Style):
props = bpy.context.scene.BIMStylesProperties props = bpy.context.scene.BIMStylesProperties
return bonsai.bim.helper.export_attributes(props.attributes) 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 @classmethod
def get_active_style_type(cls) -> str: def get_active_style_type(cls) -> str:
return bpy.context.scene.BIMStylesProperties.style_type return bpy.context.scene.BIMStylesProperties.style_type
@@ -432,22 +439,30 @@ class Style(bonsai.core.tool.Style):
return attributes return attributes
@classmethod @classmethod
def get_surface_rendering_style(cls, obj: bpy.types.Material) -> Union[ifcopenshell.entity_instance, None]: def get_surface_rendering_style(
style_elements = cls.get_style_elements(obj) 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) return style_elements.get("IfcSurfaceStyleRendering", None)
@classmethod @classmethod
def get_texture_style(cls, obj: bpy.types.Material) -> Union[ifcopenshell.entity_instance, None]: def get_texture_style(
style_elements = cls.get_style_elements(obj) 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) return style_elements.get("IfcSurfaceStyleWithTextures", None)
@classmethod @classmethod
def get_external_style(cls, obj: bpy.types.Material) -> Union[ifcopenshell.entity_instance, None]: def get_external_style(
style_elements = cls.get_style_elements(obj) 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) return style_elements.get("IfcExternallyDefinedSurfaceStyle", None)
@classmethod @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 = { data = {
"SurfaceColour": { "SurfaceColour": {
"Name": None, "Name": None,