mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-11 06:18:09 +00:00
Fix bug where editing styles didn't work if factors were stored instead of RGB colours
This commit is contained in:
@@ -172,6 +172,7 @@ class IfcExporter:
|
|||||||
try:
|
try:
|
||||||
# This will throw an exception if the Blender object no longer exists
|
# This will throw an exception if the Blender object no longer exists
|
||||||
foo = obj.name
|
foo = obj.name
|
||||||
|
foo
|
||||||
return False
|
return False
|
||||||
except:
|
except:
|
||||||
return True
|
return True
|
||||||
@@ -199,7 +200,6 @@ class IfcExportSettings:
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def factory(context, output_file, logger):
|
def factory(context, output_file, logger):
|
||||||
scene_bim = context.scene.BIMProperties
|
|
||||||
settings = IfcExportSettings()
|
settings = IfcExportSettings()
|
||||||
settings.output_file = output_file
|
settings.output_file = output_file
|
||||||
settings.logger = logger
|
settings.logger = logger
|
||||||
|
|||||||
@@ -16,31 +16,24 @@
|
|||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
|
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
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 re
|
||||||
import shutil
|
import bpy
|
||||||
import threading
|
|
||||||
import json
|
import json
|
||||||
import time
|
import time
|
||||||
|
import bmesh
|
||||||
|
import shutil
|
||||||
|
import threading
|
||||||
import mathutils
|
import mathutils
|
||||||
import math
|
|
||||||
import multiprocessing
|
|
||||||
import zipfile
|
|
||||||
import tempfile
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
from blenderbim.bim.module.drawing.prop import getDiagramScales
|
import multiprocessing
|
||||||
from pathlib import Path
|
import ifcopenshell
|
||||||
from itertools import cycle
|
import ifcopenshell.geom
|
||||||
from datetime import datetime
|
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.ifc import IfcStore
|
||||||
|
from blenderbim.bim.module.drawing.prop import getDiagramScales
|
||||||
|
|
||||||
|
|
||||||
class FileCopy(threading.Thread):
|
class FileCopy(threading.Thread):
|
||||||
@@ -407,7 +400,6 @@ class IfcImporter:
|
|||||||
props.has_blender_offset = True
|
props.has_blender_offset = True
|
||||||
|
|
||||||
def get_offset_point(self):
|
def get_offset_point(self):
|
||||||
offset_point = None
|
|
||||||
elements_checked = 0
|
elements_checked = 0
|
||||||
# If more than these points aren't far away, the file probably isn't absolutely positioned
|
# If more than these points aren't far away, the file probably isn't absolutely positioned
|
||||||
element_checking_threshold = 100
|
element_checking_threshold = 100
|
||||||
@@ -462,16 +454,14 @@ class IfcImporter:
|
|||||||
return mathutils.Matrix(matrix.tolist())
|
return mathutils.Matrix(matrix.tolist())
|
||||||
|
|
||||||
def find_decomposed_ifc_class(self, element, ifc_class):
|
def find_decomposed_ifc_class(self, element, ifc_class):
|
||||||
results = []
|
if element.is_a(ifc_class):
|
||||||
|
return element
|
||||||
rel_aggregates = element.IsDecomposedBy
|
rel_aggregates = element.IsDecomposedBy
|
||||||
if not rel_aggregates:
|
|
||||||
return results
|
|
||||||
for rel_aggregate in rel_aggregates:
|
for rel_aggregate in rel_aggregates:
|
||||||
for part in rel_aggregate.RelatedObjects:
|
for part in rel_aggregate.RelatedObjects:
|
||||||
if part.is_a(ifc_class):
|
result = self.find_decomposed_ifc_class(part, ifc_class)
|
||||||
results.append(part)
|
if result:
|
||||||
results.extend(self.find_decomposed_ifc_class(part, ifc_class))
|
return result
|
||||||
return results
|
|
||||||
|
|
||||||
def create_grids(self):
|
def create_grids(self):
|
||||||
grids = self.file.by_type("IfcGrid")
|
grids = self.file.by_type("IfcGrid")
|
||||||
@@ -1485,7 +1475,6 @@ class IfcImportSettings:
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def factory(context, input_file, logger):
|
def factory(context, input_file, logger):
|
||||||
scene_bim = context.scene.BIMProperties
|
|
||||||
scene_diff = context.scene.DiffProperties
|
scene_diff = context.scene.DiffProperties
|
||||||
settings = IfcImportSettings()
|
settings = IfcImportSettings()
|
||||||
settings.input_file = input_file
|
settings.input_file = input_file
|
||||||
|
|||||||
@@ -52,8 +52,25 @@ class UpdateStyleColours(bpy.types.Operator):
|
|||||||
self.file = IfcStore.get_file()
|
self.file = IfcStore.get_file()
|
||||||
material = bpy.data.materials.get(self.material) if self.material else context.active_object.active_material
|
material = bpy.data.materials.get(self.material) if self.material else context.active_object.active_material
|
||||||
settings = get_colour_settings(material)
|
settings = get_colour_settings(material)
|
||||||
settings["style"] = self.file.by_id(material.BIMMaterialProperties.ifc_style_id)
|
for style in self.file.by_id(material.BIMMaterialProperties.ifc_style_id).Styles:
|
||||||
ifcopenshell.api.run("style.edit_style_colours", self.file, **settings)
|
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"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
@@ -167,7 +184,7 @@ class EditStyle(bpy.types.Operator):
|
|||||||
attributes = blenderbim.bim.helper.export_attributes(props.attributes)
|
attributes = blenderbim.bim.helper.export_attributes(props.attributes)
|
||||||
self.file = IfcStore.get_file()
|
self.file = IfcStore.get_file()
|
||||||
style = self.file.by_id(material.BIMMaterialProperties.ifc_style_id)
|
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)
|
Data.load(IfcStore.get_file(), material.BIMMaterialProperties.ifc_style_id)
|
||||||
bpy.ops.bim.disable_editing_style()
|
bpy.ops.bim.disable_editing_style()
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|||||||
@@ -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]
|
|
||||||
@@ -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))
|
||||||
@@ -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]
|
||||||
Reference in New Issue
Block a user