mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-30 03:59:55 +00:00
black .
This commit is contained in:
@@ -23,28 +23,29 @@ from logging import Logger
|
|||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
from typing import List, Dict, Tuple, Optional
|
from typing import List, Dict, Tuple, Optional
|
||||||
|
|
||||||
|
|
||||||
class Patcher:
|
class Patcher:
|
||||||
"""
|
"""
|
||||||
Assigns fractions to material constituents based on their "width".
|
Assigns fractions to material constituents based on their "width".
|
||||||
|
|
||||||
In Reference View MVD, material layer information is exchanged through
|
In Reference View MVD, material layer information is exchanged through
|
||||||
IfcMaterialConstituentSet and IfcPhysicalComplexQuantity instead of IfcMaterialLayerSet.
|
IfcMaterialConstituentSet and IfcPhysicalComplexQuantity instead of IfcMaterialLayerSet.
|
||||||
The layer thicknesses are stored as IfcQuantityLength within IfcPhysicalComplexQuantity
|
The layer thicknesses are stored as IfcQuantityLength within IfcPhysicalComplexQuantity
|
||||||
with a Discrimination of 'layer'.
|
with a Discrimination of 'layer'.
|
||||||
|
|
||||||
While the Fraction attribute in IfcMaterialConstituent is optional, it's valuable for
|
While the Fraction attribute in IfcMaterialConstituent is optional, it's valuable for
|
||||||
downstream applications as it indicates the relative proportion of each constituent in
|
downstream applications as it indicates the relative proportion of each constituent in
|
||||||
the total material composition in a more straightforward way.
|
the total material composition in a more straightforward way.
|
||||||
However, authoring applications often export material constituents without setting this attribute.
|
However, authoring applications often export material constituents without setting this attribute.
|
||||||
|
|
||||||
This patcher helps maintain proper material information in Reference View exports by:
|
This patcher helps maintain proper material information in Reference View exports by:
|
||||||
1. Finding width quantities from IfcPhysicalComplexQuantity with 'layer' discrimination
|
1. Finding width quantities from IfcPhysicalComplexQuantity with 'layer' discrimination
|
||||||
2. Using these widths to calculate relative proportions
|
2. Using these widths to calculate relative proportions
|
||||||
3. Setting the optional but valuable Fraction attribute
|
3. Setting the optional but valuable Fraction attribute
|
||||||
|
|
||||||
For example, if a wall has constituents with widths of 0.1m and 0.2m, their fractions
|
For example, if a wall has constituents with widths of 0.1m and 0.2m, their fractions
|
||||||
would be set to 0.333 and 0.667 respectively.
|
would be set to 0.333 and 0.667 respectively.
|
||||||
|
|
||||||
References:
|
References:
|
||||||
- IFC4 Reference View MVD: https://standards.buildingsmart.org/MVD/RELEASE/IFC4/ADD2_TC1/RV1_2/HTML/
|
- IFC4 Reference View MVD: https://standards.buildingsmart.org/MVD/RELEASE/IFC4/ADD2_TC1/RV1_2/HTML/
|
||||||
- IfcMaterialConstituent: https://standards.buildingsmart.org/IFC/RELEASE/IFC4/ADD2_TC1/HTML/schema/ifcmaterialresource/lexical/ifcmaterialconstituent.htm
|
- IfcMaterialConstituent: https://standards.buildingsmart.org/IFC/RELEASE/IFC4/ADD2_TC1/HTML/schema/ifcmaterialresource/lexical/ifcmaterialconstituent.htm
|
||||||
@@ -57,11 +58,11 @@ class Patcher:
|
|||||||
def patch(self):
|
def patch(self):
|
||||||
"""Execute the patch to assign fractions to material constituents."""
|
"""Execute the patch to assign fractions to material constituents."""
|
||||||
unit_scale = ifcopenshell.util.unit.calculate_unit_scale(self.file)
|
unit_scale = ifcopenshell.util.unit.calculate_unit_scale(self.file)
|
||||||
|
|
||||||
# Get length unit from project
|
# Get length unit from project
|
||||||
length_unit = ifcopenshell.util.unit.get_project_unit(self.file, "LENGTHUNIT")
|
length_unit = ifcopenshell.util.unit.get_project_unit(self.file, "LENGTHUNIT")
|
||||||
|
|
||||||
for constituent_set in self.file.by_type('IfcMaterialConstituentSet'):
|
for constituent_set in self.file.by_type("IfcMaterialConstituentSet"):
|
||||||
if not (constituents := constituent_set.MaterialConstituents):
|
if not (constituents := constituent_set.MaterialConstituents):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
@@ -81,9 +82,7 @@ class Patcher:
|
|||||||
continue
|
continue
|
||||||
|
|
||||||
# Calculate constituent widths and total width
|
# Calculate constituent widths and total width
|
||||||
constituent_widths, total_width = self.calculate_constituent_widths(
|
constituent_widths, total_width = self.calculate_constituent_widths(constituents, elements, unit_scale)
|
||||||
constituents, elements, unit_scale
|
|
||||||
)
|
|
||||||
|
|
||||||
if not constituent_widths:
|
if not constituent_widths:
|
||||||
continue
|
continue
|
||||||
@@ -100,25 +99,31 @@ class Patcher:
|
|||||||
|
|
||||||
def get_element_quantities(self, element: ifcopenshell.entity_instance) -> Dict[str, float]:
|
def get_element_quantities(self, element: ifcopenshell.entity_instance) -> Dict[str, float]:
|
||||||
"""Get width quantities for an element."""
|
"""Get width quantities for an element."""
|
||||||
qtos = [v for k,v in ifcopenshell.util.element.get_psets(element, qtos_only=True).items()
|
qtos = [
|
||||||
if k.endswith("BaseQuantities")]
|
v
|
||||||
|
for k, v in ifcopenshell.util.element.get_psets(element, qtos_only=True).items()
|
||||||
|
if k.endswith("BaseQuantities")
|
||||||
|
]
|
||||||
if qtos:
|
if qtos:
|
||||||
return {k:v["properties"]["Width"] for k,v in qtos[0].items()
|
return {
|
||||||
if isinstance(v,dict) and
|
k: v["properties"]["Width"]
|
||||||
(v.get("Discrimination") or "").lower() == "layer" and
|
for k, v in qtos[0].items()
|
||||||
v.get("properties",{}).get("Width", "") is not None}
|
if isinstance(v, dict)
|
||||||
|
and (v.get("Discrimination") or "").lower() == "layer"
|
||||||
|
and v.get("properties", {}).get("Width", "") is not None
|
||||||
|
}
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
def calculate_constituent_widths(
|
def calculate_constituent_widths(
|
||||||
self,
|
self,
|
||||||
constituents: List[ifcopenshell.entity_instance],
|
constituents: List[ifcopenshell.entity_instance],
|
||||||
elements: set[ifcopenshell.entity_instance],
|
elements: set[ifcopenshell.entity_instance],
|
||||||
unit_scale: float
|
unit_scale: float,
|
||||||
) -> Tuple[Dict[ifcopenshell.entity_instance, float], float]:
|
) -> Tuple[Dict[ifcopenshell.entity_instance, float], float]:
|
||||||
"""Calculate the widths of constituents based on associated quantities."""
|
"""Calculate the widths of constituents based on associated quantities."""
|
||||||
if not elements:
|
if not elements:
|
||||||
return {}, 0.0
|
return {}, 0.0
|
||||||
|
|
||||||
# Get quantities from all elements and use the first valid one
|
# Get quantities from all elements and use the first valid one
|
||||||
element_quantities = {}
|
element_quantities = {}
|
||||||
for element in elements:
|
for element in elements:
|
||||||
@@ -127,18 +132,18 @@ class Patcher:
|
|||||||
element_quantities = quantities
|
element_quantities = quantities
|
||||||
self.logger.debug(f"Using quantities from element: {element.GlobalId}")
|
self.logger.debug(f"Using quantities from element: {element.GlobalId}")
|
||||||
break
|
break
|
||||||
|
|
||||||
if not element_quantities:
|
if not element_quantities:
|
||||||
self.logger.warning("No valid quantities found in any element")
|
self.logger.warning("No valid quantities found in any element")
|
||||||
return {}, 0.0
|
return {}, 0.0
|
||||||
|
|
||||||
constituent_widths = {}
|
constituent_widths = {}
|
||||||
total_width = 0.0
|
total_width = 0.0
|
||||||
|
|
||||||
for constituent in constituents:
|
for constituent in constituents:
|
||||||
if not constituent.Name: # Skip unnamed constituents as per RV MVD
|
if not constituent.Name: # Skip unnamed constituents as per RV MVD
|
||||||
continue
|
continue
|
||||||
|
|
||||||
constituent_name = constituent.Name.strip()
|
constituent_name = constituent.Name.strip()
|
||||||
if width := element_quantities.get(constituent_name):
|
if width := element_quantities.get(constituent_name):
|
||||||
constituent_widths[constituent] = width * unit_scale
|
constituent_widths[constituent] = width * unit_scale
|
||||||
|
|||||||
Reference in New Issue
Block a user