mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-12 10:33:20 +00:00
Merge remote-tracking branch 'origin/v0.8.0' into datamodel-v1.0
This commit is contained in:
@@ -17,20 +17,20 @@
|
||||
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from collections import deque
|
||||
from collections.abc import Callable
|
||||
from functools import partial
|
||||
from typing import Any, Literal, Optional, Union, get_args
|
||||
import ifcopenshell
|
||||
import ifcopenshell.ifcopenshell_wrapper as W
|
||||
import ifcopenshell.api.geometry
|
||||
import ifcopenshell.api.type
|
||||
import ifcopenshell.api.project
|
||||
import ifcopenshell.api.context
|
||||
import ifcopenshell.api.geometry
|
||||
import ifcopenshell.api.owner.settings
|
||||
import ifcopenshell.api.project
|
||||
import ifcopenshell.api.type
|
||||
import ifcopenshell.ifcopenshell_wrapper as W
|
||||
import ifcopenshell.util.element
|
||||
import ifcopenshell.util.geolocation
|
||||
import ifcopenshell.util.placement
|
||||
import ifcopenshell.util.unit
|
||||
from typing import Optional, Any, Union, Literal, get_args, Callable
|
||||
from functools import partial
|
||||
|
||||
|
||||
APPENDABLE_ASSET = Literal[
|
||||
"IfcTypeProduct",
|
||||
@@ -40,7 +40,7 @@ APPENDABLE_ASSET = Literal[
|
||||
"IfcProfileDef",
|
||||
"IfcPresentationStyle",
|
||||
]
|
||||
APPENDABLE_ASSET_TYPES = get_args(APPENDABLE_ASSET)
|
||||
APPENDABLE_ASSET_TYPES: tuple[APPENDABLE_ASSET, ...] = get_args(APPENDABLE_ASSET)
|
||||
MATERIAL_SETS = ("IfcMaterialLayerSet", "IfcMaterialConstituentSet", "IfcMaterialProfileSet")
|
||||
|
||||
|
||||
@@ -243,6 +243,59 @@ class Usecase:
|
||||
except RuntimeError:
|
||||
return None
|
||||
|
||||
def material_sets_are_equal(self, set1: ifcopenshell.entity_instance, set2: ifcopenshell.entity_instance) -> bool:
|
||||
"""Check if two material sets are structurally equivalent."""
|
||||
if set1.is_a() != set2.is_a():
|
||||
return False
|
||||
|
||||
ifc_class = set1.is_a()
|
||||
|
||||
if ifc_class == "IfcMaterialLayerSet":
|
||||
layers1 = set1.MaterialLayers or []
|
||||
layers2 = set2.MaterialLayers or []
|
||||
if len(layers1) != len(layers2):
|
||||
return False
|
||||
for l1, l2 in zip(layers1, layers2):
|
||||
if (l1.Material is None) != (l2.Material is None):
|
||||
return False
|
||||
if l1.Material and l1.Material.Name != l2.Material.Name:
|
||||
return False
|
||||
if l1.LayerThickness != l2.LayerThickness:
|
||||
return False
|
||||
|
||||
elif ifc_class == "IfcMaterialConstituentSet":
|
||||
constituents1 = set1.MaterialConstituents or []
|
||||
constituents2 = set2.MaterialConstituents or []
|
||||
if len(constituents1) != len(constituents2):
|
||||
return False
|
||||
for c1, c2 in zip(constituents1, constituents2):
|
||||
if (c1.Material is None) != (c2.Material is None):
|
||||
return False
|
||||
if c1.Material and c1.Material.Name != c2.Material.Name:
|
||||
return False
|
||||
if c1.Name != c2.Name:
|
||||
return False
|
||||
|
||||
elif ifc_class == "IfcMaterialProfileSet":
|
||||
profiles1 = set1.MaterialProfiles or []
|
||||
profiles2 = set2.MaterialProfiles or []
|
||||
if len(profiles1) != len(profiles2):
|
||||
return False
|
||||
for p1, p2 in zip(profiles1, profiles2):
|
||||
if (p1.Material is None) != (p2.Material is None):
|
||||
return False
|
||||
if p1.Material and p1.Material.Name != p2.Material.Name:
|
||||
return False
|
||||
if (p1.Profile is None) != (p2.Profile is None):
|
||||
return False
|
||||
if p1.Profile:
|
||||
profile_name1 = getattr(p1.Profile, "ProfileName", None)
|
||||
profile_name2 = getattr(p2.Profile, "ProfileName", None)
|
||||
if profile_name1 != profile_name2:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def get_existing_element(self, element: ifcopenshell.entity_instance) -> Union[ifcopenshell.entity_instance, None]:
|
||||
"""Get existing element for a library element.
|
||||
|
||||
@@ -264,13 +317,17 @@ class Usecase:
|
||||
name = element.Name
|
||||
return next((e for e in self.file.by_type("IfcMaterial") if e.Name == name), None)
|
||||
|
||||
elif element in MATERIAL_SETS:
|
||||
elif element.is_a() in MATERIAL_SETS:
|
||||
ifc_class = element.is_a()
|
||||
name_attr = "LayerSetName" if ifc_class == "IfcMaterialLayerSet" else "Name"
|
||||
material_set_name = getattr(element, name_attr)
|
||||
if material_set_name is None:
|
||||
return
|
||||
return next((e for e in self.file.by_type(ifc_class) if getattr(e, name_attr) == material_set_name), None)
|
||||
for candidate in self.file.by_type(ifc_class):
|
||||
if getattr(candidate, name_attr) == material_set_name:
|
||||
if self.material_sets_are_equal(element, candidate):
|
||||
return candidate
|
||||
return None
|
||||
|
||||
elif element.is_a("IfcProfileDef"):
|
||||
profile_name = element.ProfileName
|
||||
@@ -324,6 +381,7 @@ class Usecase:
|
||||
def append_type_product(self):
|
||||
self.whitelisted_inverse_attributes = {
|
||||
"IfcObjectDefinition": ["HasAssociations"],
|
||||
"IfcDistributionElementType": ["IsNestedBy"],
|
||||
self.base_material_class: ["HasExternalReferences", "HasProperties", "HasRepresentation"],
|
||||
"IfcRepresentationItem": ["StyledByItem", "LayerAssignment"],
|
||||
"IfcRepresentation": ["LayerAssignments"],
|
||||
@@ -340,6 +398,7 @@ class Usecase:
|
||||
"IfcObjectDefinition": ["HasAssociations"],
|
||||
"IfcObject": ["IsDefinedBy.IfcRelDefinesByProperties"],
|
||||
"IfcElement": ["HasOpenings"],
|
||||
"IfcDistributionElement": ["IsNestedBy"],
|
||||
self.base_material_class: ["HasExternalReferences", "HasProperties", "HasRepresentation"],
|
||||
"IfcRepresentationItem": [
|
||||
"StyledByItem",
|
||||
@@ -372,7 +431,7 @@ class Usecase:
|
||||
)
|
||||
ifcopenshell.api.type.assign_type(
|
||||
self.file,
|
||||
should_run_listeners=False,
|
||||
should_run_listeners=False, # ty:ignore[unknown-argument]
|
||||
related_objects=[element],
|
||||
relating_type=new_type,
|
||||
should_map_representations=False,
|
||||
@@ -512,6 +571,8 @@ class Usecase:
|
||||
return False
|
||||
elif element.is_a("IfcRoot") and self.by_guid(element.GlobalId) is not None:
|
||||
return False
|
||||
elif element.is_a("IfcDistributionPort"):
|
||||
return False
|
||||
elif element.is_a(self.target_class):
|
||||
return True
|
||||
elif self.target_class == "IfcProduct" and element.is_a("IfcTypeProduct"):
|
||||
@@ -665,12 +726,11 @@ class Usecase:
|
||||
name_attr = "LayerSetName" if ifc_class == "IfcMaterialLayerSet" else "Name"
|
||||
material_set_name = getattr(element, name_attr)
|
||||
if material_set_name is not None:
|
||||
existing_material_set = next(
|
||||
(e for e in ifc_file.by_type(ifc_class) if getattr(e, name_attr) == material_set_name), None
|
||||
)
|
||||
if existing_material_set is not None:
|
||||
reuse_identities[element_identity] = existing_material_set
|
||||
return existing_material_set
|
||||
for candidate in ifc_file.by_type(ifc_class):
|
||||
if getattr(candidate, name_attr) == material_set_name:
|
||||
if self.material_sets_are_equal(element, candidate):
|
||||
reuse_identities[element_identity] = candidate
|
||||
return candidate
|
||||
|
||||
elif element.is_a("IfcPresentationStyle"):
|
||||
style_name = element.Name
|
||||
|
||||
@@ -16,11 +16,12 @@
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from typing import Union
|
||||
|
||||
import ifcopenshell
|
||||
import ifcopenshell.api.owner
|
||||
import ifcopenshell.guid
|
||||
import ifcopenshell.util.element
|
||||
from typing import Union
|
||||
|
||||
|
||||
def assign_declaration(
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import datetime
|
||||
|
||||
import ifcopenshell
|
||||
import ifcopenshell.util.schema
|
||||
|
||||
@@ -52,9 +53,7 @@ def create_file(version: ifcopenshell.util.schema.IFC_SCHEMA = "IFC4") -> ifcope
|
||||
"""
|
||||
file = ifcopenshell.file(schema=version)
|
||||
file.header.file_name.name = "/dev/null" # Hehehe
|
||||
file.header.file_name.time_stamp = (
|
||||
datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).astimezone().replace(microsecond=0).isoformat()
|
||||
)
|
||||
file.header.file_name.time_stamp = datetime.datetime.now().astimezone().replace(microsecond=0).isoformat()
|
||||
file.header.file_name.preprocessor_version = "IfcOpenShell {}".format(ifcopenshell.version)
|
||||
file.header.file_name.originating_system = "IfcOpenShell {}".format(ifcopenshell.version)
|
||||
file.header.file_name.authorization = "Nobody"
|
||||
|
||||
Reference in New Issue
Block a user