New verbose option in util get_pset(s) which lets you get ID and class for complex processing.

This commit is contained in:
Dion Moult
2023-10-15 08:57:26 +11:00
parent 8d25bfca18
commit 6f42c71e88
2 changed files with 108 additions and 45 deletions
@@ -19,7 +19,7 @@
import ifcopenshell import ifcopenshell
def get_pset(element, name, prop=None, should_inherit=True): def get_pset(element, name, prop=None, should_inherit=True, verbose=False):
"""Retrieve a single property set or single property """Retrieve a single property set or single property
This is more efficient than ifcopenshell.util.element.get_psets if you know This is more efficient than ifcopenshell.util.element.get_psets if you know
@@ -64,7 +64,7 @@ def get_pset(element, name, prop=None, should_inherit=True):
if should_inherit: if should_inherit:
element_type = ifcopenshell.util.element.get_type(element) element_type = ifcopenshell.util.element.get_type(element)
if element_type: if element_type:
type_pset = get_pset(element_type, name, prop, should_inherit=False) type_pset = get_pset(element_type, name, prop, should_inherit=False, verbose=verbose)
for relationship in element.IsDefinedBy: for relationship in element.IsDefinedBy:
if relationship.is_a("IfcRelDefinesByProperties"): if relationship.is_a("IfcRelDefinesByProperties"):
definition = relationship.RelatingPropertyDefinition definition = relationship.RelatingPropertyDefinition
@@ -77,19 +77,19 @@ def get_pset(element, name, prop=None, should_inherit=True):
if not prop: if not prop:
if type_pset: if type_pset:
occurrence_pset = get_property_definition(pset) occurrence_pset = get_property_definition(pset, verbose=verbose)
if occurrence_pset: if occurrence_pset:
type_pset.update(occurrence_pset) type_pset.update(occurrence_pset)
return type_pset return type_pset
return get_property_definition(pset) return get_property_definition(pset, verbose=verbose)
value = get_property_definition(pset, prop) value = get_property_definition(pset, prop=prop, verbose=verbose)
if value is None and type_pset is not None: if value is None and type_pset is not None:
return type_pset return type_pset
return value return value
def get_psets(element, psets_only=False, qtos_only=False, should_inherit=True): def get_psets(element, psets_only=False, qtos_only=False, should_inherit=True, verbose=False):
"""Retrieve property sets, their related properties' names & values and ids. """Retrieve property sets, their related properties' names & values and ids.
If should_inherit is true, the pset "id" only refers to the ID of the If should_inherit is true, the pset "id" only refers to the ID of the
@@ -122,12 +122,12 @@ def get_psets(element, psets_only=False, qtos_only=False, should_inherit=True):
continue continue
if qtos_only and not definition.is_a("IfcElementQuantity"): if qtos_only and not definition.is_a("IfcElementQuantity"):
continue continue
psets[definition.Name] = get_property_definition(definition) psets[definition.Name] = get_property_definition(definition, verbose=verbose)
elif element.is_a("IfcMaterialDefinition") or element.is_a("IfcProfileDef"): elif element.is_a("IfcMaterialDefinition") or element.is_a("IfcProfileDef"):
for definition in getattr(element, "HasProperties", None) or []: for definition in getattr(element, "HasProperties", None) or []:
if qtos_only: if qtos_only:
continue continue
psets[definition.Name] = get_property_definition(definition) psets[definition.Name] = get_property_definition(definition, verbose=verbose)
elif hasattr(element, "IsDefinedBy"): elif hasattr(element, "IsDefinedBy"):
if should_inherit: if should_inherit:
element_type = ifcopenshell.util.element.get_type(element) element_type = ifcopenshell.util.element.get_type(element)
@@ -140,21 +140,21 @@ def get_psets(element, psets_only=False, qtos_only=False, should_inherit=True):
continue continue
if qtos_only and not definition.is_a("IfcElementQuantity"): if qtos_only and not definition.is_a("IfcElementQuantity"):
continue continue
psets.setdefault(definition.Name, {}).update(get_property_definition(definition)) psets.setdefault(definition.Name, {}).update(get_property_definition(definition, verbose=verbose))
return psets return psets
def get_property_definition(definition, prop=None): def get_property_definition(definition, prop=None, verbose=False):
if not definition: if not definition:
return return
if prop: if prop:
if definition.is_a("IfcElementQuantity"): if definition.is_a("IfcElementQuantity"):
return get_quantity(definition.Quantities, prop) return get_quantity(definition.Quantities, prop, verbose=verbose)
elif definition.is_a("IfcPropertySet"): elif definition.is_a("IfcPropertySet"):
return get_property(definition.HasProperties, prop) return get_property(definition.HasProperties, prop, verbose=verbose)
elif definition.is_a("IfcMaterialProperties") or definition.is_a("IfcProfileProperties"): elif definition.is_a("IfcMaterialProperties") or definition.is_a("IfcProfileProperties"):
return get_property(definition.Properties, prop) return get_property(definition.Properties, prop, verbose=verbose)
else: else:
# Entity introduced in IFC4 # Entity introduced in IFC4
# definition.is_a('IfcPreDefinedPropertySet'): # definition.is_a('IfcPreDefinedPropertySet'):
@@ -166,11 +166,11 @@ def get_property_definition(definition, prop=None):
props = {} props = {}
if definition.is_a("IfcElementQuantity"): if definition.is_a("IfcElementQuantity"):
props.update(get_quantities(definition.Quantities)) props.update(get_quantities(definition.Quantities, verbose=verbose))
elif definition.is_a("IfcPropertySet"): elif definition.is_a("IfcPropertySet"):
props.update(get_properties(definition.HasProperties)) props.update(get_properties(definition.HasProperties, verbose=verbose))
elif definition.is_a("IfcMaterialProperties") or definition.is_a("IfcProfileProperties"): elif definition.is_a("IfcMaterialProperties") or definition.is_a("IfcProfileProperties"):
props.update(get_properties(definition.Properties)) props.update(get_properties(definition.Properties, verbose=verbose))
else: else:
# Entity introduced in IFC4 # Entity introduced in IFC4
# definition.is_a('IfcPreDefinedPropertySet'): # definition.is_a('IfcPreDefinedPropertySet'):
@@ -181,76 +181,105 @@ def get_property_definition(definition, prop=None):
return props return props
def get_quantity(quantities, name): def get_quantity(quantities, name, verbose=False):
for quantity in quantities or []: for quantity in quantities or []:
if quantity.Name != name: if quantity.Name != name:
continue continue
if quantity.is_a("IfcPhysicalSimpleQuantity"): if quantity.is_a("IfcPhysicalSimpleQuantity"):
return quantity[3] result = quantity[3]
results[quantity.Name] = quantity[3]
elif quantity.is_a("IfcPhysicalComplexQuantity"): elif quantity.is_a("IfcPhysicalComplexQuantity"):
data = {k: v for k, v in quantity.get_info().items() if v is not None and k != "Name"} data = {k: v for k, v in quantity.get_info().items() if v is not None and k != "Name"}
data["properties"] = get_quantities(quantity.HasQuantities) data["properties"] = get_quantities(quantity.HasQuantities)
del data["HasQuantities"] del data["HasQuantities"]
return data result = data
if verbose:
result = {"id": quantity.id(), "class": quantity.is_a(), "value": result}
return result
def get_quantities(quantities, name=None): def get_quantities(quantities, verbose=False):
results = {} results = {}
for quantity in quantities or []: for quantity in quantities or []:
if quantity.is_a("IfcPhysicalSimpleQuantity"): if quantity.is_a("IfcPhysicalSimpleQuantity"):
results[quantity.Name] = quantity[3] results[quantity.Name] = quantity[3]
if verbose:
results[quantity.Name] = {
"id": quantity.id(),
"class": quantity.is_a(),
"value": results[quantity.Name],
}
elif quantity.is_a("IfcPhysicalComplexQuantity"): elif quantity.is_a("IfcPhysicalComplexQuantity"):
data = {k: v for k, v in quantity.get_info().items() if v is not None and k != "Name"} data = {k: v for k, v in quantity.get_info().items() if v is not None and k != "Name"}
data["properties"] = get_quantities(quantity.HasQuantities) data["properties"] = get_quantities(quantity.HasQuantities)
del data["HasQuantities"] del data["HasQuantities"]
results[quantity.Name] = data results[quantity.Name] = data
if verbose:
results[quantity.Name] = {
"id": quantity.id(),
"class": quantity.is_a(),
"value": results[quantity.Name],
}
return results return results
def get_property(properties, name): def get_property(properties, name, verbose=False):
for prop in properties or []: for prop in properties or []:
if prop.Name != name: if prop.Name != name:
continue continue
if prop.is_a("IfcPropertySingleValue"): if prop.is_a("IfcPropertySingleValue"):
return prop.NominalValue.wrappedValue if prop.NominalValue else None result = prop.NominalValue.wrappedValue if prop.NominalValue else None
elif prop.is_a("IfcPropertyEnumeratedValue"): elif prop.is_a("IfcPropertyEnumeratedValue"):
return [v.wrappedValue for v in prop.EnumerationValues] if prop.EnumerationValues else None result = [v.wrappedValue for v in prop.EnumerationValues] if prop.EnumerationValues else None
elif prop.is_a("IfcPropertyListValue"): elif prop.is_a("IfcPropertyListValue"):
return [v.wrappedValue for v in prop.ListValues] or None result = [v.wrappedValue for v in prop.ListValues] or None
elif prop.is_a("IfcPropertyBoundedValue"): elif prop.is_a("IfcPropertyBoundedValue"):
data = prop.get_info() data = prop.get_info()
del data["Unit"] del data["Unit"]
return data result = data
elif prop.is_a("IfcPropertyTableValue"): elif prop.is_a("IfcPropertyTableValue"):
return prop.get_info() result = prop.get_info()
elif prop.is_a("IfcComplexProperty"): elif prop.is_a("IfcComplexProperty"):
data = {k: v for k, v in prop.get_info().items() if v is not None and k != "Name"} data = {k: v for k, v in prop.get_info().items() if v is not None and k != "Name"}
data["properties"] = get_properties(prop.HasProperties) data["properties"] = get_properties(prop.HasProperties)
del data["HasProperties"] del data["HasProperties"]
return data result = data
if verbose:
result = {"id": prop.id(), "class": prop.is_a(), "value": result}
return result
def get_properties(properties): def get_properties(properties, verbose=False):
results = {} results = {}
for prop in properties or []: for prop in properties or []:
if prop.is_a("IfcPropertySingleValue"): if prop.is_a("IfcPropertySingleValue"):
results[prop.Name] = prop.NominalValue.wrappedValue if prop.NominalValue else None results[prop.Name] = prop.NominalValue.wrappedValue if prop.NominalValue else None
if verbose:
results[prop.Name] = {"id": prop.id(), "class": prop.is_a(), "value": results[prop.Name]}
elif prop.is_a("IfcPropertyEnumeratedValue"): elif prop.is_a("IfcPropertyEnumeratedValue"):
results[prop.Name] = [v.wrappedValue for v in prop.EnumerationValues] if prop.EnumerationValues else None results[prop.Name] = [v.wrappedValue for v in prop.EnumerationValues] if prop.EnumerationValues else None
if verbose:
results[prop.Name] = {"id": prop.id(), "class": prop.is_a(), "value": results[prop.Name]}
elif prop.is_a("IfcPropertyListValue"): elif prop.is_a("IfcPropertyListValue"):
results[prop.Name] = [v.wrappedValue for v in prop.ListValues] or None results[prop.Name] = [v.wrappedValue for v in prop.ListValues] or None
if verbose:
results[prop.Name] = {"id": prop.id(), "class": prop.is_a(), "value": results[prop.Name]}
elif prop.is_a("IfcPropertyBoundedValue"): elif prop.is_a("IfcPropertyBoundedValue"):
data = prop.get_info() data = prop.get_info()
del data["Unit"] del data["Unit"]
results[prop.Name] = data results[prop.Name] = data
if verbose:
results[prop.Name] = {"id": prop.id(), "class": prop.is_a(), "value": results[prop.Name]}
elif prop.is_a("IfcPropertyTableValue"): elif prop.is_a("IfcPropertyTableValue"):
results[prop.Name] = prop.get_info() results[prop.Name] = prop.get_info()
if verbose:
results[prop.Name] = {"id": prop.id(), "class": prop.is_a(), "value": results[prop.Name]}
elif prop.is_a("IfcComplexProperty"): elif prop.is_a("IfcComplexProperty"):
data = {k: v for k, v in prop.get_info().items() if v is not None and k != "Name"} data = {k: v for k, v in prop.get_info().items() if v is not None and k != "Name"}
data["properties"] = get_properties(prop.HasProperties) data["properties"] = get_properties(prop.HasProperties)
del data["HasProperties"] del data["HasProperties"]
results[prop.Name] = data results[prop.Name] = data
if verbose:
results[prop.Name] = {"id": prop.id(), "class": prop.is_a(), "value": results[prop.Name]}
return results return results
@@ -31,6 +31,11 @@ class TestGetPsetIFC4(test.bootstrap.IFC4):
ifcopenshell.api.run("pset.edit_pset", self.file, pset=pset, properties={"a": "b"}) ifcopenshell.api.run("pset.edit_pset", self.file, pset=pset, properties={"a": "b"})
assert subject.get_pset(element, "name") == {"a": "b", "id": pset.id()} assert subject.get_pset(element, "name") == {"a": "b", "id": pset.id()}
assert subject.get_pset(element, "name", "a") == "b" assert subject.get_pset(element, "name", "a") == "b"
assert subject.get_pset(element, "name", "a", verbose=True) == {
"id": 4,
"class": "IfcPropertySingleValue",
"value": "b",
}
def test_getting_the_psets_of_a_product_type_as_a_dictionary(self): def test_getting_the_psets_of_a_product_type_as_a_dictionary(self):
type_element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWallType") type_element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWallType")
@@ -38,6 +43,14 @@ class TestGetPsetIFC4(test.bootstrap.IFC4):
pset = ifcopenshell.api.run("pset.add_pset", self.file, product=type_element, name="name") pset = ifcopenshell.api.run("pset.add_pset", self.file, product=type_element, name="name")
ifcopenshell.api.run("pset.edit_pset", self.file, pset=pset, properties={"x": "y"}) ifcopenshell.api.run("pset.edit_pset", self.file, pset=pset, properties={"x": "y"})
assert subject.get_pset(type_element, "name") == {"x": "y", "id": pset.id()} assert subject.get_pset(type_element, "name") == {"x": "y", "id": pset.id()}
assert subject.get_pset(type_element, "name", verbose=True) == {
"x": {
"id": 3,
"class": "IfcPropertySingleValue",
"value": "y",
},
"id": pset.id(),
}
def test_getting_inherited_psets(self): def test_getting_inherited_psets(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")
@@ -401,34 +414,55 @@ class TestGetStyles(test.bootstrap.IFC4):
assert subject.get_styles(element) == [] assert subject.get_styles(element) == []
model = ifcopenshell.api.run("context.add_context", self.file, context_type="Model") model = ifcopenshell.api.run("context.add_context", self.file, context_type="Model")
body = ifcopenshell.api.run("context.add_context", self.file, body = ifcopenshell.api.run(
context_type="Model", context_identifier="Body", target_view="MODEL_VIEW", parent=model) "context.add_context",
self.file,
context_type="Model",
context_identifier="Body",
target_view="MODEL_VIEW",
parent=model,
)
material = ifcopenshell.api.run("material.add_material", self.file) material = ifcopenshell.api.run("material.add_material", self.file)
ifcopenshell.api.run("material.assign_material", self.file, product=element, material=material) ifcopenshell.api.run("material.assign_material", self.file, product=element, material=material)
style = ifcopenshell.api.run("style.add_style", self.file) style = ifcopenshell.api.run("style.add_style", self.file)
ifcopenshell.api.run("style.add_surface_style", self.file, ifcopenshell.api.run(
style=style, ifc_class="IfcSurfaceStyleShading", attributes={ "style.add_surface_style",
"SurfaceColour": { "Name": None, "Red": 1.0, "Green": 0.8, "Blue": 0.8 }, self.file,
"Transparency": 0., # 0 is opaque, 1 is transparent style=style,
}) ifc_class="IfcSurfaceStyleShading",
attributes={
"SurfaceColour": {"Name": None, "Red": 1.0, "Green": 0.8, "Blue": 0.8},
"Transparency": 0.0, # 0 is opaque, 1 is transparent
},
)
ifcopenshell.api.run("style.assign_material_style", self.file, material=material, style=style, context=body) ifcopenshell.api.run("style.assign_material_style", self.file, material=material, style=style, context=body)
assert subject.get_styles(element) == [style] assert subject.get_styles(element) == [style]
style2 = ifcopenshell.api.run("style.add_style", self.file) style2 = ifcopenshell.api.run("style.add_style", self.file)
ifcopenshell.api.run("style.add_surface_style", self.file, ifcopenshell.api.run(
style=style2, ifc_class="IfcSurfaceStyleShading", attributes={ "style.add_surface_style",
"SurfaceColour": { "Name": None, "Red": 1.0, "Green": 0.8, "Blue": 0.8 }, self.file,
"Transparency": 0., # 0 is opaque, 1 is transparent style=style2,
}) ifc_class="IfcSurfaceStyleShading",
attributes={
"SurfaceColour": {"Name": None, "Red": 1.0, "Green": 0.8, "Blue": 0.8},
"Transparency": 0.0, # 0 is opaque, 1 is transparent
},
)
representation = ifcopenshell.api.run("geometry.add_wall_representation", self.file, representation = ifcopenshell.api.run(
context=body, length=5, height=3, thickness=0.118) "geometry.add_wall_representation", self.file, context=body, length=5, height=3, thickness=0.118
)
ifcopenshell.api.run("geometry.assign_representation", self.file, product=element, representation=representation) ifcopenshell.api.run(
ifcopenshell.api.run("style.assign_representation_styles", self.file, shape_representation=representation, styles=[style2]) "geometry.assign_representation", self.file, product=element, representation=representation
)
ifcopenshell.api.run(
"style.assign_representation_styles", self.file, shape_representation=representation, styles=[style2]
)
assert subject.get_styles(element) == [style, style2] assert subject.get_styles(element) == [style, style2]