mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-19 14:41:25 +00:00
Swapping a Blender material for another is now auto synchronised.
This commit is contained in:
@@ -45,7 +45,7 @@ class IfcExporter:
|
|||||||
IfcStore.update_cache()
|
IfcStore.update_cache()
|
||||||
if bpy.context.scene.BIMProjectProperties.is_authoring:
|
if bpy.context.scene.BIMProjectProperties.is_authoring:
|
||||||
self.sync_deletions()
|
self.sync_deletions()
|
||||||
self.sync_object_placements()
|
self.sync_all_objects()
|
||||||
self.sync_edited_objects()
|
self.sync_edited_objects()
|
||||||
extension = self.ifc_export_settings.output_file.split(".")[-1]
|
extension = self.ifc_export_settings.output_file.split(".")[-1]
|
||||||
if extension == "ifczip":
|
if extension == "ifczip":
|
||||||
@@ -98,10 +98,11 @@ class IfcExporter:
|
|||||||
ifcopenshell.api.run("root.remove_product", self.file, **{"product": product})
|
ifcopenshell.api.run("root.remove_product", self.file, **{"product": product})
|
||||||
return results
|
return results
|
||||||
|
|
||||||
def sync_object_placements(self):
|
def sync_all_objects(self):
|
||||||
results = []
|
results = []
|
||||||
self.unit_scale = ifcopenshell.util.unit.calculate_unit_scale(self.file)
|
self.unit_scale = ifcopenshell.util.unit.calculate_unit_scale(self.file)
|
||||||
for ifc_definition_id, obj in IfcStore.id_map.items():
|
for ifc_definition_id in list(IfcStore.id_map.keys()):
|
||||||
|
obj = IfcStore.id_map[ifc_definition_id]
|
||||||
try:
|
try:
|
||||||
if isinstance(obj, bpy.types.Material):
|
if isinstance(obj, bpy.types.Material):
|
||||||
continue
|
continue
|
||||||
@@ -109,6 +110,9 @@ class IfcExporter:
|
|||||||
result = self.sync_object_placement(obj)
|
result = self.sync_object_placement(obj)
|
||||||
if result:
|
if result:
|
||||||
results.append(result)
|
results.append(result)
|
||||||
|
result = self.sync_object_material(obj)
|
||||||
|
if result:
|
||||||
|
results.append(result)
|
||||||
except ReferenceError:
|
except ReferenceError:
|
||||||
pass # The object is likely deleted
|
pass # The object is likely deleted
|
||||||
return results
|
return results
|
||||||
@@ -131,6 +135,17 @@ class IfcExporter:
|
|||||||
IfcStore.edited_objs.clear()
|
IfcStore.edited_objs.clear()
|
||||||
return results
|
return results
|
||||||
|
|
||||||
|
def sync_object_material(self, obj):
|
||||||
|
if not obj.data or not isinstance(obj.data, bpy.types.Mesh):
|
||||||
|
return
|
||||||
|
if not self.has_changed_materials(obj):
|
||||||
|
return
|
||||||
|
bpy.ops.bim.update_representation(obj=obj.name)
|
||||||
|
|
||||||
|
def has_changed_materials(self, obj):
|
||||||
|
checksum = obj.data.BIMMeshProperties.material_checksum
|
||||||
|
return checksum != str([s.id() for s in tool.Geometry.get_styles(obj) if s])
|
||||||
|
|
||||||
def sync_object_placement(self, obj):
|
def sync_object_placement(self, obj):
|
||||||
if not self.has_object_moved(obj):
|
if not self.has_object_moved(obj):
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -68,6 +68,7 @@ class MaterialCreator:
|
|||||||
self.add_default_material(element)
|
self.add_default_material(element)
|
||||||
if self.parse_representations(element):
|
if self.parse_representations(element):
|
||||||
self.assign_material_slots_to_faces()
|
self.assign_material_slots_to_faces()
|
||||||
|
tool.Geometry.record_object_materials(obj)
|
||||||
|
|
||||||
def add_default_material(self, element):
|
def add_default_material(self, element):
|
||||||
element_material = ifcopenshell.util.element.get_material(element)
|
element_material = ifcopenshell.util.element.get_material(element)
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
import bpy
|
import bpy
|
||||||
from bpy.types import Operator
|
from bpy.types import Operator
|
||||||
|
|
||||||
|
|
||||||
class BIM_OT_cityjson2ifc(Operator):
|
class BIM_OT_cityjson2ifc(Operator):
|
||||||
bl_idname = "bim.convert_cityjson2ifc"
|
bl_idname = "bim.convert_cityjson2ifc"
|
||||||
bl_label = "Convert CityJSON to IFC"
|
bl_label = "Convert CityJSON to IFC"
|
||||||
@@ -27,7 +28,7 @@ class BIM_OT_cityjson2ifc(Operator):
|
|||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
from cjio import cityjson
|
from cjio import cityjson
|
||||||
from ifccityjson.cityjson2ifc.cityjson2ifc import Cityjson2ifc
|
from ifccityjson.cityjson2ifc.cityjson2ifc import Cityjson2ifc
|
||||||
|
|
||||||
props = context.scene.ifccityjson_properties
|
props = context.scene.ifccityjson_properties
|
||||||
city_model = cityjson.load(props.input, transform=False)
|
city_model = cityjson.load(props.input, transform=False)
|
||||||
data = {
|
data = {
|
||||||
@@ -53,7 +54,7 @@ class BIM_OT_find_cityjson_lod(Operator):
|
|||||||
|
|
||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
from cjio import cityjson
|
from cjio import cityjson
|
||||||
|
|
||||||
props = context.scene.ifccityjson_properties
|
props = context.scene.ifccityjson_properties
|
||||||
city_model = cityjson.load(props.input)
|
city_model = cityjson.load(props.input)
|
||||||
lods = set()
|
lods = set()
|
||||||
|
|||||||
@@ -341,3 +341,4 @@ class BIMMeshProperties(PropertyGroup):
|
|||||||
is_parametric: BoolProperty(name="Is Parametric", default=False)
|
is_parametric: BoolProperty(name="Is Parametric", default=False)
|
||||||
ifc_definition: StringProperty(name="IFC Definition")
|
ifc_definition: StringProperty(name="IFC Definition")
|
||||||
ifc_parameters: CollectionProperty(name="IFC Parameters", type=IfcParameter)
|
ifc_parameters: CollectionProperty(name="IFC Parameters", type=IfcParameter)
|
||||||
|
material_checksum: StringProperty(name="Material Checksum")
|
||||||
|
|||||||
@@ -62,6 +62,7 @@ def add_representation(
|
|||||||
styles=geometry.get_styles(obj),
|
styles=geometry.get_styles(obj),
|
||||||
should_use_presentation_style_assignment=geometry.should_use_presentation_style_assignment(),
|
should_use_presentation_style_assignment=geometry.should_use_presentation_style_assignment(),
|
||||||
)
|
)
|
||||||
|
geometry.record_object_materials(obj)
|
||||||
|
|
||||||
ifc.run("geometry.assign_representation", product=element, representation=representation)
|
ifc.run("geometry.assign_representation", product=element, representation=representation)
|
||||||
|
|
||||||
|
|||||||
@@ -100,6 +100,7 @@ class Geometry:
|
|||||||
def is_mapped_representation(cls, representation): pass
|
def is_mapped_representation(cls, representation): pass
|
||||||
def is_type_product(cls, element): pass
|
def is_type_product(cls, element): pass
|
||||||
def link(cls, element, obj): pass
|
def link(cls, element, obj): pass
|
||||||
|
def record_object_materials(cls, obj): pass
|
||||||
def record_object_position(cls, obj): pass
|
def record_object_position(cls, obj): pass
|
||||||
def rename_object(cls, obj, name): pass
|
def rename_object(cls, obj, name): pass
|
||||||
def replace_object_with_empty(cls, obj): pass
|
def replace_object_with_empty(cls, obj): pass
|
||||||
|
|||||||
@@ -224,6 +224,10 @@ class Geometry(blenderbim.core.tool.Geometry):
|
|||||||
def link(cls, element, obj):
|
def link(cls, element, obj):
|
||||||
obj.BIMMeshProperties.ifc_definition_id = element.id()
|
obj.BIMMeshProperties.ifc_definition_id = element.id()
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def record_object_materials(cls, obj):
|
||||||
|
obj.data.BIMMeshProperties.material_checksum = str([s.id() for s in cls.get_styles(obj) if s])
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def record_object_position(cls, obj):
|
def record_object_position(cls, obj):
|
||||||
# These are recorded separately because they have different numerical tolerances
|
# These are recorded separately because they have different numerical tolerances
|
||||||
|
|||||||
@@ -401,3 +401,18 @@ Scenario: Export IFC - with changed style colour synchronised
|
|||||||
And an empty Blender session is started
|
And an empty Blender session is started
|
||||||
And I press "bim.load_project(filepath='{cwd}/test/files/export.ifc')"
|
And I press "bim.load_project(filepath='{cwd}/test/files/export.ifc')"
|
||||||
Then the material "Material" colour is "1,0,0,1"
|
Then the material "Material" colour is "1,0,0,1"
|
||||||
|
|
||||||
|
Scenario: Export IFC - with changed style element synchronised
|
||||||
|
Given an empty IFC project
|
||||||
|
And I add a cube
|
||||||
|
And the object "Cube" is selected
|
||||||
|
And I add a material
|
||||||
|
And I set "scene.BIMRootProperties.ifc_class" to "IfcWall"
|
||||||
|
And I press "bim.assign_class"
|
||||||
|
And the object "IfcWall/Cube" is selected
|
||||||
|
When I add a material
|
||||||
|
And the material "Material.001" colour is set to "1,0,0,1"
|
||||||
|
And I press "export_ifc.bim(filepath='{cwd}/test/files/export.ifc')"
|
||||||
|
And an empty Blender session is started
|
||||||
|
And I press "bim.load_project(filepath='{cwd}/test/files/export.ifc')"
|
||||||
|
Then the material "Material.001" colour is "1,0,0,1"
|
||||||
|
|||||||
@@ -91,6 +91,7 @@ def i_add_a_sun():
|
|||||||
|
|
||||||
|
|
||||||
@given("I add a material")
|
@given("I add a material")
|
||||||
|
@when("I add a material")
|
||||||
def i_add_a_material():
|
def i_add_a_material():
|
||||||
bpy.context.active_object.active_material = bpy.data.materials.new("Material")
|
bpy.context.active_object.active_material = bpy.data.materials.new("Material")
|
||||||
|
|
||||||
|
|||||||
@@ -74,6 +74,7 @@ class TestAddRepresentation:
|
|||||||
styles=["style"],
|
styles=["style"],
|
||||||
should_use_presentation_style_assignment=False,
|
should_use_presentation_style_assignment=False,
|
||||||
).should_be_called()
|
).should_be_called()
|
||||||
|
geometry.record_object_materials("obj").should_be_called()
|
||||||
|
|
||||||
# Assign representation to product
|
# Assign representation to product
|
||||||
ifc.run("geometry.assign_representation", product="element", representation="representation").should_be_called()
|
ifc.run("geometry.assign_representation", product="element", representation="representation").should_be_called()
|
||||||
|
|||||||
@@ -352,6 +352,19 @@ class TestLink(NewFile):
|
|||||||
assert obj.BIMMeshProperties.ifc_definition_id == element.id()
|
assert obj.BIMMeshProperties.ifc_definition_id == element.id()
|
||||||
|
|
||||||
|
|
||||||
|
class TestRecordObjectMaterials(NewFile):
|
||||||
|
def test_run(self):
|
||||||
|
obj = bpy.data.objects.new("Object", bpy.data.meshes.new("Mesh"))
|
||||||
|
ifc = ifcopenshell.file()
|
||||||
|
tool.Ifc.set(ifc)
|
||||||
|
style = ifc.createIfcSurfaceStyle()
|
||||||
|
material = bpy.data.materials.new("Material")
|
||||||
|
material.BIMMaterialProperties.ifc_style_id = style.id()
|
||||||
|
obj.data.materials.append(material)
|
||||||
|
subject.record_object_materials(obj)
|
||||||
|
assert obj.data.BIMMeshProperties.material_checksum == str([style.id()])
|
||||||
|
|
||||||
|
|
||||||
class TestRecordObjectPosition(NewFile):
|
class TestRecordObjectPosition(NewFile):
|
||||||
def test_run(self):
|
def test_run(self):
|
||||||
obj = bpy.data.objects.new("Object", None)
|
obj = bpy.data.objects.new("Object", None)
|
||||||
|
|||||||
Reference in New Issue
Block a user