mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-10 01:41:57 +00:00
library.assign_reference - support batching #4474
This commit is contained in:
@@ -93,6 +93,9 @@ ARGUMENTS_DEPRECATION = {
|
||||
"classification.remove_reference": partial(
|
||||
batching_argument_deprecation, prev_argument="product", new_argument="products"
|
||||
),
|
||||
"library.assign_reference": partial(
|
||||
batching_argument_deprecation, prev_argument="product", new_argument="products"
|
||||
),
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -17,23 +17,30 @@
|
||||
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import ifcopenshell
|
||||
import ifcopenshell.api
|
||||
import ifcopenshell.util.element
|
||||
from typing import Union
|
||||
|
||||
|
||||
class Usecase:
|
||||
def __init__(self, file, product=None, reference=None):
|
||||
"""Associates a product with a library reference
|
||||
def __init__(
|
||||
self, file: ifcopenshell.file, products: ifcopenshell.entity_instance, reference: ifcopenshell.entity_instance
|
||||
):
|
||||
"""Associates a list products with a library reference
|
||||
|
||||
A product may be associated with zero, one, or many references across
|
||||
multiple libraries. See ifcopenshell.api.library.add_reference for more
|
||||
detail about how references work.
|
||||
|
||||
:param product: The IfcProduct you want to associate with the reference
|
||||
:type product: ifcopenshell.entity_instance.entity_instance
|
||||
:param products: The list of IfcProducts you want to associate with the reference
|
||||
:type products: list[ifcopenshell.entity_instance.entity_instance]
|
||||
:param reference: The IfcLibraryReference you want the product to be
|
||||
associated with.
|
||||
:type reference: ifcopenshell.entity_instance.entity_instance
|
||||
:return: The IfcRelAssociatesLibrary relationship entity
|
||||
:rtype: ifcopenshell.entity_instance.entity_instance
|
||||
or `None` if `products` was an empty list or all products were
|
||||
already assigned to the `reference`.
|
||||
:rtype: Union[ifcopenshell.entity_instance.entity_instance, None]
|
||||
|
||||
Example:
|
||||
|
||||
@@ -51,40 +58,46 @@ class Usecase:
|
||||
ifc_class="IfcUnitaryEquipment", predefined_type="AIRHANDLER")
|
||||
|
||||
# And now assign the IFC model's AHU with its Brickschema counterpart
|
||||
ifcopenshell.api.run("library.assign_reference", model, reference=reference, product=ahu)
|
||||
ifcopenshell.api.run("library.assign_reference", model, reference=reference, products=[ahu])
|
||||
"""
|
||||
self.file = file
|
||||
self.settings = {
|
||||
"product": product,
|
||||
"products": products,
|
||||
"reference": reference,
|
||||
}
|
||||
|
||||
def execute(self):
|
||||
def execute(self) -> Union[ifcopenshell.entity_instance, None]:
|
||||
# TODO: do we need to support non-ifcroot elements like we do in classification.add_reference?
|
||||
|
||||
referenced_elements = ifcopenshell.util.element.get_referenced_elements(self.settings["reference"])
|
||||
products: set[ifcopenshell.entity_instance] = set(self.settings["products"])
|
||||
products = products - referenced_elements
|
||||
|
||||
if not products:
|
||||
return
|
||||
|
||||
if self.file.schema == "IFC2X3":
|
||||
rels = self.get_ifc2x3_rels()
|
||||
rel = next(
|
||||
(
|
||||
r
|
||||
for r in self.file.by_type("IfcRelAssociatesLibrary")
|
||||
if r.RelatingLibrary == self.settings["reference"]
|
||||
),
|
||||
None,
|
||||
)
|
||||
else:
|
||||
rels = self.settings["reference"].LibraryRefForObjects
|
||||
if not rels:
|
||||
rel = next(iter(self.settings["reference"].LibraryRefForObjects), None)
|
||||
|
||||
if not rel:
|
||||
return self.file.create_entity(
|
||||
"IfcRelAssociatesLibrary",
|
||||
GlobalId=ifcopenshell.guid.new(),
|
||||
OwnerHistory=ifcopenshell.api.run("owner.create_owner_history", self.file),
|
||||
RelatedObjects=[self.settings["product"]],
|
||||
RelatedObjects=list(products),
|
||||
RelatingLibrary=self.settings["reference"],
|
||||
)
|
||||
|
||||
for rel in rels:
|
||||
if self.settings["product"] in rel.RelatedObjects:
|
||||
return rel
|
||||
|
||||
rel = rels[0]
|
||||
related_objects = list(rel.RelatedObjects)
|
||||
related_objects.append(self.settings["product"])
|
||||
rel.RelatedObjects = related_objects
|
||||
related_objects = set(rel.RelatedObjects) | products
|
||||
rel.RelatedObjects = list(related_objects)
|
||||
ifcopenshell.api.run("owner.update_owner_history", self.file, element=rel)
|
||||
return rel
|
||||
|
||||
def get_ifc2x3_rels(self):
|
||||
return [
|
||||
r for r in self.file.by_type("IfcRelAssociatesLibrary") if r.RelatingLibrary == self.settings["reference"]
|
||||
]
|
||||
|
||||
@@ -49,7 +49,7 @@ class Usecase:
|
||||
ifc_class="IfcUnitaryEquipment", predefined_type="AIRHANDLER")
|
||||
|
||||
# And now assign the IFC model's AHU with its Brickschema counterpart
|
||||
ifcopenshell.api.run("library.assign_reference", model, reference=reference, product=ahu)
|
||||
ifcopenshell.api.run("library.assign_reference", model, reference=reference, products=[ahu])
|
||||
|
||||
# Let's change our mind and unassign it.
|
||||
ifcopenshell.api.run("library.unassign_reference", model, reference=reference, product=ahu)
|
||||
|
||||
@@ -20,39 +20,48 @@ import test.bootstrap
|
||||
import ifcopenshell.api
|
||||
|
||||
|
||||
def validate_ifc_file(ifc_file: ifcopenshell.file, use_json=True):
|
||||
import ifcopenshell
|
||||
import ifcopenshell.validate
|
||||
|
||||
if use_json:
|
||||
logger = ifcopenshell.validate.json_logger()
|
||||
else:
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger("validate")
|
||||
logger.setLevel(logging.DEBUG)
|
||||
|
||||
ifcopenshell.validate.validate(ifc_file, logger, express_rules=True)
|
||||
if use_json:
|
||||
if logger.statements:
|
||||
from pprint import pprint
|
||||
|
||||
pprint(logger.statements)
|
||||
else:
|
||||
print("IFC is completely valid.")
|
||||
|
||||
|
||||
class TestAssignReference(test.bootstrap.IFC4):
|
||||
def test_assigning_a_reference(self):
|
||||
reference = self.file.createIfcLibraryReference()
|
||||
product = self.file.createIfcWall()
|
||||
product2 = self.file.createIfcWall()
|
||||
ifcopenshell.api.run("library.assign_reference", self.file, product=product, reference=reference)
|
||||
assert reference.LibraryRefForObjects[0].RelatedObjects == (product,)
|
||||
ifcopenshell.api.run("library.assign_reference", self.file, product=product2, reference=reference)
|
||||
assert reference.LibraryRefForObjects[0].RelatedObjects == (product, product2)
|
||||
product3 = self.file.createIfcWall()
|
||||
ifcopenshell.api.run("library.assign_reference", self.file, products=[product], reference=reference)
|
||||
rel = self.file.by_type("IfcRelAssociatesLibrary")[0]
|
||||
assert rel.RelatedObjects == (product,)
|
||||
ifcopenshell.api.run("library.assign_reference", self.file, products=[product2, product3], reference=reference)
|
||||
assert set(rel.RelatedObjects) == set((product, product2, product3))
|
||||
|
||||
def test_not_assigning_twice(self):
|
||||
reference = self.file.createIfcLibraryReference()
|
||||
product = self.file.createIfcWall()
|
||||
ifcopenshell.api.run("library.assign_reference", self.file, product=product, reference=reference)
|
||||
ifcopenshell.api.run("library.assign_reference", self.file, product=product, reference=reference)
|
||||
assert reference.LibraryRefForObjects[0].RelatedObjects == (product,)
|
||||
|
||||
|
||||
class TestAssignReferenceIFC2X3(test.bootstrap.IFC2X3):
|
||||
def test_assigning_a_reference(self):
|
||||
reference = self.file.createIfcLibraryReference()
|
||||
product = self.file.createIfcWall()
|
||||
product2 = self.file.createIfcWall()
|
||||
ifcopenshell.api.run("library.assign_reference", self.file, product=product, reference=reference)
|
||||
ifcopenshell.api.run("library.assign_reference", self.file, products=[product], reference=reference)
|
||||
ifcopenshell.api.run("library.assign_reference", self.file, products=[product], reference=reference)
|
||||
rel = self.file.by_type("IfcRelAssociatesLibrary")[0]
|
||||
assert rel.RelatedObjects == (product,)
|
||||
ifcopenshell.api.run("library.assign_reference", self.file, product=product2, reference=reference)
|
||||
assert rel.RelatedObjects == (product, product2)
|
||||
|
||||
def test_not_assigning_twice(self):
|
||||
reference = self.file.createIfcLibraryReference()
|
||||
product = self.file.createIfcWall()
|
||||
ifcopenshell.api.run("library.assign_reference", self.file, product=product, reference=reference)
|
||||
ifcopenshell.api.run("library.assign_reference", self.file, product=product, reference=reference)
|
||||
rel = self.file.by_type("IfcRelAssociatesLibrary")[0]
|
||||
assert rel.RelatedObjects == (product,)
|
||||
|
||||
class TestAssignReferenceIFC2X3(test.bootstrap.IFC2X3, TestAssignReference):
|
||||
pass
|
||||
|
||||
@@ -24,7 +24,7 @@ class TestRemoveReference(test.bootstrap.IFC4):
|
||||
def test_removing_a_reference(self):
|
||||
reference = self.file.createIfcLibraryReference()
|
||||
product = self.file.createIfcWall()
|
||||
ifcopenshell.api.run("library.assign_reference", self.file, product=product, reference=reference)
|
||||
ifcopenshell.api.run("library.assign_reference", self.file, products=[product], reference=reference)
|
||||
ifcopenshell.api.run("library.remove_reference", self.file, reference=reference)
|
||||
assert len(self.file.by_type("IfcLibraryReference")) == 0
|
||||
assert len(self.file.by_type("IfcRelAssociatesLibrary")) == 0
|
||||
|
||||
@@ -24,6 +24,6 @@ class TestUnassignReference(test.bootstrap.IFC4):
|
||||
def test_unassigning_a_reference(self):
|
||||
reference = self.file.createIfcLibraryReference()
|
||||
product = self.file.createIfcWall()
|
||||
ifcopenshell.api.run("library.assign_reference", self.file, product=product, reference=reference)
|
||||
ifcopenshell.api.run("library.assign_reference", self.file, products=[product], reference=reference)
|
||||
ifcopenshell.api.run("library.unassign_reference", self.file, product=product, reference=reference)
|
||||
assert len(self.file.by_type("IfcRelAssociatesLibrary")) == 0
|
||||
|
||||
@@ -236,3 +236,13 @@ class TestTemporarySupportForDeprecatedAPIArguments(test.bootstrap.IFC4):
|
||||
ifcopenshell.api.run("classification.remove_reference", self.file, product=element, reference=reference)
|
||||
assert len(ifcopenshell.util.classification.get_references(element)) == 0
|
||||
assert len(self.file.by_type("IfcClassificationReference")) == 0
|
||||
|
||||
@deprecation_check
|
||||
def test_assigning_a_reference(self):
|
||||
reference = self.file.createIfcLibraryReference()
|
||||
product = self.file.createIfcWall()
|
||||
product2 = self.file.createIfcWall()
|
||||
ifcopenshell.api.run("library.assign_reference", self.file, product=product, reference=reference)
|
||||
assert reference.LibraryRefForObjects[0].RelatedObjects == (product,)
|
||||
ifcopenshell.api.run("library.assign_reference", self.file, product=product2, reference=reference)
|
||||
assert set(reference.LibraryRefForObjects[0].RelatedObjects) == set((product, product2))
|
||||
|
||||
@@ -788,7 +788,6 @@ class TestGetNestIFC2X3(test.bootstrap.IFC2X3, TestGetNestIFC4):
|
||||
class TestGetReferencedElements(test.bootstrap.IFC4):
|
||||
# TODO: test other references:
|
||||
# IfcDocumentReference
|
||||
# IfcLibraryReference
|
||||
# IfcExternallyDefinedHatchStyle
|
||||
# IfcExternallyDefinedSurfaceStyle
|
||||
# IfcExternallyDefinedTextFont
|
||||
@@ -808,6 +807,15 @@ class TestGetReferencedElements(test.bootstrap.IFC4):
|
||||
)
|
||||
assert subject.get_referenced_elements(reference) == set(elements)
|
||||
|
||||
def test_get_elements_referenced_by_library_reference(self):
|
||||
reference = self.file.createIfcLibraryReference()
|
||||
elements = [
|
||||
ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall"),
|
||||
ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall"),
|
||||
]
|
||||
ifcopenshell.api.run("library.assign_reference", self.file, reference=reference, products=elements)
|
||||
assert subject.get_referenced_elements(reference) == set(elements)
|
||||
|
||||
|
||||
class TestGetReferencedElementsIFC2X3(test.bootstrap.IFC2X3, TestGetReferencedElements):
|
||||
pass
|
||||
|
||||
Reference in New Issue
Block a user