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):
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"}
+22 -7
View File
@@ -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,