mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-21 23:31:00 +00:00
Fix ifcpatch unit conversion for lists of ifc entities #6280
This commit is contained in:
@@ -24,6 +24,7 @@ from typing import Iterable
|
|||||||
from typing import Literal
|
from typing import Literal
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
from typing import Union
|
from typing import Union
|
||||||
|
from typing import Generator
|
||||||
|
|
||||||
import ifcopenshell
|
import ifcopenshell
|
||||||
import ifcopenshell.ifcopenshell_wrapper as ifcopenshell_wrapper
|
import ifcopenshell.ifcopenshell_wrapper as ifcopenshell_wrapper
|
||||||
@@ -803,9 +804,18 @@ def is_attr_type(
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def iter_element_and_attributes_per_type(
|
FloatOrSequenceOfFloats = Union[float, tuple["FloatOrSequenceOfFloats", ...]]
|
||||||
ifc_file: ifcopenshell.file, attr_type_name: str
|
|
||||||
) -> Iterable[tuple[ifcopenshell.entity_instance, ifcopenshell_wrapper.attribute, Any]]:
|
|
||||||
|
def iter_element_and_attributes_per_type(ifc_file: ifcopenshell.file, attr_type_name: str) -> Generator[
|
||||||
|
tuple[
|
||||||
|
ifcopenshell.entity_instance,
|
||||||
|
ifcopenshell_wrapper.attribute,
|
||||||
|
Union[FloatOrSequenceOfFloats, ifcopenshell.entity_instance],
|
||||||
|
],
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
]:
|
||||||
schema: ifcopenshell_wrapper.schema_definition = ifcopenshell_wrapper.schema_by_name(ifc_file.schema_identifier)
|
schema: ifcopenshell_wrapper.schema_definition = ifcopenshell_wrapper.schema_by_name(ifc_file.schema_identifier)
|
||||||
|
|
||||||
for element in ifc_file:
|
for element in ifc_file:
|
||||||
@@ -826,6 +836,17 @@ def iter_element_and_attributes_per_type(
|
|||||||
|
|
||||||
if isinstance(val, ifcopenshell.entity_instance) and not val.is_a(attr_type_name):
|
if isinstance(val, ifcopenshell.entity_instance) and not val.is_a(attr_type_name):
|
||||||
continue
|
continue
|
||||||
|
elif isinstance(val, tuple):
|
||||||
|
if not val:
|
||||||
|
continue
|
||||||
|
val_ = val[0]
|
||||||
|
# If it's a tuple of entities, just yield the entities we need to edit.
|
||||||
|
if isinstance(val_, ifcopenshell.entity_instance):
|
||||||
|
for val_ in val:
|
||||||
|
if not val_.is_a(attr_type_name):
|
||||||
|
continue
|
||||||
|
yield element, attr, val_
|
||||||
|
continue
|
||||||
|
|
||||||
yield element, attr, val
|
yield element, attr, val
|
||||||
|
|
||||||
@@ -863,9 +884,10 @@ def convert_file_length_units(ifc_file: ifcopenshell.file, target_units: str = "
|
|||||||
|
|
||||||
# Traverse all elements and their nested attributes in the file and convert them
|
# Traverse all elements and their nested attributes in the file and convert them
|
||||||
for element, attr, val in iter_element_and_attributes_per_type(file_patched, "IfcLengthMeasure"):
|
for element, attr, val in iter_element_and_attributes_per_type(file_patched, "IfcLengthMeasure"):
|
||||||
|
# NOTE: There is no risk of editing same entities twice as they're all recreated
|
||||||
|
# after file is reloaded as `file_patched`.
|
||||||
if isinstance(val, ifcopenshell.entity_instance):
|
if isinstance(val, ifcopenshell.entity_instance):
|
||||||
new_value = convert_value(val.wrappedValue)
|
val.wrappedValue = convert_value(val.wrappedValue)
|
||||||
getattr(element, attr.name()).wrappedValue = new_value
|
|
||||||
else:
|
else:
|
||||||
new_value = convert_value(val)
|
new_value = convert_value(val)
|
||||||
setattr(element, attr.name(), new_value)
|
setattr(element, attr.name(), new_value)
|
||||||
|
|||||||
@@ -247,6 +247,32 @@ class TestConvertFileLengthUnits(test.bootstrap.IFC2X3):
|
|||||||
rectangle = builder.rectangle((100, 100))
|
rectangle = builder.rectangle((100, 100))
|
||||||
extrusion = builder.extrude(rectangle, 1000)
|
extrusion = builder.extrude(rectangle, 1000)
|
||||||
|
|
||||||
|
# IfcLengthMeasure entities.
|
||||||
|
product = ifcopenshell.api.root.create_entity(self.file, "IfcWall")
|
||||||
|
pset = ifcopenshell.api.pset.add_pset(self.file, product, "TestPset")
|
||||||
|
# Consider weird case when same entity is reused.
|
||||||
|
length_measure = self.file.create_entity("IfcLengthMeasure", 50.0)
|
||||||
|
enum_property = self.file.create_entity(
|
||||||
|
"IfcPropertyEnumeratedValue",
|
||||||
|
Name="Enum",
|
||||||
|
# Not entirely sure if there are real life cases when mixed typed entities used in the list
|
||||||
|
# but just to be safe.
|
||||||
|
EnumerationValues=[
|
||||||
|
length_measure,
|
||||||
|
self.file.create_entity("IfcLabel", "TEXT"),
|
||||||
|
self.file.create_entity("IfcLengthMeasure", 250.0),
|
||||||
|
length_measure,
|
||||||
|
],
|
||||||
|
)
|
||||||
|
ifcopenshell.api.pset.edit_pset(
|
||||||
|
self.file,
|
||||||
|
pset,
|
||||||
|
properties={
|
||||||
|
"Length": self.file.create_entity("IfcLengthMeasure", 25.0),
|
||||||
|
"Enum": enum_property,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
ifcopenshell.api.unit.assign_unit(self.file, units=[unit])
|
ifcopenshell.api.unit.assign_unit(self.file, units=[unit])
|
||||||
output = subject.convert_file_length_units(self.file, target_units="METER")
|
output = subject.convert_file_length_units(self.file, target_units="METER")
|
||||||
assert subject.get_full_unit_name(subject.get_project_unit(output, "LENGTHUNIT")) == "METRE"
|
assert subject.get_full_unit_name(subject.get_project_unit(output, "LENGTHUNIT")) == "METRE"
|
||||||
@@ -267,6 +293,12 @@ class TestConvertFileLengthUnits(test.bootstrap.IFC2X3):
|
|||||||
points = rectangle.Points.CoordList
|
points = rectangle.Points.CoordList
|
||||||
assert np.allclose(points, expected_points)
|
assert np.allclose(points, expected_points)
|
||||||
|
|
||||||
|
# IfcLengthMeasure entities.
|
||||||
|
product = output.by_type("IfcWall")[0]
|
||||||
|
pset_data = ifcopenshell.util.element.get_pset(product, "TestPset")
|
||||||
|
assert pset_data["Length"] == 0.025
|
||||||
|
assert pset_data["Enum"] == [0.05, "TEXT", 0.25, 0.05]
|
||||||
|
|
||||||
def test_converting_map_conversion_if_there_is_no_map_unit(self):
|
def test_converting_map_conversion_if_there_is_no_map_unit(self):
|
||||||
ifcopenshell.api.root.create_entity(self.file, ifc_class="IfcProject")
|
ifcopenshell.api.root.create_entity(self.file, ifc_class="IfcProject")
|
||||||
unit = ifcopenshell.api.unit.add_si_unit(self.file, unit_type="LENGTHUNIT", prefix="MILLI")
|
unit = ifcopenshell.api.unit.add_si_unit(self.file, unit_type="LENGTHUNIT", prefix="MILLI")
|
||||||
|
|||||||
Reference in New Issue
Block a user