mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-09 09:21:46 +00:00
Fix UI bugs for settings predefined types / assign_type to prevent invalid ifc (#7011)
This commit is contained in:
@@ -255,6 +255,8 @@ class IfcClassData:
|
|||||||
if not element:
|
if not element:
|
||||||
return False
|
return False
|
||||||
if element_type := ifcopenshell.util.element.get_type(element):
|
if element_type := ifcopenshell.util.element.get_type(element):
|
||||||
|
if element_type == element:
|
||||||
|
return False
|
||||||
# Allow for None due to https://github.com/buildingSMART/IFC4.3.x-development/issues/818
|
# Allow for None due to https://github.com/buildingSMART/IFC4.3.x-development/issues/818
|
||||||
return ifcopenshell.util.element.get_predefined_type(element_type) not in ("NOTDEFINED", None)
|
return ifcopenshell.util.element.get_predefined_type(element_type) not in ("NOTDEFINED", None)
|
||||||
return False
|
return False
|
||||||
|
|||||||
@@ -59,10 +59,14 @@ class BIM_PT_class(Panel):
|
|||||||
row = self.layout.row(align=True)
|
row = self.layout.row(align=True)
|
||||||
row.operator("bim.reassign_class", icon="CHECKMARK")
|
row.operator("bim.reassign_class", icon="CHECKMARK")
|
||||||
row.operator("bim.disable_reassign_class", icon="CANCEL", text="")
|
row.operator("bim.disable_reassign_class", icon="CANCEL", text="")
|
||||||
|
|
||||||
|
# If Entity has inherited Predefined Type, disable PredefinedType / ObjectType dropdown to forbid double typing. See #7006)
|
||||||
|
enable_predef_types = not IfcClassData.data["has_inherited_predefined_type"]
|
||||||
self.draw_class_dropdowns(
|
self.draw_class_dropdowns(
|
||||||
context,
|
context,
|
||||||
root_prop.get_ifc_predefined_types(rprops, context),
|
root_prop.get_ifc_predefined_types(rprops, context),
|
||||||
is_reassigning_class=True,
|
is_reassigning_class=True,
|
||||||
|
set_predefined_types_enabled=enable_predef_types,
|
||||||
)
|
)
|
||||||
self.layout.prop(rprops, "relating_class_object", icon="COPYDOWN")
|
self.layout.prop(rprops, "relating_class_object", icon="COPYDOWN")
|
||||||
else:
|
else:
|
||||||
@@ -82,22 +86,29 @@ class BIM_PT_class(Panel):
|
|||||||
return
|
return
|
||||||
|
|
||||||
ifc_predefined_types = root_prop.get_ifc_predefined_types(rprops, context)
|
ifc_predefined_types = root_prop.get_ifc_predefined_types(rprops, context)
|
||||||
self.draw_class_dropdowns(context, ifc_predefined_types)
|
# If Entity has inherited Predefined Type, disable PredefinedType / ObjectType dropdown to forbid double typing. See #7006)
|
||||||
|
enable_predef_types = not IfcClassData.data["has_inherited_predefined_type"]
|
||||||
|
|
||||||
|
self.draw_class_dropdowns(context, ifc_predefined_types, set_predefined_types_enabled=enable_predef_types)
|
||||||
row = self.layout.row(align=True)
|
row = self.layout.row(align=True)
|
||||||
op = row.operator("bim.assign_class")
|
op = row.operator("bim.assign_class")
|
||||||
op.ifc_class = rprops.ifc_class
|
op.ifc_class = rprops.ifc_class
|
||||||
op.predefined_type = rprops.ifc_predefined_type if ifc_predefined_types else ""
|
op.predefined_type = rprops.ifc_predefined_type if ifc_predefined_types else ""
|
||||||
op.userdefined_type = rprops.ifc_userdefined_type
|
op.userdefined_type = rprops.ifc_userdefined_type
|
||||||
|
|
||||||
def draw_class_dropdowns(self, context, ifc_predefined_types, is_reassigning_class=False):
|
def draw_class_dropdowns(
|
||||||
|
self, context, ifc_predefined_types, is_reassigning_class=False, set_predefined_types_enabled=True
|
||||||
|
):
|
||||||
props = tool.Root.get_root_props()
|
props = tool.Root.get_root_props()
|
||||||
layout = self.layout
|
layout = self.layout
|
||||||
prop_with_search(layout, props, "ifc_product")
|
prop_with_search(layout, props, "ifc_product")
|
||||||
prop_with_search(layout, props, "ifc_class")
|
prop_with_search(layout, props, "ifc_class")
|
||||||
if ifc_predefined_types:
|
if ifc_predefined_types:
|
||||||
prop_with_search(layout, props, "ifc_predefined_type")
|
row = prop_with_search(layout, props, "ifc_predefined_type")
|
||||||
|
row.enabled = set_predefined_types_enabled
|
||||||
if props.ifc_predefined_type == "USERDEFINED":
|
if props.ifc_predefined_type == "USERDEFINED":
|
||||||
row = layout.row()
|
row = layout.row()
|
||||||
row.prop(props, "ifc_userdefined_type")
|
row.prop(props, "ifc_userdefined_type")
|
||||||
|
row.enabled = set_predefined_types_enabled
|
||||||
if not is_reassigning_class:
|
if not is_reassigning_class:
|
||||||
prop_with_search(layout, props, "contexts")
|
prop_with_search(layout, props, "contexts")
|
||||||
|
|||||||
@@ -188,10 +188,7 @@ class Usecase:
|
|||||||
if not related_objects:
|
if not related_objects:
|
||||||
return
|
return
|
||||||
|
|
||||||
related_objects_set = set(related_objects)
|
|
||||||
|
|
||||||
ifc2x3 = self.file.schema == "IFC2X3"
|
ifc2x3 = self.file.schema == "IFC2X3"
|
||||||
|
|
||||||
related_objects_set = set(related_objects)
|
related_objects_set = set(related_objects)
|
||||||
if ifc2x3:
|
if ifc2x3:
|
||||||
types = next(iter(relating_type.ObjectTypeOf), None)
|
types = next(iter(relating_type.ObjectTypeOf), None)
|
||||||
@@ -257,6 +254,14 @@ class Usecase:
|
|||||||
relating_type=relating_type,
|
relating_type=relating_type,
|
||||||
)
|
)
|
||||||
self.map_material_usages(objects_to_change, relating_type)
|
self.map_material_usages(objects_to_change, relating_type)
|
||||||
|
|
||||||
|
# Remove PredefinedType / ObjectType if existing to forbid double typing(See #7006)
|
||||||
|
predefined_type = ifcopenshell.util.element.get_predefined_type(relating_type)
|
||||||
|
if predefined_type != "NOTDEFINED" and predefined_type is not None:
|
||||||
|
for obj in related_objects_set:
|
||||||
|
obj.ObjectType = None
|
||||||
|
if hasattr(obj, "PredefinedType"):
|
||||||
|
obj.PredefinedType = None
|
||||||
return types
|
return types
|
||||||
|
|
||||||
def map_material_usages(
|
def map_material_usages(
|
||||||
|
|||||||
@@ -139,6 +139,37 @@ class TestAssignType(test.bootstrap.IFC4):
|
|||||||
assert (material := ifcopenshell.util.element.get_material(element1))
|
assert (material := ifcopenshell.util.element.get_material(element1))
|
||||||
assert material.id() == material_id
|
assert material.id() == material_id
|
||||||
|
|
||||||
|
def test_remove_predefined_type_if_type_assignment(self):
|
||||||
|
"""
|
||||||
|
if an element has a PredefinedType, it should be removed when assigning a type.
|
||||||
|
This is because the type will have its own PredefinedType, and the element's PredefinedType
|
||||||
|
will conflict with it. (See #7006)
|
||||||
|
"""
|
||||||
|
element_type = ifcopenshell.api.root.create_entity(self.file, ifc_class="IfcWallType")
|
||||||
|
element_type.PredefinedType = "MOVABLE"
|
||||||
|
|
||||||
|
element = ifcopenshell.api.root.create_entity(self.file, ifc_class="IfcWall")
|
||||||
|
element.PredefinedType = "USERDEFINED"
|
||||||
|
element.ObjectType = "Test"
|
||||||
|
ifcopenshell.api.type.assign_type(self.file, related_objects=[element], relating_type=element_type)
|
||||||
|
assert element.PredefinedType is None
|
||||||
|
assert element.ObjectType is None
|
||||||
|
|
||||||
|
def test_keep_predefined_type_if_type_assignment_is_notdefined(self):
|
||||||
|
"""
|
||||||
|
if an element has a PredefinedType, it will be removed when assigning a type.(See #7006)
|
||||||
|
This behavior needs to be blocked if the PredefinedType of the typing Entity is set to "NOTDEFINED". (See #7011)
|
||||||
|
"""
|
||||||
|
element_type = ifcopenshell.api.root.create_entity(self.file, ifc_class="IfcWallType")
|
||||||
|
element_type.PredefinedType = "NOTDEFINED"
|
||||||
|
|
||||||
|
element = ifcopenshell.api.root.create_entity(self.file, ifc_class="IfcWall")
|
||||||
|
element.PredefinedType = "USERDEFINED"
|
||||||
|
element.ObjectType = "Test"
|
||||||
|
ifcopenshell.api.type.assign_type(self.file, related_objects=[element], relating_type=element_type)
|
||||||
|
assert element.PredefinedType == "USERDEFINED"
|
||||||
|
assert element.ObjectType == "Test"
|
||||||
|
|
||||||
|
|
||||||
class TestAssignTypeIFC2X3(test.bootstrap.IFC2X3, TestAssignType):
|
class TestAssignTypeIFC2X3(test.bootstrap.IFC2X3, TestAssignType):
|
||||||
pass
|
pass
|
||||||
|
|||||||
Reference in New Issue
Block a user