mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-12 06:32:09 +00:00
Fix #3957. Fix bug where shared properties were not edited independently.
This commit is contained in:
@@ -158,9 +158,9 @@ class Usecase:
|
|||||||
def execute(self):
|
def execute(self):
|
||||||
self.update_pset_name()
|
self.update_pset_name()
|
||||||
self.load_pset_template()
|
self.load_pset_template()
|
||||||
self.update_existing_properties()
|
existing_props = self.update_existing_properties()
|
||||||
new_properties = self.add_new_properties()
|
new_props = self.add_new_properties()
|
||||||
self.extend_pset_with_new_properties(new_properties)
|
self.assign_new_properties(existing_props + new_props)
|
||||||
|
|
||||||
def update_pset_name(self):
|
def update_pset_name(self):
|
||||||
if self.settings["name"]:
|
if self.settings["name"]:
|
||||||
@@ -198,18 +198,26 @@ class Usecase:
|
|||||||
# IfcPropertySingleValue. Or maybe the user should
|
# IfcPropertySingleValue. Or maybe the user should
|
||||||
# just delete the property first? - vulevukusej
|
# just delete the property first? - vulevukusej
|
||||||
def update_existing_properties(self):
|
def update_existing_properties(self):
|
||||||
|
existing_props = []
|
||||||
for prop in self.get_properties():
|
for prop in self.get_properties():
|
||||||
if not self._should_update_prop(prop):
|
if not self._should_update_prop(prop):
|
||||||
|
existing_props.append(prop)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
if self.file.get_total_inverses(prop) > 1:
|
||||||
|
continue # Treat as a new property to avoid affecting other psets.
|
||||||
|
|
||||||
if prop.is_a("IfcPropertyEnumeratedValue"):
|
if prop.is_a("IfcPropertyEnumeratedValue"):
|
||||||
self.update_existing_prop_enum(prop)
|
prop = self.update_existing_prop_enum(prop)
|
||||||
|
if prop:
|
||||||
|
existing_props.append(prop)
|
||||||
elif prop.is_a("IfcPropertySingleValue"):
|
elif prop.is_a("IfcPropertySingleValue"):
|
||||||
self.update_existing_prop_single_value(prop)
|
prop = self.update_existing_prop_single_value(prop)
|
||||||
|
if prop:
|
||||||
|
existing_props.append(prop)
|
||||||
else:
|
else:
|
||||||
raise NotImplementedError(f"Updating '{prop.is_a()}' properties is not supported yet")
|
raise NotImplementedError(f"Updating '{prop.is_a()}' properties is not supported yet")
|
||||||
|
return existing_props
|
||||||
|
|
||||||
def update_existing_prop_enum(self, prop):
|
def update_existing_prop_enum(self, prop):
|
||||||
"""
|
"""
|
||||||
@@ -228,10 +236,7 @@ class Usecase:
|
|||||||
sel_vals.append(ifc_val)
|
sel_vals.append(ifc_val)
|
||||||
prop.EnumerationValues = tuple(sel_vals) or None
|
prop.EnumerationValues = tuple(sel_vals) or None
|
||||||
|
|
||||||
elif (
|
elif isinstance(value, ifcopenshell.entity_instance) and value.is_a("IfcPropertyEnumeratedValue"):
|
||||||
isinstance(value, ifcopenshell.entity_instance)
|
|
||||||
and value.is_a("IfcPropertyEnumeratedValue")
|
|
||||||
):
|
|
||||||
if not value.EnumerationReference.EnumerationValues:
|
if not value.EnumerationReference.EnumerationValues:
|
||||||
if self._try_purge(prop):
|
if self._try_purge(prop):
|
||||||
return
|
return
|
||||||
@@ -245,6 +250,7 @@ class Usecase:
|
|||||||
if unit:
|
if unit:
|
||||||
prop.Unit = unit
|
prop.Unit = unit
|
||||||
del self.settings["properties"][prop.Name]
|
del self.settings["properties"][prop.Name]
|
||||||
|
return prop
|
||||||
|
|
||||||
def update_existing_prop_single_value(self, prop):
|
def update_existing_prop_single_value(self, prop):
|
||||||
"""
|
"""
|
||||||
@@ -267,6 +273,7 @@ class Usecase:
|
|||||||
if unit:
|
if unit:
|
||||||
prop.Unit = unit
|
prop.Unit = unit
|
||||||
del self.settings["properties"][prop.Name]
|
del self.settings["properties"][prop.Name]
|
||||||
|
return prop
|
||||||
|
|
||||||
def add_new_properties(self):
|
def add_new_properties(self):
|
||||||
properties = []
|
properties = []
|
||||||
@@ -284,9 +291,7 @@ class Usecase:
|
|||||||
kwargs = {"Name": name, "NominalValue": value}
|
kwargs = {"Name": name, "NominalValue": value}
|
||||||
if unit:
|
if unit:
|
||||||
kwargs["Unit"] = unit
|
kwargs["Unit"] = unit
|
||||||
properties.append(
|
properties.append(self.file.create_entity("IfcPropertySingleValue", **kwargs))
|
||||||
self.file.create_entity("IfcPropertySingleValue", **kwargs)
|
|
||||||
)
|
|
||||||
|
|
||||||
else:
|
else:
|
||||||
raise ValueError(f"{value.is_a()} cannot be assigned to the property set '{name}'")
|
raise ValueError(f"{value.is_a()} cannot be assigned to the property set '{name}'")
|
||||||
@@ -307,11 +312,8 @@ class Usecase:
|
|||||||
self.file.create_entity(
|
self.file.create_entity(
|
||||||
"IfcPropertyListValue",
|
"IfcPropertyListValue",
|
||||||
Name=name,
|
Name=name,
|
||||||
ListValues=[
|
ListValues=[self.file.create_entity(ifc_class, v) for v in value],
|
||||||
self.file.create_entity(ifc_class, v)
|
Unit=unit,
|
||||||
for v in value
|
|
||||||
],
|
|
||||||
Unit=unit
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
break
|
break
|
||||||
@@ -321,7 +323,7 @@ class Usecase:
|
|||||||
"IFCPROPERTYENUMERATION",
|
"IFCPROPERTYENUMERATION",
|
||||||
Name=name,
|
Name=name,
|
||||||
EnumerationValues=pset_template.Enumerators.EnumerationValues,
|
EnumerationValues=pset_template.Enumerators.EnumerationValues,
|
||||||
**({"Unit": unit} if unit else {})
|
**({"Unit": unit} if unit else {}),
|
||||||
)
|
)
|
||||||
prop_enum_value = self.file.create_entity(
|
prop_enum_value = self.file.create_entity(
|
||||||
"IFCPROPERTYENUMERATEDVALUE",
|
"IFCPROPERTYENUMERATEDVALUE",
|
||||||
@@ -347,14 +349,10 @@ class Usecase:
|
|||||||
if unit:
|
if unit:
|
||||||
args["Unit"] = unit
|
args["Unit"] = unit
|
||||||
|
|
||||||
properties.append(
|
properties.append(self.file.create_entity("IfcPropertySingleValue", **args))
|
||||||
self.file.create_entity("IfcPropertySingleValue", **args)
|
|
||||||
)
|
|
||||||
return properties
|
return properties
|
||||||
|
|
||||||
def extend_pset_with_new_properties(self, new_properties):
|
def assign_new_properties(self, props):
|
||||||
props = list(self.get_properties())
|
|
||||||
props.extend(new_properties)
|
|
||||||
if hasattr(self.settings["pset"], "HasProperties"):
|
if hasattr(self.settings["pset"], "HasProperties"):
|
||||||
self.settings["pset"].HasProperties = props
|
self.settings["pset"].HasProperties = props
|
||||||
elif hasattr(self.settings["pset"], "Properties"):
|
elif hasattr(self.settings["pset"], "Properties"):
|
||||||
|
|||||||
@@ -95,6 +95,7 @@ class TestEditPset(test.bootstrap.IFC4):
|
|||||||
element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall")
|
element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall")
|
||||||
pset = ifcopenshell.api.run("pset.add_pset", self.file, product=element, name="Pset_WallCommon")
|
pset = ifcopenshell.api.run("pset.add_pset", self.file, product=element, name="Pset_WallCommon")
|
||||||
ifcopenshell.api.run("pset.edit_pset", self.file, pset=pset, properties={"Reference": "Foo"})
|
ifcopenshell.api.run("pset.edit_pset", self.file, pset=pset, properties={"Reference": "Foo"})
|
||||||
|
print("test")
|
||||||
ifcopenshell.api.run("pset.edit_pset", self.file, pset=pset, properties={"Reference": None}, should_purge=True)
|
ifcopenshell.api.run("pset.edit_pset", self.file, pset=pset, properties={"Reference": None}, should_purge=True)
|
||||||
pset = element.IsDefinedBy[0].RelatingPropertyDefinition
|
pset = element.IsDefinedBy[0].RelatingPropertyDefinition
|
||||||
assert len(pset.HasProperties) == 0
|
assert len(pset.HasProperties) == 0
|
||||||
@@ -168,7 +169,9 @@ class TestEditPset(test.bootstrap.IFC4):
|
|||||||
assert pset.HasProperties[0].NominalValue.wrappedValue == 34
|
assert pset.HasProperties[0].NominalValue.wrappedValue == 34
|
||||||
|
|
||||||
def test_editing_list_valued_properties(self):
|
def test_editing_list_valued_properties(self):
|
||||||
cable = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcDistributionPort", predefined_type="CABLE")
|
cable = ifcopenshell.api.run(
|
||||||
|
"root.create_entity", self.file, ifc_class="IfcDistributionPort", predefined_type="CABLE"
|
||||||
|
)
|
||||||
pset = ifcopenshell.api.run("pset.add_pset", self.file, product=cable, name="Pset_DistributionPortTypeCable")
|
pset = ifcopenshell.api.run("pset.add_pset", self.file, product=cable, name="Pset_DistributionPortTypeCable")
|
||||||
ifcopenshell.api.run(
|
ifcopenshell.api.run(
|
||||||
"pset.edit_pset",
|
"pset.edit_pset",
|
||||||
@@ -178,10 +181,10 @@ class TestEditPset(test.bootstrap.IFC4):
|
|||||||
"Protocols": ["One", "Two", "Three"],
|
"Protocols": ["One", "Two", "Three"],
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
assert pset.HasProperties[0].is_a('IfcPropertyListValue')
|
assert pset.HasProperties[0].is_a("IfcPropertyListValue")
|
||||||
assert len(pset.HasProperties[0].ListValues) == 3
|
assert len(pset.HasProperties[0].ListValues) == 3
|
||||||
assert set(map(ifcopenshell.entity_instance.is_a, pset.HasProperties[0].ListValues)) == {'IfcIdentifier'}
|
assert set(map(ifcopenshell.entity_instance.is_a, pset.HasProperties[0].ListValues)) == {"IfcIdentifier"}
|
||||||
assert list(map(operator.itemgetter(0), pset.HasProperties[0].ListValues)) == ['One', 'Two', 'Three']
|
assert list(map(operator.itemgetter(0), pset.HasProperties[0].ListValues)) == ["One", "Two", "Three"]
|
||||||
|
|
||||||
def test_editing_properties_with_an_explicit_type(self):
|
def test_editing_properties_with_an_explicit_type(self):
|
||||||
element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall")
|
element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall")
|
||||||
@@ -262,10 +265,10 @@ class TestEditPset(test.bootstrap.IFC4):
|
|||||||
"Name": "foo",
|
"Name": "foo",
|
||||||
"TemplateType": "P_SINGLEVALUE",
|
"TemplateType": "P_SINGLEVALUE",
|
||||||
"PrimaryMeasureType": "IfcContextDependentMeasure",
|
"PrimaryMeasureType": "IfcContextDependentMeasure",
|
||||||
}
|
},
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
}
|
},
|
||||||
)
|
)
|
||||||
element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall")
|
element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall")
|
||||||
pset = ifcopenshell.api.run("pset.add_pset", self.file, product=element, name="Foo_Bar")
|
pset = ifcopenshell.api.run("pset.add_pset", self.file, product=element, name="Foo_Bar")
|
||||||
@@ -282,3 +285,19 @@ class TestEditPset(test.bootstrap.IFC4):
|
|||||||
assert pset.HasProperties[0].Name == "foo"
|
assert pset.HasProperties[0].Name == "foo"
|
||||||
assert pset.HasProperties[0].NominalValue.is_a("IfcContextDependentMeasure")
|
assert pset.HasProperties[0].NominalValue.is_a("IfcContextDependentMeasure")
|
||||||
assert pset.HasProperties[0].NominalValue.wrappedValue == 12
|
assert pset.HasProperties[0].NominalValue.wrappedValue == 12
|
||||||
|
|
||||||
|
def test_editing_a_shared_property(self):
|
||||||
|
element1 = self.file.createIfcMaterial()
|
||||||
|
element2 = self.file.createIfcMaterial()
|
||||||
|
pset1 = ifcopenshell.api.run("pset.add_pset", self.file, product=element1, name="Foo_Bar")
|
||||||
|
pset2 = ifcopenshell.api.run("pset.add_pset", self.file, product=element2, name="Foo_Bar")
|
||||||
|
ifcopenshell.api.run("pset.edit_pset", self.file, pset=pset1, properties={"foo": "bar"})
|
||||||
|
ifcopenshell.api.run("pset.edit_pset", self.file, pset=pset2, properties={"foo2": "bar2"})
|
||||||
|
element1.HasProperties[0].Properties = list(element1.HasProperties[0].Properties) + list(
|
||||||
|
element2.HasProperties[0].Properties
|
||||||
|
)
|
||||||
|
assert ifcopenshell.util.element.get_pset(element1, "Foo_Bar", "foo2") == "bar2"
|
||||||
|
assert ifcopenshell.util.element.get_pset(element2, "Foo_Bar", "foo2") == "bar2"
|
||||||
|
ifcopenshell.api.run("pset.edit_pset", self.file, pset=pset1, properties={"foo2": "bar3"})
|
||||||
|
assert ifcopenshell.util.element.get_pset(element1, "Foo_Bar", "foo2") == "bar3"
|
||||||
|
assert ifcopenshell.util.element.get_pset(element2, "Foo_Bar", "foo2") == "bar2"
|
||||||
|
|||||||
Reference in New Issue
Block a user