diff --git a/src/ifcblenderexport/blenderbim/bim/__init__.py b/src/ifcblenderexport/blenderbim/bim/__init__.py index 035b498760..1496e4caa5 100644 --- a/src/ifcblenderexport/blenderbim/bim/__init__.py +++ b/src/ifcblenderexport/blenderbim/bim/__init__.py @@ -15,6 +15,7 @@ if bpy is not None: import blenderbim.bim.module.model as module_model import blenderbim.bim.module.project as module_project import blenderbim.bim.module.spatial as module_spatial + import blenderbim.bim.module.style as module_style import blenderbim.bim.module.unit as module_unit from . import ui, prop, operator @@ -321,6 +322,7 @@ if bpy is not None: classes.extend(module_model.classes) classes.extend(module_project.classes) classes.extend(module_spatial.classes) + classes.extend(module_style.classes) classes.extend(module_unit.classes) def menu_func_export(self, context): @@ -363,6 +365,7 @@ if bpy is not None: module_model.register() module_project.register() module_spatial.register() + module_style.register() module_unit.register() bpy.app.handlers.depsgraph_update_pre.append(operator.depsgraph_update_pre_handler) bpy.app.handlers.load_post.append(prop.toggleDecorationsOnLoad) @@ -386,6 +389,7 @@ if bpy is not None: del bpy.types.TextCurve.BIMTextProperties bpy.types.SCENE_PT_unit.remove(ui.ifc_units) module_unit.unregister() + module_style.unregister() module_spatial.unregister() module_project.unregister() module_model.unregister() diff --git a/src/ifcblenderexport/blenderbim/bim/module/geometry/assign_styles.py b/src/ifcblenderexport/blenderbim/bim/module/geometry/assign_styles.py index 1728b44672..e4ad0a1e36 100644 --- a/src/ifcblenderexport/blenderbim/bim/module/geometry/assign_styles.py +++ b/src/ifcblenderexport/blenderbim/bim/module/geometry/assign_styles.py @@ -1,7 +1,11 @@ class Usecase: def __init__(self, file, settings=None): self.file = file - self.settings = {"shape_representation": None, "styles": []} + self.settings = { + "shape_representation": None, + "styles": [], + "should_use_presentation_style_assignment": False, + } for key, value in settings.items(): self.settings[key] = value @@ -16,9 +20,12 @@ class Usecase: if not item.is_a("IfcGeometricRepresentationItem"): continue style = self.settings["styles"].pop(0) + name = style.Name + if self.file.schema == "IFC2X3" or self.settings["should_use_presentation_style_assignment"]: + style = self.file.createIfcPresentationStyleAssignment([style]) self.results.append( self.file.createIfcStyledItem( - item, [style], style.Name + item, [style], name ) ) return self.results diff --git a/src/ifcblenderexport/blenderbim/bim/module/style/__init__.py b/src/ifcblenderexport/blenderbim/bim/module/style/__init__.py new file mode 100644 index 0000000000..bd340a126a --- /dev/null +++ b/src/ifcblenderexport/blenderbim/bim/module/style/__init__.py @@ -0,0 +1,16 @@ +import bpy +from . import ui, operator + +classes = ( + operator.AddStyle, + operator.EditStyle, + ui.BIM_PT_style, +) + + +def register(): + pass + + +def unregister(): + pass diff --git a/src/ifcblenderexport/blenderbim/bim/module/style/add_style.py b/src/ifcblenderexport/blenderbim/bim/module/style/add_style.py new file mode 100644 index 0000000000..f4cef0abe7 --- /dev/null +++ b/src/ifcblenderexport/blenderbim/bim/module/style/add_style.py @@ -0,0 +1,43 @@ +class Usecase: + def __init__(self, file, settings=None): + self.file = file + self.settings = { + "Name": "Name", + "SurfaceColour": [], # RGB + "DiffuseColour": [], # RGB + "Transparency": 0, + "external_definition": { + "Location": None, + "Identification": None, + "Name": "Name" + }, + } + for key, value in settings.items(): + self.settings[key] = value + + def execute(self): + styles = [self.create_surface_style_rendering()] + if self.settings["external_definition"]: + styles.append(self.create_externally_defined_surface_style()) + # Name is filled out because Revit treats this incorrectly as the material name + return self.file.createIfcSurfaceStyle(self.settings["Name"], "BOTH", styles) + + def create_surface_style_rendering(self): + return self.file.create_entity("IfcSurfaceStyleRendering", **{ + "SurfaceColour": self.create_colour_rgb(self.settings["SurfaceColour"]), + "Transparency": (self.settings["Transparency"] - 1) * -1, + "ReflectanceMethod": "NOTDEFINED", + "DiffuseColour": self.create_colour_rgb(self.settings["DiffuseColour"]) + }) + + def create_externally_defined_surface_style(self): + self.file.create_entity( + "IfcExternallyDefinedSurfaceStyle", **{ + "Location": self.settings["Location"], + "Identification": self.settings["Identification"], + "Name": self.settings["Name"], + } + ) + + def create_colour_rgb(self, colour): + return self.file.createIfcColourRgb(None, colour[0], colour[1], colour[2]) diff --git a/src/ifcblenderexport/blenderbim/bim/module/style/edit_style.py b/src/ifcblenderexport/blenderbim/bim/module/style/edit_style.py new file mode 100644 index 0000000000..e83397eece --- /dev/null +++ b/src/ifcblenderexport/blenderbim/bim/module/style/edit_style.py @@ -0,0 +1,67 @@ +class Usecase: + def __init__(self, file, settings=None): + self.file = file + self.settings = { + "style": None, + "SurfaceColour": [], # RGB + "DiffuseColour": [], # RGB + "Transparency": 0, + "external_definition": { + "Location": None, + "Identification": None, + "Name": "Name" + }, + } + for key, value in settings.items(): + self.settings[key] = value + + def execute(self): + #has_external_definition = None + for element in self.file.traverse(self.settings["style"]): + if element.is_a("IfcSurfaceStyleShading"): + if element.SurfaceColour: + self.update_colour_rgb(element.SurfaceColour, self.settings["SurfaceColour"]) + else: + element.SurfaceColour = self.create_colour_rgb(self.settings["SurfaceColour"]) + element.Transparency = (self.settings["Transparency"] - 1) * -1 + if element.is_a("IfcSurfaceStyleRendering"): + if element.DiffuseColour: + self.update_colour_rgb(element.DiffuseColour, self.settings["DiffuseColour"]) + else: + element.DiffuseColour = self.create_colour_rgb(self.settings["DiffuseColour"]) + # TODO: Move to separate usecase + #if element.is_a("IfcExternallyDefinedSurfaceStyle"): + # element.Location = self.settings["Location"] + # element.Identification = self.settings["Identification"] + # element.Name = self.settings["Name"] + # has_external_definition = True + #if not has_external_definition: + # styles = list(self.settings["style"].Styles) + # styles.append(self.create_externally_defined_surface_style()) + # self.settings["style"].Styles = styles + return self.settings["style"] + + def create_surface_style_rendering(self): + return self.file.create_entity("IfcSurfaceStyleRendering", **{ + "SurfaceColour": self.create_colour_rgb(self.settings["SurfaceColour"]), + "Transparency": (self.settings["Transparency"] - 1) * -1, + "ReflectanceMethod": "NOTDEFINED", + "DiffuseColour": self.create_colour_rgb(self.settings["DiffuseColour"]) + }) + + def create_externally_defined_surface_style(self): + self.file.create_entity( + "IfcExternallyDefinedSurfaceStyle", **{ + "Location": self.settings["Location"], + "Identification": self.settings["Identification"], + "Name": self.settings["Name"], + } + ) + + def create_colour_rgb(self, colour): + return self.file.createIfcColourRgb(None, colour[0], colour[1], colour[2]) + + def update_colour_rgb(self, element, colour): + element[1] = colour[0] + element[2] = colour[1] + element[3] = colour[2] diff --git a/src/ifcblenderexport/blenderbim/bim/module/style/operator.py b/src/ifcblenderexport/blenderbim/bim/module/style/operator.py new file mode 100644 index 0000000000..9141733e23 --- /dev/null +++ b/src/ifcblenderexport/blenderbim/bim/module/style/operator.py @@ -0,0 +1,50 @@ +import bpy +import blenderbim.bim.module.style.add_style as add_style +import blenderbim.bim.module.style.edit_style as edit_style +from blenderbim.bim.ifc import IfcStore + +# from blenderbim.bim.module.spatial.data import Data + + +def get_colour_settings(material): + transparency = material.diffuse_color[3] + diffuse_colour = material.diffuse_color + if material.use_nodes and hasattr(material.node_tree, "nodes") and "Principled BSDF" in material.node_tree.nodes: + bsdf = material.node_tree.nodes["Principled BSDF"] + transparency = bsdf.inputs["Alpha"].default_value + diffuse_colour = bsdf.inputs["Base Color"].default_value + return { + "SurfaceColour": material.diffuse_color, + "Transparency": transparency, + "DiffuseColour": diffuse_colour, + } + + +class EditStyle(bpy.types.Operator): + bl_idname = "bim.edit_style" + bl_label = "Edit Style" + material: bpy.props.StringProperty() + + def execute(self, context): + self.file = IfcStore.get_file() + material = bpy.data.objects.get(self.material) if self.material else bpy.context.active_object.active_material + settings = get_colour_settings(material) + settings["style"] = self.file.by_id(material.BIMMaterialProperties.ifc_style_id) + edit_style.Usecase(self.file, settings).execute() + return {"FINISHED"} + + +class AddStyle(bpy.types.Operator): + bl_idname = "bim.add_style" + bl_label = "Add Style" + material: bpy.props.StringProperty() + + def execute(self, context): + self.file = IfcStore.get_file() + material = bpy.data.objects.get(self.material) if self.material else bpy.context.active_object.active_material + settings = get_colour_settings(material) + settings["Name"] = material.name + settings["external_definition"] = None # TODO: Implement. See #1222 + style = add_style.Usecase(self.file, settings).execute() + material.BIMMaterialProperties.ifc_style_id = int(style.id()) + return {"FINISHED"} diff --git a/src/ifcblenderexport/blenderbim/bim/module/style/ui.py b/src/ifcblenderexport/blenderbim/bim/module/style/ui.py new file mode 100644 index 0000000000..05cfa2da97 --- /dev/null +++ b/src/ifcblenderexport/blenderbim/bim/module/style/ui.py @@ -0,0 +1,21 @@ +from bpy.types import Panel + + +class BIM_PT_style(Panel): + bl_label = "IFC Style" + bl_idname = "BIM_PT_style" + bl_space_type = "PROPERTIES" + bl_region_type = "WINDOW" + bl_context = "material" + + @classmethod + def poll(cls, context): + return context.active_object is not None and context.active_object.active_material is not None + + def draw(self, context): + props = context.active_object.active_material.BIMMaterialProperties + row = self.layout.row() + if props.ifc_style_id: + row.operator("bim.edit_style", icon="GREASEPENCIL") + else: + row.operator("bim.add_style", icon="ADD")