This commit is contained in:
Andrej730
2025-02-18 15:18:23 +05:00
parent 83a351b1c7
commit 17642ca4e9
117 changed files with 683 additions and 1005 deletions
@@ -20,7 +20,7 @@ import ifcopenshell
import ifcopenshell.guid
import ifcopenshell.util.schema
import ifcopenshell.util.date
from typing import Union
from typing import Union, Any
def add_classification(
@@ -61,9 +61,7 @@ def add_classification(
classification library. The latter approach is preferred if you are
using a commonly known system such as Uniclass, as this will ensure
all metadata is added correctly.
:type classification: str,ifcopenshell.entity_instance
:return: The added IfcClassification element
:rtype: ifcopenshell.entity_instance
Example:
@@ -81,28 +79,28 @@ def add_classification(
"""
usecase = Usecase()
usecase.file = file
usecase.settings = {
"classification": classification,
}
return usecase.execute()
return usecase.execute(classification)
class Usecase:
def execute(self):
if isinstance(self.settings["classification"], str):
classification = self.file.createIfcClassification(Name=self.settings["classification"])
file: ifcopenshell.file
def execute(self, classification: Union[str, ifcopenshell.entity_instance]) -> ifcopenshell.entity_instance:
self.classification = classification
if isinstance(self.classification, str):
classification = self.file.create_entity("IfcClassification", Name=self.classification)
self.relate_to_project(classification)
return classification
return self.add_from_library()
def add_from_library(self):
def add_from_library(self) -> ifcopenshell.entity_instance:
edition_date = None
if self.settings["classification"].EditionDate:
edition_date = ifcopenshell.util.date.ifc2datetime(self.settings["classification"].EditionDate)
self.settings["classification"].EditionDate = None
if self.classification.EditionDate:
edition_date = ifcopenshell.util.date.ifc2datetime(self.classification.EditionDate)
self.classification.EditionDate = None
migrator = ifcopenshell.util.schema.Migrator()
result = migrator.migrate(self.settings["classification"], self.file)
result = migrator.migrate(self.classification, self.file)
# TODO: should auto date migration be part of the migrator?
if self.file.schema == "IFC2X3" and edition_date:
@@ -118,7 +116,7 @@ class Usecase:
return result
def relate_to_project(self, classification):
def relate_to_project(self, classification: ifcopenshell.entity_instance) -> None:
self.file.create_entity(
"IfcRelAssociatesClassification",
GlobalId=ifcopenshell.guid.new(),
@@ -21,7 +21,7 @@ import ifcopenshell.api.owner
import ifcopenshell.guid
import ifcopenshell.util.element
import ifcopenshell.util.schema
from typing import Optional, Union
from typing import Optional, Union, Any
def add_reference(
@@ -65,23 +65,18 @@ def add_reference(
:param product: The list of IFC objects, properties, or resources you want to
associate the classification reference to.
:type product: list[ifcopenshell.entity_instance]
:param reference: The classification reference entity taken from an
IFC classification library. If you supply this parameter, you will
use option 2.
:type reference: ifcopenshell.entity_instance, optional
:param identification: If you choose option 1 and do not specify a
reference, you may manually specify an identification code. The code
is typically a short identifier and may have punctuation to separate
the levels of hierarchy in the classificaion (e.g. Pr_12_23_34).
:type identification: str, optional
:param name: If you choose option 1 and do not specify a reference, you
may manually specify a name. The name is typically human readable.
:type name: str, optional
:param classification: The IfcClassification entity in your IFC model
(not the library, if you are doing option 2) that the reference is
part of.
:type classification: ifcopenshell.entity_instance
:param is_lightweight: If you are doing option 2, choose whether or not
to only add that particular reference (lighweight) or also add all
of its parent references in the classification hierarchy (not
@@ -91,13 +86,11 @@ def add_reference(
references merely help describe the "tree" of classifications, but
is generally unnecessary. Using lightweight classifications are
recommended and is the default.
:type is_lightweight: bool, optional
:raises TypeError: If file is IFC2X3 and `products` has non-IfcRoot elements.
:return: The newly added IfcClassificationReference
or `None` if `products` was empty list.
:rtype: Union[ifcopenshell.entity_instance, None]
Example:
@@ -136,6 +129,9 @@ def add_reference(
class Usecase:
file: ifcopenshell.file
settings: dict[str, Any]
def execute(self):
if not self.settings["products"]:
return
@@ -28,11 +28,8 @@ def edit_classification(
IfcClassification, consult the IFC documentation.
:param classification: The IfcClassification entity you want to edit
:type classification: ifcopenshell.entity_instance
:param attributes: a dictionary of attribute names and values.
:type attributes: dict
:return: None
:rtype: None
Example:
@@ -43,7 +40,5 @@ def edit_classification(
ifcopenshell.api.classification.edit_classification(model,
classification=classification, attributes={"Name": "Foo"})
"""
settings = {"classification": classification, "attributes": attributes or {}}
for name, value in settings["attributes"].items():
setattr(settings["classification"], name, value)
for name, value in attributes.items():
setattr(classification, name, value)
@@ -28,11 +28,8 @@ def edit_reference(
IfcClassificationReference, consult the IFC documentation.
:param reference: The IfcClassificationReference entity you want to edit
:type reference: ifcopenshell.entity_instance
:param attributes: a dictionary of attribute names and values.
:type attributes: dict
:return: None
:rtype: None
Example:
@@ -43,7 +40,5 @@ def edit_reference(
ifcopenshell.api.classification.edit_reference(model,
reference=reference, attributes={"Name": "Foo"})
"""
settings = {"reference": reference, "attributes": attributes or {}}
for name, value in settings["attributes"].items():
setattr(settings["reference"], name, value)
for name, value in attributes.items():
setattr(reference, name, value)
@@ -28,9 +28,7 @@ def remove_classification(file: ifcopenshell.file, classification: ifcopenshell.
removed from a project.
:param classification: The IfcClassification entity you want to remove
:type classification: ifcopenshell.entity_instance
:return: None
:rtype: None
Example:
@@ -42,16 +40,17 @@ def remove_classification(file: ifcopenshell.file, classification: ifcopenshell.
"""
usecase = Usecase()
usecase.file = file
usecase.settings = {"classification": classification}
return usecase.execute()
return usecase.execute(classification)
class Usecase:
def execute(self):
references = self.get_references(self.settings["classification"])
file: ifcopenshell.file
def execute(self, classification: ifcopenshell.entity_instance) -> None:
references = self.get_references(classification)
for reference in references:
self.file.remove(reference)
self.file.remove(self.settings["classification"])
self.file.remove(classification)
for rel in self.file.by_type("IfcRelAssociatesClassification"):
if not rel.RelatingClassification:
history = rel.OwnerHistory
@@ -33,15 +33,12 @@ def remove_reference(
:param reference: The IfcClassificationReference entity of the
relationship you want to remove.
:type reference: ifcopenshell.entity_instance
:param product: The list fo object entities of the relationship you want to
remove.
:type product: list[ifcopenshell.entity_instance]
:raises TypeError: If file is IFC2X3 and `products` has non-IfcRoot elements.
:return: None
:rtype: None
Example:
@@ -56,20 +53,18 @@ def remove_reference(
ifcopenshell.api.classification.remove_reference(model,
reference=reference, products=[wall_type])
"""
settings = {"reference": reference, "products": products}
is_ifc2x3 = file.schema == "IFC2X3"
products = set(settings["products"])
referenced = ifcopenshell.util.element.get_referenced_elements(settings["reference"])
products -= products.difference(referenced)
products_set = set(products)
referenced = ifcopenshell.util.element.get_referenced_elements(reference)
products_set -= products_set.difference(referenced)
# all products are already unassigned from a reference
if not products:
if not products_set:
return
rooted_products: set[ifcopenshell.entity_instance] = set()
non_rooted_products: set[ifcopenshell.entity_instance] = set()
for product in settings["products"]:
for product in products:
if product.is_a("IfcRoot"):
rooted_products.add(product)
else:
@@ -86,7 +81,7 @@ def remove_reference(
reference_rels = {
rel
for rel in reference_rels
if rel.is_a("IfcRelAssociatesClassification") and rel.RelatingClassification == settings["reference"]
if rel.is_a("IfcRelAssociatesClassification") and rel.RelatingClassification == reference
}
for rel in reference_rels:
@@ -108,7 +103,7 @@ def remove_reference(
rels = getattr(product, "HasExternalReference", [])
reference_rels.update(rels)
reference_rels = {rel for rel in reference_rels if rel.RelatingReference == settings["reference"]}
reference_rels = {rel for rel in reference_rels if rel.RelatingReference == reference}
for rel in reference_rels:
related_objects = set(rel.RelatedResourceObjects) - non_rooted_products
if related_objects:
@@ -117,6 +112,6 @@ def remove_reference(
file.remove(rel)
# TODO: we only handle lightweight classifications here
referenced_elements = ifcopenshell.util.element.get_referenced_elements(settings["reference"])
referenced_elements = ifcopenshell.util.element.get_referenced_elements(reference)
if not referenced_elements:
file.remove(settings["reference"])
file.remove(reference)