diff --git a/src/blenderbim/blenderbim/bim/export_ifc.py b/src/blenderbim/blenderbim/bim/export_ifc.py index 14051fd5b7..7a115d0ea9 100644 --- a/src/blenderbim/blenderbim/bim/export_ifc.py +++ b/src/blenderbim/blenderbim/bim/export_ifc.py @@ -172,6 +172,7 @@ class IfcExporter: try: # This will throw an exception if the Blender object no longer exists foo = obj.name + foo return False except: return True @@ -199,7 +200,6 @@ class IfcExportSettings: @staticmethod def factory(context, output_file, logger): - scene_bim = context.scene.BIMProperties settings = IfcExportSettings() settings.output_file = output_file settings.logger = logger diff --git a/src/blenderbim/blenderbim/bim/import_ifc.py b/src/blenderbim/blenderbim/bim/import_ifc.py index c60946d568..ba7a501e68 100644 --- a/src/blenderbim/blenderbim/bim/import_ifc.py +++ b/src/blenderbim/blenderbim/bim/import_ifc.py @@ -16,31 +16,24 @@ # You should have received a copy of the GNU General Public License # along with BlenderBIM Add-on. If not, see . -import ifcopenshell -import ifcopenshell.geom -import ifcopenshell.util.geolocation -import ifcopenshell.util.selector -import ifcopenshell.util.element -import ifcopenshell.util.unit -import bpy -import bmesh -import os import re -import shutil -import threading +import bpy import json import time +import bmesh +import shutil +import threading import mathutils -import math -import multiprocessing -import zipfile -import tempfile import numpy as np -from blenderbim.bim.module.drawing.prop import getDiagramScales -from pathlib import Path -from itertools import cycle -from datetime import datetime +import multiprocessing +import ifcopenshell +import ifcopenshell.geom +import ifcopenshell.util.unit +import ifcopenshell.util.element +import ifcopenshell.util.selector +import ifcopenshell.util.geolocation from blenderbim.bim.ifc import IfcStore +from blenderbim.bim.module.drawing.prop import getDiagramScales class FileCopy(threading.Thread): @@ -407,7 +400,6 @@ class IfcImporter: props.has_blender_offset = True def get_offset_point(self): - offset_point = None elements_checked = 0 # If more than these points aren't far away, the file probably isn't absolutely positioned element_checking_threshold = 100 @@ -462,16 +454,14 @@ class IfcImporter: return mathutils.Matrix(matrix.tolist()) def find_decomposed_ifc_class(self, element, ifc_class): - results = [] + if element.is_a(ifc_class): + return element rel_aggregates = element.IsDecomposedBy - if not rel_aggregates: - return results for rel_aggregate in rel_aggregates: for part in rel_aggregate.RelatedObjects: - if part.is_a(ifc_class): - results.append(part) - results.extend(self.find_decomposed_ifc_class(part, ifc_class)) - return results + result = self.find_decomposed_ifc_class(part, ifc_class) + if result: + return result def create_grids(self): grids = self.file.by_type("IfcGrid") @@ -1485,7 +1475,6 @@ class IfcImportSettings: @staticmethod def factory(context, input_file, logger): - scene_bim = context.scene.BIMProperties scene_diff = context.scene.DiffProperties settings = IfcImportSettings() settings.input_file = input_file diff --git a/src/blenderbim/blenderbim/bim/module/style/operator.py b/src/blenderbim/blenderbim/bim/module/style/operator.py index 88cb72a497..c03376c187 100644 --- a/src/blenderbim/blenderbim/bim/module/style/operator.py +++ b/src/blenderbim/blenderbim/bim/module/style/operator.py @@ -52,8 +52,25 @@ class UpdateStyleColours(bpy.types.Operator): self.file = IfcStore.get_file() material = bpy.data.materials.get(self.material) if self.material else context.active_object.active_material settings = get_colour_settings(material) - settings["style"] = self.file.by_id(material.BIMMaterialProperties.ifc_style_id) - ifcopenshell.api.run("style.edit_style_colours", self.file, **settings) + for style in self.file.by_id(material.BIMMaterialProperties.ifc_style_id).Styles: + if style.is_a("IfcSurfaceStyleRendering"): + ifcopenshell.api.run( + "style.edit_surface_style", + self.file, + style=style, + attributes={ + "SurfaceColour": settings["surface_colour"], + "Transparency": settings["transparency"], + "DiffuseColour": settings["diffuse_colour"], + }, + ) + elif style.is_a("IfcSurfaceStyleShading"): + ifcopenshell.api.run( + "style.edit_surface_style", + self.file, + style=style, + attributes={"SurfaceColour": settings["surface_colour"], "Transparency": settings["transparency"]}, + ) return {"FINISHED"} @@ -167,7 +184,7 @@ class EditStyle(bpy.types.Operator): attributes = blenderbim.bim.helper.export_attributes(props.attributes) self.file = IfcStore.get_file() style = self.file.by_id(material.BIMMaterialProperties.ifc_style_id) - ifcopenshell.api.run("style.edit_style", self.file, **{"style": style, "attributes": attributes}) + ifcopenshell.api.run("style.edit_presentation_style", self.file, **{"style": style, "attributes": attributes}) Data.load(IfcStore.get_file(), material.BIMMaterialProperties.ifc_style_id) bpy.ops.bim.disable_editing_style() return {"FINISHED"} diff --git a/src/ifcopenshell-python/ifcopenshell/api/style/edit_style.py b/src/ifcopenshell-python/ifcopenshell/api/style/edit_presentation_style.py similarity index 100% rename from src/ifcopenshell-python/ifcopenshell/api/style/edit_style.py rename to src/ifcopenshell-python/ifcopenshell/api/style/edit_presentation_style.py diff --git a/src/ifcopenshell-python/ifcopenshell/api/style/edit_style_colours.py b/src/ifcopenshell-python/ifcopenshell/api/style/edit_style_colours.py deleted file mode 100644 index 49959720a2..0000000000 --- a/src/ifcopenshell-python/ifcopenshell/api/style/edit_style_colours.py +++ /dev/null @@ -1,67 +0,0 @@ -class Usecase: - def __init__(self, file, **settings): - self.file = file - self.settings = { - "style": None, - "surface_colour": [], # RGB - "diffuse_colour": [], # 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["surface_colour"]) - else: - element.SurfaceColour = self.create_colour_rgb(self.settings["surface_colour"]) - element.Transparency = self.settings["transparency"] - if element.is_a("IfcSurfaceStyleRendering"): - if element.DiffuseColour: - self.update_colour_rgb(element.DiffuseColour, self.settings["diffuse_colour"]) - else: - element.DiffuseColour = self.create_colour_rgb(self.settings["diffuse_colour"]) - # 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["surface_colour"]), - "Transparency": self.settings["transparency"], - "ReflectanceMethod": "NOTDEFINED", - "DiffuseColour": self.create_colour_rgb(self.settings["diffuse_colour"]), - } - ) - - 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/ifcopenshell-python/ifcopenshell/api/style/edit_surface_style.py b/src/ifcopenshell-python/ifcopenshell/api/style/edit_surface_style.py new file mode 100644 index 0000000000..52ae3df70e --- /dev/null +++ b/src/ifcopenshell-python/ifcopenshell/api/style/edit_surface_style.py @@ -0,0 +1,45 @@ +class Usecase: + def __init__(self, file, **settings): + self.file = file + self.settings = {"style": None, "attributes": {}} + for key, value in settings.items(): + self.settings[key] = value + + def execute(self): + for key, value in self.settings["attributes"].items(): + if key == "SurfaceColour": + self.edit_surface_colour(value) + elif self.is_colour_or_factor(key): + self.edit_colour_or_factor(key, value) + else: + setattr(self.settings["style"], key, value) + + def edit_surface_colour(self, value): + self.settings["style"].SurfaceColour[1] = value[0] + self.settings["style"].SurfaceColour[2] = value[1] + self.settings["style"].SurfaceColour[3] = value[2] + + def is_colour_or_factor(self, name): + return name in [ + "DiffuseColour", + "TransmissionColour", + "DiffuseTransmissionColour", + "ReflectionColour", + "SpecularColour", + ] + + def edit_colour_or_factor(self, name, value): + if isinstance(value, (list, tuple)): + attribute = getattr(self.settings["style"], name) + if not attribute or not attribute.is_a("IfcColourRgb"): + colour = self.file.createIfcColourRgb(None, 0, 0, 0) + setattr(self.settings["style"], name, colour) + attribute = getattr(self.settings["style"], name) + attribute[1] = value[0] + attribute[2] = value[1] + attribute[3] = value[2] + else: + existing_value = getattr(self.settings["style"], name) + if existing_value and existing_value.id(): + self.file.remove(existing_value) + setattr(self.settings["style"], name, self.file.createIfcNormalisedRatioMeasure(value)) diff --git a/src/ifcopenshell-python/test/api/style/test_edit_surface_style.py b/src/ifcopenshell-python/test/api/style/test_edit_surface_style.py new file mode 100644 index 0000000000..23c38c8779 --- /dev/null +++ b/src/ifcopenshell-python/test/api/style/test_edit_surface_style.py @@ -0,0 +1,87 @@ +import pytest +import test.bootstrap +import ifcopenshell.api + + +class TestEditStyleColours(test.bootstrap.IFC4): + def test_editing_a_shading_style(self): + colour = self.file.createIfcColourRgb(None, 0, 0, 0) + style = self.file.createIfcSurfaceStyleShading(colour) + ifcopenshell.api.run( + "style.edit_surface_style", + self.file, + style=style, + attributes={"SurfaceColour": [1, 1, 1], "Transparency": 0.5}, + ) + assert style.SurfaceColour == colour + assert list(colour) == [None, 1, 1, 1] + assert style.Transparency == 0.5 + + def test_editing_an_empty_colour_or_factor(self): + for attribute in [ + "DiffuseColour", + "TransmissionColour", + "DiffuseTransmissionColour", + "ReflectionColour", + "SpecularColour", + ]: + style = self.file.createIfcSurfaceStyleRendering(self.file.createIfcColourRgb(None, 0, 0, 0)) + ifcopenshell.api.run("style.edit_surface_style", self.file, style=style, attributes={attribute: [1, 1, 1]}) + assert list(getattr(style, attribute)) == [None, 1, 1, 1] + + def test_editing_an_existing_colour_to_another_colour(self): + for attribute in [ + "DiffuseColour", + "TransmissionColour", + "DiffuseTransmissionColour", + "ReflectionColour", + "SpecularColour", + ]: + colour = self.file.createIfcColourRgb(None, 0, 0, 0) + style = self.file.createIfcSurfaceStyleRendering(self.file.createIfcColourRgb(None, 0, 0, 0)) + setattr(style, attribute, colour) + ifcopenshell.api.run("style.edit_surface_style", self.file, style=style, attributes={attribute: [1, 1, 1]}) + assert list(colour) == [None, 1, 1, 1] + + def test_editing_an_existing_colour_to_a_factor(self): + for attribute in [ + "DiffuseColour", + "TransmissionColour", + "DiffuseTransmissionColour", + "ReflectionColour", + "SpecularColour", + ]: + colour = self.file.createIfcColourRgb(None, 0, 0, 0) + colour_id = colour.id() + style = self.file.createIfcSurfaceStyleRendering(self.file.createIfcColourRgb(None, 0, 0, 0)) + setattr(style, attribute, colour) + ifcopenshell.api.run("style.edit_surface_style", self.file, style=style, attributes={attribute: 0.5}) + with pytest.raises(RuntimeError): + self.file.by_id(colour_id) + assert getattr(style, attribute).wrappedValue == 0.5 + + def test_editing_an_existing_factor_to_another_factor(self): + for attribute in [ + "DiffuseColour", + "TransmissionColour", + "DiffuseTransmissionColour", + "ReflectionColour", + "SpecularColour", + ]: + style = self.file.createIfcSurfaceStyleRendering(self.file.createIfcColourRgb(None, 0, 0, 0)) + setattr(style, attribute, self.file.createIfcNormalisedRatioMeasure(0.5)) + ifcopenshell.api.run("style.edit_surface_style", self.file, style=style, attributes={attribute: 0.4}) + assert getattr(style, attribute).wrappedValue == 0.4 + + def test_editing_an_existing_factor_to_a_colour(self): + for attribute in [ + "DiffuseColour", + "TransmissionColour", + "DiffuseTransmissionColour", + "ReflectionColour", + "SpecularColour", + ]: + style = self.file.createIfcSurfaceStyleRendering(self.file.createIfcColourRgb(None, 0, 0, 0)) + setattr(style, attribute, self.file.createIfcNormalisedRatioMeasure(0.5)) + ifcopenshell.api.run("style.edit_surface_style", self.file, style=style, attributes={attribute: [1, 1, 1]}) + assert list(getattr(style, attribute)) == [None, 1, 1, 1]