Column profiles now auto update when you change the material profile

This commit is contained in:
Dion Moult
2021-06-21 12:21:46 +10:00
parent e0b93a70d3
commit 54526960c8
8 changed files with 87 additions and 30 deletions
@@ -396,7 +396,7 @@ class CreateDrawing(bpy.types.Operator):
def get_classes(self, element, position, svg_writer):
classes = [position, element.is_a()]
material = ifcopenshell.util.element.get_material(element)
material = ifcopenshell.util.element.get_material(element, should_skip_usage=True)
if material:
classes.append("material-{}".format(re.sub("[^0-9a-zA-Z]+", "", self.get_material_name(material))))
classes.append("globalid-{}".format(element.GlobalId))
@@ -58,7 +58,7 @@ class AddRepresentation(bpy.types.Operator):
obj: bpy.props.StringProperty()
context_id: bpy.props.IntProperty()
ifc_representation_class: bpy.props.StringProperty()
profile_set: bpy.props.IntProperty()
profile_set_usage: bpy.props.IntProperty()
def execute(self, context):
obj = bpy.data.objects.get(self.obj) if self.obj else bpy.context.active_object
@@ -94,7 +94,7 @@ class AddRepresentation(bpy.types.Operator):
"should_force_faceted_brep": context.scene.BIMGeometryProperties.should_force_faceted_brep,
"should_force_triangulation": context.scene.BIMGeometryProperties.should_force_triangulation,
"ifc_representation_class": self.ifc_representation_class,
"profile_set": self.file.by_id(self.profile_set) if self.profile_set else None
"profile_set_usage": self.file.by_id(self.profile_set_usage) if self.profile_set_usage else None
}
result = ifcopenshell.api.run("geometry.add_representation", self.file, **representation_data)
@@ -46,11 +46,11 @@ def ensure_solid(usecase_path, ifc_file, settings):
if not parametric or parametric["Engine"] != "BlenderBIM.DumbColumn":
return
material = ifcopenshell.util.element.get_material(product)
if material and material.is_a("IfcMaterialProfileSet"):
settings["profile_set"] = material
if material and material.is_a("IfcMaterialProfileSetUsage"):
settings["profile_set_usage"] = material
else:
return
settings["ifc_representation_class"] = "IfcExtrudedAreaSolid/IfcMaterialProfileSet"
settings["ifc_representation_class"] = "IfcExtrudedAreaSolid/IfcMaterialProfileSetUsage"
class DumbColumnGenerator:
@@ -110,20 +110,51 @@ class DumbColumnGenerator:
bpy.ops.bim.assign_class(
obj=obj.name, ifc_class="IfcColumn", predefined_type="COLUMN", should_add_representation=False
)
element = self.file.by_id(obj.BIMObjectProperties.ifc_definition_id)
bpy.ops.bim.assign_type(relating_type=self.relating_type.id(), related_object=obj.name)
profile_set_usage = ifcopenshell.util.element.get_material(element)
bpy.ops.bim.add_representation(
obj=obj.name,
context_id=ifcopenshell.util.representation.get_context(self.file, "Model", "Body", "MODEL_VIEW").id(),
ifc_representation_class="IfcExtrudedAreaSolid/IfcMaterialProfileSet",
profile_set=self.profile_set.id(),
)
representation = ifcopenshell.util.representation.get_representation(
self.file.by_id(obj.BIMObjectProperties.ifc_definition_id), "Model", "Body", "MODEL_VIEW"
ifc_representation_class="IfcExtrudedAreaSolid/IfcMaterialProfileSetUsage",
profile_set_usage=profile_set_usage.id(),
)
representation = ifcopenshell.util.representation.get_representation(element, "Model", "Body", "MODEL_VIEW")
bpy.ops.bim.switch_representation(obj=obj.name, ifc_definition_id=representation.id(), should_reload=True)
element = self.file.by_id(obj.BIMObjectProperties.ifc_definition_id)
pset = ifcopenshell.api.run("pset.add_pset", self.file, product=element, name="EPset_Parametric")
ifcopenshell.api.run("pset.edit_pset", self.file, pset=pset, properties={"Engine": "BlenderBIM.DumbColumn"})
MaterialData.load(self.file)
obj.select_set(True)
return obj
class DumbColumnRegenerator:
def regenerate_from_profile(self, usecase_path, ifc_file, settings):
self.file = IfcStore.get_file()
self.unit_scale = ifcopenshell.util.unit.calculate_unit_scale(ifc_file)
profile = settings["profile"].Profile
if not profile:
return
for profile_set in [
mp.ToMaterialProfileSet[0] for mp in self.file.get_inverse(profile) if mp.is_a("IfcMaterialProfile")
]:
for inverse in ifc_file.get_inverse(profile_set):
if not inverse.is_a("IfcMaterialProfileSetUsage"):
continue
if ifc_file.schema == "IFC2X3":
for rel in ifc_file.get_inverse(inverse):
if not rel.is_a("IfcRelAssociatesMaterial"):
continue
for element in rel.RelatedObjects:
self.change_profile(element)
else:
for rel in inverse.AssociatedTo:
for element in rel.RelatedObjects:
self.change_profile(element)
def change_profile(self, element):
obj = IfcStore.get_element(element.id())
if not obj:
return
representation = ifcopenshell.util.representation.get_representation(element, "Model", "Body", "MODEL_VIEW")
bpy.ops.bim.switch_representation(obj=obj.name, ifc_definition_id=representation.id(), should_reload=True)
@@ -50,3 +50,8 @@ def load_post(*args):
ifcopenshell.api.add_pre_listener(
"geometry.add_representation", "BlenderBIM.DumbColumn.EnsureSolid", column.ensure_solid
)
ifcopenshell.api.add_post_listener(
"material.edit_profile",
"BlenderBIM.DumbColumn.RegenerateFromProfile",
column.DumbColumnRegenerator().regenerate_from_profile,
)
@@ -30,9 +30,9 @@ class Usecase:
# IfcExtrudedAreaSolid/IfcCircleProfileDef
# IfcExtrudedAreaSolid/IfcArbitraryClosedProfileDef
# IfcExtrudedAreaSolid/IfcArbitraryProfileDefWithVoids
# IfcExtrudedAreaSolid/IfcMaterialProfileSet
# IfcExtrudedAreaSolid/IfcMaterialProfileSetUsage
"ifc_representation_class": None, # Whether to cast a mesh into a particular class
"profile_set": None, # The material profile set if the extrusion requires it
"profile_set_usage": None, # The material profile set if the extrusion requires it
}
self.ifc_vertices = []
for key, value in settings.items():
@@ -220,7 +220,7 @@ class Usecase:
return self.create_arbitrary_extrusion_representation()
elif self.settings["ifc_representation_class"] == "IfcExtrudedAreaSolid/IfcArbitraryProfileDefWithVoids":
return self.create_arbitrary_void_extrusion_representation()
elif self.settings["ifc_representation_class"] == "IfcExtrudedAreaSolid/IfcMaterialProfileSet":
elif self.settings["ifc_representation_class"] == "IfcExtrudedAreaSolid/IfcMaterialProfileSetUsage":
return self.create_material_profile_set_extrusion_representation()
return self.create_mesh_representation()
@@ -410,10 +410,8 @@ class Usecase:
)
def create_material_profile_set_extrusion_representation(self):
profile_def = (
self.settings["profile_set"].CompositeProfile
or self.settings["profile_set"].MaterialProfiles[0].Profile
)
profile_set = self.settings["profile_set_usage"].ForProfileSet
profile_def = profile_set.CompositeProfile or profile_set.MaterialProfiles[0].Profile
position = None
if self.file.schema == "IFC2X3":
position = self.file.createIfcAxis2Placement3D(
@@ -1,3 +1,6 @@
import ifcopenshell.util.representation
class Usecase:
def __init__(self, file, **settings):
self.file = file
@@ -6,9 +9,28 @@ class Usecase:
self.settings[key] = value
def execute(self):
if (
self.settings["material_profile"].Profile
and len(self.file.get_inverse(self.settings["material_profile"].Profile)) == 1
):
self.file.remove(self.settings["material_profile"].Profile)
old_profile = self.settings["material_profile"].Profile
self.settings["material_profile"].Profile = self.settings["profile"]
for profile_set in self.settings["material_profile"].ToMaterialProfileSet:
for inverse in self.file.get_inverse(profile_set):
if not inverse.is_a("IfcMaterialProfileSetUsage"):
continue
if self.file.schema == "IFC2X3":
for rel in self.file.get_inverse(inverse):
if not rel.is_a("IfcRelAssociatesMaterial"):
continue
for element in rel.RelatedObjects:
self.change_profile(element)
else:
for rel in inverse.AssociatedTo:
for element in rel.RelatedObjects:
self.change_profile(element)
if old_profile and len(self.file.get_inverse(old_profile)) == 0:
self.file.remove(old_profile)
def change_profile(self, element):
representation = ifcopenshell.util.representation.get_representation(element, "Model", "Body", "MODEL_VIEW")
for subelement in self.file.traverse(representation):
if subelement.is_a("IfcSweptAreaSolid"):
subelement.SweptArea = self.settings["profile"]
@@ -62,14 +62,15 @@ def get_type(element):
return relationship.RelatingType
def get_material(element):
def get_material(element, should_skip_usage=False):
if hasattr(element, "HasAssociations") and element.HasAssociations:
for relationship in element.HasAssociations:
if relationship.is_a("IfcRelAssociatesMaterial"):
if relationship.RelatingMaterial.is_a("IfcMaterialLayerSetUsage"):
return relationship.RelatingMaterial.ForLayerSet
elif relationship.RelatingMaterial.is_a("IfcMaterialProfileSetUsage"):
return relationship.RelatingMaterial.ForProfileSet
if should_skip_usage:
if relationship.RelatingMaterial.is_a("IfcMaterialLayerSetUsage"):
return relationship.RelatingMaterial.ForLayerSet
elif relationship.RelatingMaterial.is_a("IfcMaterialProfileSetUsage"):
return relationship.RelatingMaterial.ForProfileSet
return relationship.RelatingMaterial
relating_type = get_type(element)
if hasattr(relating_type, "HasAssociations") and relating_type.HasAssociations:
@@ -221,7 +221,7 @@ class Selector:
key = ".".join(key.split(".")[1:])
elif "." in key and key.split(".")[0] == "material":
try:
element = ifcopenshell.util.element.get_material(element)
element = ifcopenshell.util.element.get_material(element, should_skip_usage=True)
if not element:
return None
except: