mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-10 17:58:20 +00:00
Merge remote-tracking branch 'origin/v0.7.0' into v08attempt1
This commit is contained in:
@@ -153,7 +153,7 @@ interface to access the IfcOpenShell utilities.
|
||||
|
||||
1. Install the BlenderBIM Add-on by following the `BlenderBIM Add-on
|
||||
installation documentation
|
||||
<https://blenderbim.org/docs/users/installation.html>`_.
|
||||
<https://docs.blenderbim.org/users/installation.html>`_.
|
||||
|
||||
2. Launch Blender. Change to the **Scene Properties** tab in the **Properties
|
||||
Panel**. Scroll down to the **IFC Collaboration > IFC CSV Import / Export**
|
||||
|
||||
@@ -88,7 +88,7 @@ interface to access the IfcOpenShell utilities.
|
||||
|
||||
1. Install the BlenderBIM Add-on by following the `BlenderBIM Add-on
|
||||
installation documentation
|
||||
<https://blenderbim.org/docs/users/installation.html>`_.
|
||||
<https://docs.blenderbim.org/users/installation.html>`_.
|
||||
|
||||
2. Launch Blender. Change to the **Scene Properties** tab in the **Properties
|
||||
Panel**. Scroll down to the **IFC Quality Control > IFC Diff** panel.
|
||||
|
||||
@@ -227,7 +227,7 @@ The BlenderBIM Add-on is available either as a stable build or a daily build.
|
||||
|
||||
1. Install the BlenderBIM Add-on by following the `BlenderBIM Add-on
|
||||
installation documentation
|
||||
<https://blenderbim.org/docs/users/installation.html>`_.
|
||||
<https://docs.blenderbim.org/users/installation.html>`_.
|
||||
|
||||
2. Launch Blender. On the top left of the Viewport panel, click the **Editor
|
||||
Type** icon to change the viewport into a **Python Console**.
|
||||
@@ -261,7 +261,7 @@ and run your script using the **Text > Run Script** menu or by clicking on the
|
||||
Blender. This can help when learning how to write scripts as you can double
|
||||
check the results of your scripts with what you see in the graphical
|
||||
interface. `Read more
|
||||
<https://blenderbim.org/docs/users/exploring_an_ifc_model.html>`_.
|
||||
<https://docs.blenderbim.org/users/exploring_an_ifc_model.html>`_.
|
||||
|
||||
From source with precompiled binaries
|
||||
-------------------------------------
|
||||
|
||||
@@ -12,7 +12,7 @@ Packaged installation
|
||||
|
||||
IfcSverchok is packaged like a regular Blender add-on, so installation is the
|
||||
same as any other Blender add-on. `Download IfcSverchok here
|
||||
<https://blenderbim.org/builds/ifcsverchok-230823.zip>`__.
|
||||
<https://github.com/IfcOpenShell/IfcOpenShell/releases/download/ifcsverchok-240417/ifcsverchok-240417.zip>`__.
|
||||
|
||||
Like all Blender add-ons, they can be installed using ``Edit > Preferences >
|
||||
Addons > Install > Choose Downloaded ZIP > Enable Add-on Checkbox``. You can
|
||||
|
||||
@@ -87,6 +87,36 @@ ARGUMENTS_DEPRECATION = {
|
||||
"material.unassign_material": partial(
|
||||
batching_argument_deprecation, prev_argument="product", new_argument="products"
|
||||
),
|
||||
"classification.add_reference": partial(
|
||||
batching_argument_deprecation, prev_argument="product", new_argument="products"
|
||||
),
|
||||
"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"
|
||||
),
|
||||
"library.unassign_reference": partial(
|
||||
batching_argument_deprecation, prev_argument="product", new_argument="products"
|
||||
),
|
||||
"document.assign_document": partial(
|
||||
batching_argument_deprecation, prev_argument="product", new_argument="products"
|
||||
),
|
||||
"document.unassign_document": partial(
|
||||
batching_argument_deprecation, prev_argument="product", new_argument="products"
|
||||
),
|
||||
"spatial.reference_structure": partial(
|
||||
batching_argument_deprecation, prev_argument="product", new_argument="products"
|
||||
),
|
||||
"spatial.dereference_structure": partial(
|
||||
batching_argument_deprecation, prev_argument="product", new_argument="products"
|
||||
),
|
||||
"constraint.assign_constraint": partial(
|
||||
batching_argument_deprecation, prev_argument="product", new_argument="products"
|
||||
),
|
||||
"constraint.unassign_constraint": partial(
|
||||
batching_argument_deprecation, prev_argument="product", new_argument="products"
|
||||
),
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -64,7 +64,8 @@ class Usecase:
|
||||
self.settings["product"].PredefinedType = "USERDEFINED"
|
||||
elif hasattr(self.settings["product"], "ObjectType"):
|
||||
relating_type = ifcopenshell.util.element.get_type(self.settings["product"])
|
||||
if relating_type and relating_type.PredefinedType != "NOTDEFINED":
|
||||
# Allow for None due to https://github.com/buildingSMART/IFC4.3.x-development/issues/818
|
||||
if relating_type and relating_type.PredefinedType not in ("NOTDEFINED", None):
|
||||
self.settings["product"].ObjectType = None
|
||||
self.settings["product"].PredefinedType = None
|
||||
elif (
|
||||
|
||||
@@ -19,10 +19,11 @@
|
||||
import ifcopenshell
|
||||
import ifcopenshell.util.schema
|
||||
import ifcopenshell.util.date
|
||||
from typing import Union
|
||||
|
||||
|
||||
class Usecase:
|
||||
def __init__(self, file, classification=None):
|
||||
def __init__(self, file: ifcopenshell.file, classification: Union[str, ifcopenshell.entity_instance]):
|
||||
"""Adds a new classification system to the project
|
||||
|
||||
External classification systems such as Uniclass or Omniclass are
|
||||
@@ -81,7 +82,7 @@ class Usecase:
|
||||
"classification": classification,
|
||||
}
|
||||
|
||||
def execute(self):
|
||||
def execute(self) -> ifcopenshell.entity_instance:
|
||||
if isinstance(self.settings["classification"], str):
|
||||
classification = self.file.createIfcClassification(Name=self.settings["classification"])
|
||||
self.relate_to_project(classification)
|
||||
|
||||
@@ -17,12 +17,24 @@
|
||||
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import ifcopenshell
|
||||
import ifcopenshell.api
|
||||
import ifcopenshell.util.element
|
||||
import ifcopenshell.util.schema
|
||||
from typing import Optional, Union
|
||||
|
||||
|
||||
class Usecase:
|
||||
def __init__(self, file, product=None, reference=None, identification=None, name=None, classification=None, is_lightweight=True):
|
||||
"""Adds a new classification reference and assigns it to a product
|
||||
def __init__(
|
||||
self,
|
||||
file: ifcopenshell.file,
|
||||
products: list[ifcopenshell.entity_instance],
|
||||
reference: Optional[ifcopenshell.entity_instance] = None,
|
||||
identification: Optional[str] = None,
|
||||
name: Optional[str] = None,
|
||||
classification: Optional[ifcopenshell.entity_instance] = None,
|
||||
is_lightweight=True,
|
||||
):
|
||||
"""Adds a new classification reference and assigns it to the list of products
|
||||
|
||||
A classification reference is a single entry such as "Pr_12_23_34" that
|
||||
is part of an external classification system (such as Uniclass or
|
||||
@@ -33,7 +45,7 @@ class Usecase:
|
||||
resources such as profiles, documents, libraries, and so on.
|
||||
|
||||
Classification references can be added in two ways. Option 1) specify a
|
||||
custom arbitrary reference, where you have the manually specify the
|
||||
custom arbitrary reference, where you have to manually specify the
|
||||
identification (e.g. "Pr_12_23_45") and name (e.g. "Door Products").
|
||||
Option 2) add a reference from an IFC classification library. The latter
|
||||
is preferred if you are using a common classification system such as
|
||||
@@ -52,13 +64,13 @@ class Usecase:
|
||||
assigned to both the type and an occurrence, then the assignment at the
|
||||
occurrence will override the type classification.
|
||||
|
||||
:param product: The IFC object, property, or resource you want to
|
||||
:param product: The list of IFC objects, properties, or resources you want to
|
||||
associate the classification reference to.
|
||||
:type product: ifcopenshell.entity_instance.entity_instance
|
||||
:type product: list[ifcopenshell.entity_instance.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 product: ifcopenshell.entity_instance.entity_instance, optional
|
||||
:type reference: ifcopenshell.entity_instance.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
|
||||
@@ -70,7 +82,7 @@ class Usecase:
|
||||
: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 product: ifcopenshell.entity_instance.entity_instance
|
||||
:type classification: ifcopenshell.entity_instance.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
|
||||
@@ -81,8 +93,12 @@ class Usecase:
|
||||
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
|
||||
:rtype: ifcopenshell.entity_instance.entity_instance
|
||||
or `None` if `products` was empty list.
|
||||
:rtype: Union[ifcopenshell.entity_instance.entity_instance, None]
|
||||
|
||||
Example:
|
||||
|
||||
@@ -93,7 +109,7 @@ class Usecase:
|
||||
classification = ifcopenshell.api.run("classification.add_classification",
|
||||
model, classification="MyCustomClassification")
|
||||
ifcopenshell.api.run("classification.add_reference", model,
|
||||
product=wall_type, classification=classification,
|
||||
products=[wall_type], classification=classification,
|
||||
identification="W_01", name="Interior Walls")
|
||||
|
||||
# Option 2: adding a popular classification from a library
|
||||
@@ -104,12 +120,12 @@ class Usecase:
|
||||
reference = [r for r in library.by_type("IfcClassificationReference")
|
||||
if r.Identification == "XYZ"][0]
|
||||
ifcopenshell.api.run("classification.add_reference", model,
|
||||
product=wall_type, classification=classification,
|
||||
products=[wall_type], classification=classification,
|
||||
reference=reference)
|
||||
"""
|
||||
self.file = file
|
||||
self.settings = {
|
||||
"product": product,
|
||||
"products": products,
|
||||
"reference": reference,
|
||||
"identification": identification,
|
||||
"name": name,
|
||||
@@ -117,8 +133,27 @@ class Usecase:
|
||||
"is_lightweight": is_lightweight,
|
||||
}
|
||||
|
||||
def execute(self):
|
||||
self.is_rooted = self.settings["product"].is_a("IfcRoot")
|
||||
def execute(self) -> Union[ifcopenshell.entity_instance, None]:
|
||||
if not self.settings["products"]:
|
||||
return
|
||||
|
||||
if self.settings["reference"]:
|
||||
referenced = ifcopenshell.util.element.get_referenced_elements(self.settings["reference"])
|
||||
if set(self.settings["products"]).issubset(referenced):
|
||||
# nothing to do, all elements already have this reference assigned
|
||||
return self.settings["reference"]
|
||||
|
||||
self.rooted_products: set[ifcopenshell.entity_instance] = set()
|
||||
self.non_rooted_products: set[ifcopenshell.entity_instance] = set()
|
||||
for product in self.settings["products"]:
|
||||
if product.is_a("IfcRoot"):
|
||||
self.rooted_products.add(product)
|
||||
else:
|
||||
self.non_rooted_products.add(product)
|
||||
|
||||
if self.non_rooted_products and self.file.schema == "IFC2X3":
|
||||
raise TypeError(f"Cannot add reference to non-IfcRoot element in IFC2X3: {self.non_rooted_products}.")
|
||||
|
||||
if self.settings["reference"]:
|
||||
return self.add_from_library()
|
||||
return self.add_from_identification()
|
||||
@@ -134,14 +169,10 @@ class Usecase:
|
||||
else:
|
||||
reference.Identification = self.settings["identification"]
|
||||
|
||||
relationship = self.get_existing_relationship(reference)
|
||||
if relationship:
|
||||
self.add_to_existing_relationship(relationship)
|
||||
else:
|
||||
self.add_new_relationship(reference)
|
||||
self.update_relationships(reference)
|
||||
return reference
|
||||
|
||||
def add_from_library(self):
|
||||
def add_from_library(self) -> ifcopenshell.entity_instance:
|
||||
if hasattr(self.settings["reference"], "ItemReference"):
|
||||
identification = self.settings["reference"].ItemReference # IFC2X3
|
||||
else:
|
||||
@@ -155,8 +186,9 @@ class Usecase:
|
||||
old_referenced_source = self.settings["reference"].ReferencedSource
|
||||
self.settings["reference"].ReferencedSource = None
|
||||
else:
|
||||
classification_name = self.settings["classification"].Name
|
||||
existing_classification = [
|
||||
c for c in self.file.by_type("IfcClassification") if c.Name == self.settings["classification"].Name
|
||||
c for c in self.file.by_type("IfcClassification") if c.Name == classification_name
|
||||
]
|
||||
|
||||
reference = migrator.migrate(self.settings["reference"], self.file)
|
||||
@@ -174,15 +206,10 @@ class Usecase:
|
||||
for element in to_delete:
|
||||
self.file.remove(element)
|
||||
|
||||
relationship = self.get_existing_relationship(reference)
|
||||
if relationship:
|
||||
self.add_to_existing_relationship(relationship)
|
||||
else:
|
||||
self.add_new_relationship(reference)
|
||||
|
||||
self.update_relationships(reference)
|
||||
return reference
|
||||
|
||||
def get_existing_reference(self, identification):
|
||||
def get_existing_reference(self, identification: Optional[str] = None) -> Union[ifcopenshell.entity_instance, None]:
|
||||
for reference in self.file.by_type("IfcClassificationReference"):
|
||||
if self.file.schema == "IFC2X3":
|
||||
if reference.ItemReference == identification:
|
||||
@@ -191,39 +218,39 @@ class Usecase:
|
||||
if reference.Identification == identification:
|
||||
return reference
|
||||
|
||||
def add_new_relationship(self, reference):
|
||||
if self.is_rooted:
|
||||
self.file.create_entity(
|
||||
"IfcRelAssociatesClassification",
|
||||
GlobalId=ifcopenshell.guid.new(),
|
||||
RelatedObjects=[self.settings["product"]],
|
||||
RelatingClassification=reference,
|
||||
)
|
||||
else:
|
||||
self.file.create_entity(
|
||||
"IfcExternalReferenceRelationship",
|
||||
RelatingReference=reference,
|
||||
RelatedResourceObjects=[self.settings["product"]],
|
||||
)
|
||||
|
||||
def add_to_existing_relationship(self, rel):
|
||||
if self.is_rooted:
|
||||
related_objects = set(rel.RelatedObjects)
|
||||
related_objects.add(self.settings["product"])
|
||||
rel.RelatedObjects = list(related_objects)
|
||||
else:
|
||||
related_objects = set(rel.RelatedResourceObjects)
|
||||
related_objects.add(self.settings["product"])
|
||||
rel.RelatedResourceObjects = list(related_objects)
|
||||
|
||||
def get_existing_relationship(self, reference):
|
||||
if self.is_rooted:
|
||||
def update_relationships(self, reference: ifcopenshell.entity_instance) -> None:
|
||||
root_rel, non_root_rel = None, None
|
||||
if self.rooted_products:
|
||||
if self.file.schema == "IFC2X3":
|
||||
for rel in self.file.by_type("IfcRelAssociatesClassification"):
|
||||
if rel.RelatingClassification == reference:
|
||||
return rel
|
||||
elif reference.ClassificationRefForObjects:
|
||||
return reference.ClassificationRefForObjects[0]
|
||||
elif self.file.schema != "IFC2X3":
|
||||
if reference.ExternalReferenceForResources:
|
||||
return reference.ExternalReferenceForResources[0]
|
||||
root_rel = rel
|
||||
break
|
||||
else:
|
||||
root_rel = next(iter(reference.ClassificationRefForObjects), None)
|
||||
|
||||
if root_rel:
|
||||
related_objects = set(root_rel.RelatedObjects) | self.rooted_products
|
||||
root_rel.RelatedObjects = list(related_objects)
|
||||
ifcopenshell.api.run("owner.update_owner_history", self.file, **{"element": root_rel})
|
||||
else:
|
||||
self.file.create_entity(
|
||||
"IfcRelAssociatesClassification",
|
||||
OwnerHistory=ifcopenshell.api.run("owner.create_owner_history", self.file),
|
||||
GlobalId=ifcopenshell.guid.new(),
|
||||
RelatedObjects=list(self.rooted_products),
|
||||
RelatingClassification=reference,
|
||||
)
|
||||
|
||||
if self.non_rooted_products:
|
||||
# NOTE: Only Ifc4+. Ifc2x3 is already handled by raising TypeError
|
||||
non_root_rel = next(iter(reference.ExternalReferenceForResources), None)
|
||||
if non_root_rel:
|
||||
related_objects = set(non_root_rel.RelatedResourceObjects) | self.non_rooted_products
|
||||
non_root_rel.RelatedResourceObjects = list(related_objects)
|
||||
else:
|
||||
self.file.create_entity(
|
||||
"IfcExternalReferenceRelationship",
|
||||
RelatingReference=reference,
|
||||
RelatedResourceObjects=list(self.non_rooted_products),
|
||||
)
|
||||
|
||||
@@ -17,12 +17,18 @@
|
||||
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import ifcopenshell
|
||||
import ifcopenshell.api
|
||||
import ifcopenshell.util.element
|
||||
|
||||
|
||||
class Usecase:
|
||||
def __init__(self, file, reference=None, product=None):
|
||||
"""Removes a classification reference from a product
|
||||
def __init__(
|
||||
self,
|
||||
file: ifcopenshell.file,
|
||||
reference: ifcopenshell.entity_instance,
|
||||
products: list[ifcopenshell.entity_instance],
|
||||
):
|
||||
"""Removes a classification reference from the list of products
|
||||
|
||||
If the classification reference is no longer associated to any products,
|
||||
the classification reference itself is also removed.
|
||||
@@ -30,9 +36,12 @@ class Usecase:
|
||||
:param reference: The IfcClassificationReference entity of the
|
||||
relationship you want to remove.
|
||||
:type reference: ifcopenshell.entity_instance.entity_instance
|
||||
:param product: The object entity of the relationship you want to
|
||||
:param product: The list fo object entities of the relationship you want to
|
||||
remove.
|
||||
:type reference: ifcopenshell.entity_instance.entity_instance
|
||||
:type product: list[ifcopenshell.entity_instance.entity_instance]
|
||||
|
||||
:raises TypeError: If file is IFC2X3 and `products` has non-IfcRoot elements.
|
||||
|
||||
:return: None
|
||||
:rtype: None
|
||||
|
||||
@@ -44,42 +53,75 @@ class Usecase:
|
||||
classification = ifcopenshell.api.run("classification.add_classification",
|
||||
model, classification="MyCustomClassification")
|
||||
reference = ifcopenshell.api.run("classification.add_reference", model,
|
||||
product=wall_type, classification=classification,
|
||||
products=[wall_type], classification=classification,
|
||||
identification="W_01", name="Interior Walls")
|
||||
ifcopenshell.api.run("classification.remove_reference", model,
|
||||
reference=reference, product=wall_type)
|
||||
reference=reference, products=[wall_type])
|
||||
"""
|
||||
self.file = file
|
||||
self.settings = {"reference": reference, "product": product}
|
||||
self.settings = {"reference": reference, "products": products}
|
||||
|
||||
def execute(self):
|
||||
if self.settings["product"].is_a("IfcRoot"):
|
||||
for rel in self.file.by_type("IfcRelAssociatesClassification"):
|
||||
if rel.RelatingClassification == self.settings["reference"] and rel.RelatedObjects:
|
||||
if self.settings["product"] in rel.RelatedObjects:
|
||||
related_objects = list(rel.RelatedObjects)
|
||||
related_objects.remove(self.settings["product"])
|
||||
if len(related_objects):
|
||||
rel.RelatedObjects = related_objects
|
||||
else:
|
||||
history = rel.OwnerHistory
|
||||
self.file.remove(rel)
|
||||
if history:
|
||||
ifcopenshell.util.element.remove_deep2(self.file, history)
|
||||
else:
|
||||
for rel in self.file.by_type("IfcExternalReferenceRelationship"):
|
||||
if rel.RelatingReference == self.settings["reference"] and rel.RelatedResourceObjects:
|
||||
if self.settings["product"] in rel.RelatedResourceObjects:
|
||||
related_objects = list(rel.RelatedResourceObjects)
|
||||
related_objects.remove(self.settings["product"])
|
||||
if len(related_objects):
|
||||
rel.RelatedResourceObjects = related_objects
|
||||
else:
|
||||
self.file.remove(rel)
|
||||
def execute(self) -> None:
|
||||
is_ifc2x3 = self.file.schema == "IFC2X3"
|
||||
products = set(self.settings["products"])
|
||||
referenced = ifcopenshell.util.element.get_referenced_elements(self.settings["reference"])
|
||||
products -= products.difference(referenced)
|
||||
|
||||
# all products are already unassigned from a reference
|
||||
if not products:
|
||||
return
|
||||
|
||||
rooted_products: set[ifcopenshell.entity_instance] = set()
|
||||
non_rooted_products: set[ifcopenshell.entity_instance] = set()
|
||||
for product in self.settings["products"]:
|
||||
if product.is_a("IfcRoot"):
|
||||
rooted_products.add(product)
|
||||
else:
|
||||
non_rooted_products.add(product)
|
||||
|
||||
if non_rooted_products and is_ifc2x3:
|
||||
raise TypeError(f"Cannot add reference to non-IfcRoot element in IFC2X3: {non_rooted_products}.")
|
||||
|
||||
if rooted_products:
|
||||
reference_rels: set[ifcopenshell.entity_instance] = set()
|
||||
for product in rooted_products:
|
||||
reference_rels.update(product.HasAssociations)
|
||||
|
||||
reference_rels = {
|
||||
rel
|
||||
for rel in reference_rels
|
||||
if rel.is_a("IfcRelAssociatesClassification")
|
||||
and rel.RelatingClassification == self.settings["reference"]
|
||||
}
|
||||
|
||||
for rel in reference_rels:
|
||||
related_objects = set(rel.RelatedObjects) - rooted_products
|
||||
if related_objects:
|
||||
rel.RelatedObjects = list(related_objects)
|
||||
ifcopenshell.api.run("owner.update_owner_history", self.file, **{"element": rel})
|
||||
else:
|
||||
history = rel.OwnerHistory
|
||||
self.file.remove(rel)
|
||||
if history:
|
||||
ifcopenshell.util.element.remove_deep2(self.file, history)
|
||||
|
||||
if non_rooted_products:
|
||||
reference_rels: set[ifcopenshell.entity_instance] = set()
|
||||
for product in non_rooted_products:
|
||||
rels = getattr(product, "HasExternalReferences", None)
|
||||
if rels is None:
|
||||
rels = getattr(product, "HasExternalReference", [])
|
||||
reference_rels.update(rels)
|
||||
|
||||
reference_rels = {rel for rel in reference_rels if rel.RelatingReference == self.settings["reference"]}
|
||||
for rel in reference_rels:
|
||||
related_objects = set(rel.RelatedResourceObjects) - non_rooted_products
|
||||
if related_objects:
|
||||
rel.RelatedResourceObjects = list(related_objects)
|
||||
else:
|
||||
self.file.remove(rel)
|
||||
|
||||
# TODO: we only handle lightweight classifications here
|
||||
if (
|
||||
not self.settings["reference"].ClassificationRefForObjects
|
||||
and not self.settings["reference"].ExternalReferenceForResources
|
||||
):
|
||||
referenced_elements = ifcopenshell.util.element.get_referenced_elements(self.settings["reference"])
|
||||
if not referenced_elements:
|
||||
self.file.remove(self.settings["reference"])
|
||||
|
||||
@@ -17,11 +17,18 @@
|
||||
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import ifcopenshell
|
||||
import ifcopenshell.api
|
||||
from typing import Union
|
||||
|
||||
|
||||
class Usecase:
|
||||
def __init__(self, file, product=None, constraint=None):
|
||||
"""Assigns a constraint to a product
|
||||
def __init__(
|
||||
self,
|
||||
file: ifcopenshell.file,
|
||||
products: list[ifcopenshell.entity_instance],
|
||||
constraint: ifcopenshell.entity_instance,
|
||||
):
|
||||
"""Assigns a constraint to a list of products
|
||||
|
||||
This assigns a relationship between a product and a constraint, so that
|
||||
when a product's properties and quantities do not match the requirements
|
||||
@@ -31,36 +38,58 @@ class Usecase:
|
||||
constraints are inherited from the type. This way, it is not necessary
|
||||
to create lots of constraint assignments.
|
||||
|
||||
:param product: The product the constraint applies to. This is anything
|
||||
:param products: The list of products the constraint applies to. This is anything
|
||||
which can have properties or quantities.
|
||||
:type product: ifcopenshell.entity_instance.entity_instance
|
||||
:type products: list[ifcopenshell.entity_instance.entity_instance]
|
||||
:param constraint: The IfcObjective constraint
|
||||
:type constraint: ifcopenshell.entity_instance.entity_instance
|
||||
:return: The new or updated IfcRelAssociatesConstraint relationship
|
||||
or `None` if `products` was an empty list.
|
||||
:rtype: ifcopenshell.entity_instance.entity_instance
|
||||
"""
|
||||
self.file = file
|
||||
self.settings = {
|
||||
"product": product,
|
||||
"products": products,
|
||||
"constraint": constraint,
|
||||
}
|
||||
|
||||
def execute(self):
|
||||
rel = self.get_constraint_rel()
|
||||
related_objects = set(rel.RelatedObjects) if rel.RelatedObjects else set()
|
||||
related_objects.add(self.settings["product"])
|
||||
rel.RelatedObjects = list(related_objects)
|
||||
return rel
|
||||
def execute(self) -> Union[ifcopenshell.entity_instance, None]:
|
||||
products = set(self.settings["products"])
|
||||
if not products:
|
||||
return
|
||||
|
||||
self.constraint = self.settings["constraint"]
|
||||
|
||||
rels = self.get_constraint_rels()
|
||||
related_objects = set()
|
||||
for rel in rels:
|
||||
related_objects.update(rel.RelatedObjects)
|
||||
|
||||
products_to_assign = products - related_objects
|
||||
if not products_to_assign:
|
||||
return rels[0]
|
||||
|
||||
rel = next(iter(rels), None)
|
||||
|
||||
if rel:
|
||||
related_objects = set(rel.RelatedObjects) | products_to_assign
|
||||
rel.RelatedObjects = list(related_objects)
|
||||
ifcopenshell.api.run("owner.update_owner_history", self.file, **{"element": rel})
|
||||
return rel
|
||||
|
||||
def get_constraint_rel(self):
|
||||
for rel in self.file.by_type("IfcRelAssociatesConstraint"):
|
||||
if rel.RelatingConstraint == self.settings["constraint"]:
|
||||
return rel
|
||||
return self.file.create_entity(
|
||||
"IfcRelAssociatesConstraint",
|
||||
**{
|
||||
"GlobalId": ifcopenshell.guid.new(),
|
||||
# TODO: owner history
|
||||
"RelatingConstraint": self.settings["constraint"],
|
||||
"OwnerHistory": ifcopenshell.api.run("owner.create_owner_history", self.file),
|
||||
"RelatingConstraint": self.constraint,
|
||||
"RelatedObjects": list(products_to_assign),
|
||||
}
|
||||
)
|
||||
|
||||
def get_constraint_rels(self) -> list[ifcopenshell.entity_instance]:
|
||||
rels = []
|
||||
for rel in self.file.get_inverse(self.constraint):
|
||||
if rel.is_a("IfcRelAssociatesConstraint"):
|
||||
rels.append(rel)
|
||||
return rels
|
||||
|
||||
@@ -17,18 +17,24 @@
|
||||
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import ifcopenshell
|
||||
import ifcopenshell.api
|
||||
import ifcopenshell.util.element
|
||||
|
||||
|
||||
class Usecase:
|
||||
def __init__(self, file, product=None, constraint=None):
|
||||
"""Unassigns a constraint to a product
|
||||
def __init__(
|
||||
self,
|
||||
file: ifcopenshell.file,
|
||||
products: list[ifcopenshell.entity_instance],
|
||||
constraint: ifcopenshell.entity_instance,
|
||||
):
|
||||
"""Unassigns a constraint from a list of products
|
||||
|
||||
The constraint will not be deleted and is available to be assigned to
|
||||
other products.
|
||||
|
||||
:param product: The product the constraint applies to.
|
||||
:type product: ifcopenshell.entity_instance.entity_instance
|
||||
:param products: The list of products the constraint applies to.
|
||||
:type products: list[ifcopenshell.entity_instance.entity_instance]
|
||||
:param constraint: The IfcObjective constraint
|
||||
:type constraint: ifcopenshell.entity_instance.entity_instance
|
||||
:return: None
|
||||
@@ -36,14 +42,42 @@ class Usecase:
|
||||
"""
|
||||
self.file = file
|
||||
self.settings = {
|
||||
"product": product,
|
||||
"products": products,
|
||||
"constraint": constraint,
|
||||
}
|
||||
|
||||
def execute(self):
|
||||
for rel in self.settings["product"].HasAssociations:
|
||||
if rel.is_a("IfcRelAssociatesConstraint") and rel.RelatingConstraint == self.settings["constraint"]:
|
||||
history = rel.OwnerHistory
|
||||
self.file.remove(rel)
|
||||
if history:
|
||||
ifcopenshell.util.element.remove_deep2(self.file, history)
|
||||
products = set(self.settings["products"])
|
||||
if not products:
|
||||
return
|
||||
|
||||
self.constraint = self.settings["constraint"]
|
||||
rels = self.get_constraint_rels()
|
||||
related_objects = set()
|
||||
for rel in rels:
|
||||
related_objects.update(rel.RelatedObjects)
|
||||
|
||||
if not related_objects.intersection(products):
|
||||
return
|
||||
|
||||
for rel in rels:
|
||||
related_objects = set(rel.RelatedObjects)
|
||||
if not related_objects.intersection(products):
|
||||
continue
|
||||
related_objects -= products
|
||||
if related_objects:
|
||||
rel.RelatedObjects = list(related_objects)
|
||||
ifcopenshell.api.run("owner.update_owner_history", self.file, **{"element": rel})
|
||||
continue
|
||||
|
||||
history = rel.OwnerHistory
|
||||
self.file.remove(rel)
|
||||
if history:
|
||||
ifcopenshell.util.element.remove_deep2(self.file, history)
|
||||
|
||||
def get_constraint_rels(self) -> list[ifcopenshell.entity_instance]:
|
||||
rels = []
|
||||
for rel in self.file.get_inverse(self.constraint):
|
||||
if rel.is_a("IfcRelAssociatesConstraint"):
|
||||
rels.append(rel)
|
||||
return rels
|
||||
|
||||
@@ -69,10 +69,12 @@ class Usecase:
|
||||
|
||||
def execute(self) -> ifcopenshell.entity_instance:
|
||||
if self.file.schema == "IFC2X3":
|
||||
reference = self.file.create_entity("IfcDocumentReference")
|
||||
reference = self.file.create_entity("IfcDocumentReference", ItemReference="X")
|
||||
if self.settings["information"]:
|
||||
references = list(self.settings["information"].DocumentReferences or [])
|
||||
references.append(reference)
|
||||
self.settings["information"].DocumentReferences = references
|
||||
return reference
|
||||
return self.file.create_entity("IfcDocumentReference", ReferencedDocument=self.settings["information"])
|
||||
return self.file.create_entity(
|
||||
"IfcDocumentReference", ReferencedDocument=self.settings["information"], Identification="X"
|
||||
)
|
||||
|
||||
@@ -17,11 +17,19 @@
|
||||
# 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, document=None):
|
||||
"""Assigns a document to a product
|
||||
def __init__(
|
||||
self,
|
||||
file: ifcopenshell.file,
|
||||
products: list[ifcopenshell.entity_instance],
|
||||
document: ifcopenshell.entity_instance,
|
||||
):
|
||||
"""Assigns a document to a list of products
|
||||
|
||||
An object may be assigned to zero, one, or multiple documents. Almost
|
||||
any object or property may be assigned to a document, though typically
|
||||
@@ -32,14 +40,16 @@ class Usecase:
|
||||
consistent with other external relationships (such as classification
|
||||
systems or libraries).
|
||||
|
||||
:param product: The object to associate the document to. This could be
|
||||
:param product: The list of objects to associate the document to. This could be
|
||||
almost any sensible object in IFC.
|
||||
:type product: ifcopenshell.entity_instance.entity_instance
|
||||
:type product: list[ifcopenshell.entity_instance.entity_instance]
|
||||
:param document: The IfcDocumentReference to associate to, or
|
||||
alternatively an IfcDocumentInformation, though this is not
|
||||
recommended.
|
||||
:type document: ifcopenshell.entity_instance.entity_instance
|
||||
:return: The IfcRelAssociatesDocument relationship
|
||||
or `None` if `products` was an empty list or all products were
|
||||
already assigned to the `document`.
|
||||
:rtype: ifcopenshell.entity_instance.entity_instance
|
||||
|
||||
Example:
|
||||
@@ -54,42 +64,51 @@ class Usecase:
|
||||
reference = ifcopenshell.api.run("document.add_reference", model, information=document)
|
||||
|
||||
# Let's imagine storey represents an IfcBuildingStorey for the ground floor
|
||||
ifcopenshell.api.run("document.assign_document", model, product=storey, document=reference)
|
||||
ifcopenshell.api.run("document.assign_document", model, products=[storey], document=reference)
|
||||
"""
|
||||
self.file = file
|
||||
self.settings = {
|
||||
"product": product,
|
||||
"products": products,
|
||||
"document": document,
|
||||
}
|
||||
|
||||
def execute(self):
|
||||
rel = self.get_document_rel()
|
||||
related_objects = set(rel.RelatedObjects) if rel.RelatedObjects else set()
|
||||
related_objects.add(self.settings["product"])
|
||||
rel.RelatedObjects = list(related_objects)
|
||||
def execute(self) -> Union[ifcopenshell.entity_instance, None]:
|
||||
# TODO: do we need to support non-ifcroot elements like we do in classification.add_reference?
|
||||
# NOTE: reuses code from `library.assign_reference`
|
||||
|
||||
referenced_elements = ifcopenshell.util.element.get_referenced_elements(self.settings["document"])
|
||||
products: set[ifcopenshell.entity_instance] = set(self.settings["products"])
|
||||
products = products - referenced_elements
|
||||
|
||||
if not products:
|
||||
return
|
||||
|
||||
def get_document_rel(self):
|
||||
if self.file.schema == "IFC2X3":
|
||||
for rel in self.file.by_type("IfcRelAssociatesDocument"):
|
||||
if rel.RelatingDocument == self.settings["document"]:
|
||||
return rel
|
||||
rel = next(
|
||||
(
|
||||
r
|
||||
for r in self.file.by_type("IfcRelAssociatesDocument")
|
||||
if r.RelatingDocument == self.settings["document"]
|
||||
),
|
||||
None,
|
||||
)
|
||||
else:
|
||||
if (
|
||||
hasattr(self.settings["document"], "DocumentRefForObjects")
|
||||
and self.settings["document"].DocumentRefForObjects
|
||||
):
|
||||
return self.settings["document"].DocumentRefForObjects[0]
|
||||
elif (
|
||||
hasattr(self.settings["document"], "DocumentInfoForObjects")
|
||||
and self.settings["document"].DocumentInfoForObjects
|
||||
):
|
||||
return self.settings["document"].DocumentInfoForObjects[0]
|
||||
ifc_class = self.settings["document"].is_a()
|
||||
if ifc_class == "IfcDocumentReference":
|
||||
rel = next(iter(self.settings["document"].DocumentRefForObjects), None)
|
||||
elif ifc_class == "IfcDocumentInformation":
|
||||
rel = next(iter(self.settings["document"].DocumentInfoForObjects), None)
|
||||
|
||||
return self.file.create_entity(
|
||||
"IfcRelAssociatesDocument",
|
||||
**{
|
||||
"GlobalId": ifcopenshell.guid.new(),
|
||||
"OwnerHistory": ifcopenshell.api.run("owner.create_owner_history", self.file),
|
||||
"RelatingDocument": self.settings["document"],
|
||||
}
|
||||
)
|
||||
if not rel:
|
||||
return self.file.create_entity(
|
||||
"IfcRelAssociatesDocument",
|
||||
GlobalId=ifcopenshell.guid.new(),
|
||||
OwnerHistory=ifcopenshell.api.run("owner.create_owner_history", self.file),
|
||||
RelatedObjects=list(products),
|
||||
RelatingDocument=self.settings["document"],
|
||||
)
|
||||
|
||||
related_objects = set(rel.RelatedObjects) | products
|
||||
rel.RelatedObjects = list(related_objects)
|
||||
ifcopenshell.api.run("owner.update_owner_history", self.file, element=rel)
|
||||
return rel
|
||||
|
||||
@@ -17,16 +17,22 @@
|
||||
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import ifcopenshell
|
||||
import ifcopenshell.api
|
||||
import ifcopenshell.util.element
|
||||
|
||||
|
||||
class Usecase:
|
||||
def __init__(self, file, product=None, document=None):
|
||||
"""Unassigns a document and a product association
|
||||
def __init__(
|
||||
self,
|
||||
file: ifcopenshell.file,
|
||||
products: list[ifcopenshell.entity_instance],
|
||||
document: ifcopenshell.entity_instance,
|
||||
):
|
||||
"""Unassigns a document and an association to the list of products
|
||||
|
||||
:param product: The object that the document reference or information is
|
||||
:param product: The list of objects that the document reference or information is
|
||||
related to.
|
||||
:type product: ifcopenshell.entity_instance.entity_instance
|
||||
:type product: list[ifcopenshell.entity_instance.entity_instance]
|
||||
:param document: The IfcDocumentReference (typically) or in rare cases
|
||||
the IfcDocumentInformation that is associated with the product
|
||||
:type document: ifcopenshell.entity_instance.entity_instance
|
||||
@@ -45,24 +51,39 @@ class Usecase:
|
||||
reference = ifcopenshell.api.run("document.add_reference", model, information=document)
|
||||
|
||||
# Let's imagine storey represents an IfcBuildingStorey for the ground floor
|
||||
ifcopenshell.api.run("document.assign_document", model, product=storey, document=reference)
|
||||
ifcopenshell.api.run("document.assign_document", model, products=[storey], document=reference)
|
||||
|
||||
# Now let's change our mind and remove the association
|
||||
ifcopenshell.api.run("document.unassign_document", model, product=storey, document=reference)
|
||||
ifcopenshell.api.run("document.unassign_document", model, products=[storey], document=reference)
|
||||
"""
|
||||
self.file = file
|
||||
self.settings = {
|
||||
"product": product,
|
||||
"products": products,
|
||||
"document": document,
|
||||
}
|
||||
|
||||
def execute(self):
|
||||
for rel in self.settings["product"].HasAssociations:
|
||||
if rel.is_a("IfcRelAssociatesDocument") and rel.RelatingDocument == self.settings["document"]:
|
||||
if len(rel.RelatedObjects) == 1:
|
||||
history = rel.OwnerHistory
|
||||
self.file.remove(rel)
|
||||
if history:
|
||||
ifcopenshell.util.element.remove_deep2(self.file, history)
|
||||
else:
|
||||
rel.RelatedObjects = [o for o in rel.RelatedObjects if o != self.settings["product"]]
|
||||
# TODO: do we need to support non-ifcroot elements like we do in classification.add_reference?
|
||||
# NOTE: reuses code from `library.un assign_reference`
|
||||
|
||||
reference_rels: set[ifcopenshell.entity_instance] = set()
|
||||
products = set(self.settings["products"])
|
||||
for product in products:
|
||||
reference_rels.update(product.HasAssociations)
|
||||
|
||||
reference_rels = {
|
||||
rel
|
||||
for rel in reference_rels
|
||||
if rel.is_a("IfcRelAssociatesDocument") and rel.RelatingDocument == self.settings["document"]
|
||||
}
|
||||
|
||||
for rel in reference_rels:
|
||||
related_objects = set(rel.RelatedObjects) - products
|
||||
if related_objects:
|
||||
rel.RelatedObjects = list(related_objects)
|
||||
ifcopenshell.api.run("owner.update_owner_history", self.file, **{"element": rel})
|
||||
else:
|
||||
history = rel.OwnerHistory
|
||||
self.file.remove(rel)
|
||||
if history:
|
||||
ifcopenshell.util.element.remove_deep2(self.file, history)
|
||||
|
||||
@@ -26,7 +26,7 @@ class Usecase:
|
||||
surveyor, and a third-party digital engineer with expertise in IFC to
|
||||
moderate. For more information, read the BlenderBIM Add-on documentation
|
||||
for Georeferencing:
|
||||
https://blenderbim.org/docs/users/georeferencing.html
|
||||
https://docs.blenderbim.org/users/georeferencing.html
|
||||
|
||||
For more information about the attributes and data types of an
|
||||
IfcMapConversion, consult the IFC documentation.
|
||||
|
||||
@@ -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"]
|
||||
]
|
||||
|
||||
@@ -18,18 +18,24 @@
|
||||
|
||||
import ifcopenshell
|
||||
import ifcopenshell.util.element
|
||||
import ifcopenshell.api
|
||||
|
||||
|
||||
class Usecase:
|
||||
def __init__(self, file, reference=None, product=None):
|
||||
"""Unassigns a product from a reference
|
||||
def __init__(
|
||||
self,
|
||||
file: ifcopenshell.file,
|
||||
reference: ifcopenshell.entity_instance,
|
||||
products: list[ifcopenshell.entity_instance],
|
||||
):
|
||||
"""Unassigns a product of products from a reference
|
||||
|
||||
If the product isn't assigned to the reference, nothing will happen.
|
||||
|
||||
:param reference: The IfcLibraryReference to unassign from
|
||||
:type reference: ifcopenshell.entity_instance.entity_instance
|
||||
:param product: A IfcProduct element to unassign from the reference
|
||||
:type product: ifcopenshell.entity_instance.entity_instance
|
||||
:param products: A list of IfcProduct elements to unassign from the reference
|
||||
:type products: list[ifcopenshell.entity_instance.entity_instance]
|
||||
:return: None
|
||||
:rtype: None
|
||||
|
||||
@@ -49,27 +55,36 @@ 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)
|
||||
ifcopenshell.api.run("library.unassign_reference", model, reference=reference, products=[ahu])
|
||||
"""
|
||||
|
||||
self.file = file
|
||||
self.settings = {"reference": reference, "product": product}
|
||||
self.settings = {"reference": reference, "products": products}
|
||||
|
||||
def execute(self):
|
||||
rels = self.settings["reference"].LibraryRefForObjects
|
||||
if not rels:
|
||||
return
|
||||
for rel in rels:
|
||||
if self.settings["product"] in rel.RelatedObjects:
|
||||
if len(rel.RelatedObjects) == 1:
|
||||
history = rel.OwnerHistory
|
||||
self.file.remove(rel)
|
||||
if history:
|
||||
ifcopenshell.util.element.remove_deep2(self.file, history)
|
||||
continue
|
||||
related_objects = list(rel.RelatedObjects)
|
||||
related_objects.remove(self.settings["product"])
|
||||
rel.RelatedObjects = related_objects
|
||||
# TODO: do we need to support non-ifcroot elements like we do in classification.add_reference?
|
||||
|
||||
reference_rels: set[ifcopenshell.entity_instance] = set()
|
||||
products = set(self.settings["products"])
|
||||
for product in products:
|
||||
reference_rels.update(product.HasAssociations)
|
||||
|
||||
reference_rels = {
|
||||
rel
|
||||
for rel in reference_rels
|
||||
if rel.is_a("IfcRelAssociatesLibrary") and rel.RelatingLibrary == self.settings["reference"]
|
||||
}
|
||||
|
||||
for rel in reference_rels:
|
||||
related_objects = set(rel.RelatedObjects) - products
|
||||
if related_objects:
|
||||
rel.RelatedObjects = list(related_objects)
|
||||
ifcopenshell.api.run("owner.update_owner_history", self.file, **{"element": rel})
|
||||
else:
|
||||
history = rel.OwnerHistory
|
||||
self.file.remove(rel)
|
||||
if history:
|
||||
ifcopenshell.util.element.remove_deep2(self.file, history)
|
||||
|
||||
@@ -38,7 +38,7 @@ def get_application(ifc: ifcopenshell.file) -> Union[ifcopenshell.entity_instanc
|
||||
if not app and ifc.schema == "IFC2X3":
|
||||
raise Exception(
|
||||
"Please create an application to continue. See the owner.create_owner_history docs for more info."
|
||||
"https://blenderbim.org/docs-python/autoapi/ifcopenshell/api/owner/create_owner_history/index.html"
|
||||
"https://docs.ifcopenshell.org/autoapi/ifcopenshell/api/owner/create_owner_history/index.html"
|
||||
)
|
||||
return (app or [None])[0]
|
||||
|
||||
@@ -58,7 +58,7 @@ def get_user(ifc: ifcopenshell.file) -> Union[ifcopenshell.entity_instance, None
|
||||
if not pao and ifc.schema == "IFC2X3":
|
||||
raise Exception(
|
||||
"Please create a user to continue. See the owner.create_owner_history docs for more info."
|
||||
"https://blenderbim.org/docs-python/autoapi/ifcopenshell/api/owner/create_owner_history/index.html"
|
||||
"https://docs.ifcopenshell.org/autoapi/ifcopenshell/api/owner/create_owner_history/index.html"
|
||||
)
|
||||
return (pao or [None])[0]
|
||||
|
||||
|
||||
@@ -22,11 +22,16 @@ import ifcopenshell.util.element
|
||||
|
||||
|
||||
class Usecase:
|
||||
def __init__(self, file, product=None, relating_structure=None):
|
||||
"""Dereferences the a product and space
|
||||
def __init__(
|
||||
self,
|
||||
file: ifcopenshell.file,
|
||||
products: list[ifcopenshell.entity_instance],
|
||||
relating_structure: ifcopenshell.entity_instance,
|
||||
):
|
||||
"""Dereferences a list of products and space
|
||||
|
||||
:param product: The physical IfcElement that exists in the space.
|
||||
:type product: ifcopenshell.entity_instance.entity_instance
|
||||
:param products: The list of physical IfcElements that exists in the space.
|
||||
:type products: list[ifcopenshell.entity_instance.entity_instance]
|
||||
:param relating_structure: The IfcSpatialStructureElement element, such
|
||||
as IfcBuilding, IfcBuildingStorey, or IfcSpace that the element
|
||||
exists in.
|
||||
@@ -59,23 +64,24 @@ class Usecase:
|
||||
ifcopenshell.api.run("spatial.assign_container", model, products=[column], relating_structure=storey1)
|
||||
|
||||
# And referenced in the others
|
||||
ifcopenshell.api.run("spatial.reference_structure", model, product=column, relating_structure=storey2)
|
||||
ifcopenshell.api.run("spatial.reference_structure", model, product=column, relating_structure=storey3)
|
||||
ifcopenshell.api.run("spatial.reference_structure", model, products=[column], relating_structure=storey2)
|
||||
ifcopenshell.api.run("spatial.reference_structure", model, products=[column], relating_structure=storey3)
|
||||
|
||||
# Actually, it only goes up to storey 2.
|
||||
ifcopenshell.api.run("spatial.dereference_structure", model, product=column, relating_structure=storey3)
|
||||
ifcopenshell.api.run("spatial.dereference_structure", model, products=[column], relating_structure=storey3)
|
||||
"""
|
||||
self.file = file
|
||||
self.settings = {"product": product, "relating_structure": relating_structure}
|
||||
self.settings = {"products": products, "relating_structure": relating_structure}
|
||||
|
||||
def execute(self):
|
||||
for rel in self.settings["product"].ReferencedInStructures:
|
||||
if rel.RelatingStructure != self.settings["relating_structure"]:
|
||||
def execute(self) -> None:
|
||||
products = set(self.settings["products"])
|
||||
for rel in self.settings["relating_structure"].ReferencesElements:
|
||||
related_elements = set(rel.RelatedElements)
|
||||
if not related_elements.intersection(products):
|
||||
continue
|
||||
related_elements = list(rel.RelatedElements)
|
||||
related_elements.remove(self.settings["product"])
|
||||
related_elements = related_elements - products
|
||||
if related_elements:
|
||||
rel.RelatedElements = related_elements
|
||||
rel.RelatedElements = list(related_elements)
|
||||
ifcopenshell.api.run("owner.update_owner_history", self.file, **{"element": rel})
|
||||
else:
|
||||
history = rel.OwnerHistory
|
||||
|
||||
@@ -18,11 +18,18 @@
|
||||
|
||||
import ifcopenshell
|
||||
import ifcopenshell.api
|
||||
import ifcopenshell.util.element
|
||||
from typing import Union
|
||||
|
||||
|
||||
class Usecase:
|
||||
def __init__(self, file, product=None, relating_structure=None):
|
||||
"""Denote that a product is related to a spatial structure
|
||||
def __init__(
|
||||
self,
|
||||
file: ifcopenshell.file,
|
||||
products: list[ifcopenshell.entity_instance],
|
||||
relating_structure: ifcopenshell.entity_instance,
|
||||
):
|
||||
"""Denote that a list products is related to a list of spatial structures
|
||||
|
||||
This is similar to ifcopenshell.api.spatial.assign_container, except
|
||||
that containment can only occur between a product and a single spatial
|
||||
@@ -39,13 +46,15 @@ class Usecase:
|
||||
Referencing is non-hierarchical, so a door may be referenced in multiple
|
||||
spaces simultaneously.
|
||||
|
||||
:param product: The physical IfcElement that exists in the space.
|
||||
:type product: ifcopenshell.entity_instance.entity_instance
|
||||
:param products: The list of physical IfcElements that exists in the space.
|
||||
:type products: list[ifcopenshell.entity_instance.entity_instance]
|
||||
:param relating_structure: The IfcSpatialStructureElement element, such
|
||||
as IfcBuilding, IfcBuildingStorey, or IfcSpace that the element
|
||||
exists in.
|
||||
:type relating_structure: ifcopenshell.entity_instance.entity_instance
|
||||
:return: The IfcRelReferencedInSpatialStructure relationship instance
|
||||
:rtype: ifcopenshell.entity_instance.entity_instance
|
||||
or `None` if `products` was an empty list.
|
||||
:rtype: Union[ifcopenshell.entity_instance, None]
|
||||
|
||||
Example:
|
||||
|
||||
@@ -73,37 +82,43 @@ class Usecase:
|
||||
ifcopenshell.api.run("spatial.assign_container", model, products=[column], relating_structure=storey1)
|
||||
|
||||
# And referenced in the others
|
||||
ifcopenshell.api.run("spatial.reference_structure", model, product=column, relating_structure=storey2)
|
||||
ifcopenshell.api.run("spatial.reference_structure", model, product=column, relating_structure=storey3)
|
||||
ifcopenshell.api.run(
|
||||
"spatial.reference_structure", model, products=[column], relating_structure=[storey2, storey3]
|
||||
)
|
||||
"""
|
||||
self.file = file
|
||||
self.settings = {
|
||||
"product": product,
|
||||
"products": products,
|
||||
"relating_structure": relating_structure,
|
||||
}
|
||||
|
||||
def execute(self):
|
||||
referenced_in_structures = self.settings["product"].ReferencedInStructures
|
||||
references_elements = self.settings["relating_structure"].ReferencesElements
|
||||
def execute(self) -> Union[ifcopenshell.entity_instance, None]:
|
||||
structure = self.settings["relating_structure"]
|
||||
products = set(self.settings["products"])
|
||||
|
||||
for rel in referenced_in_structures:
|
||||
if rel.RelatingStructure == self.settings["relating_structure"]:
|
||||
return
|
||||
if not products:
|
||||
return
|
||||
|
||||
if references_elements:
|
||||
related_elements = list(references_elements[0].RelatedElements)
|
||||
related_elements.append(self.settings["product"])
|
||||
references_elements[0].RelatedElements = related_elements
|
||||
ifcopenshell.api.run("owner.update_owner_history", self.file, **{"element": references_elements[0]})
|
||||
else:
|
||||
references_elements = self.file.create_entity(
|
||||
referenced = ifcopenshell.util.element.get_structure_referenced_elements(structure)
|
||||
products_to_assign = products - referenced
|
||||
rel = next(iter(structure.ReferencesElements), None)
|
||||
|
||||
if not products_to_assign:
|
||||
return rel
|
||||
|
||||
if rel is None:
|
||||
rel = self.file.create_entity(
|
||||
"IfcRelReferencedInSpatialStructure",
|
||||
**{
|
||||
"GlobalId": ifcopenshell.guid.new(),
|
||||
"OwnerHistory": ifcopenshell.api.run("owner.create_owner_history", self.file),
|
||||
"RelatedElements": [self.settings["product"]],
|
||||
"RelatingStructure": self.settings["relating_structure"],
|
||||
"RelatedElements": list(products_to_assign),
|
||||
"RelatingStructure": structure,
|
||||
}
|
||||
)
|
||||
else:
|
||||
related_elements = set(rel.RelatedElements) | products_to_assign
|
||||
rel.RelatedElements = list(related_elements)
|
||||
ifcopenshell.api.run("owner.update_owner_history", self.file, **{"element": rel})
|
||||
|
||||
return references_elements
|
||||
return rel
|
||||
|
||||
@@ -30,7 +30,7 @@ import functools
|
||||
import subprocess
|
||||
import sys
|
||||
import time
|
||||
from typing import Union, Any, Callable, TypeVar
|
||||
from typing import Union, Any, Callable, TypeVar, overload
|
||||
|
||||
from . import ifcopenshell_wrapper
|
||||
from . import settings
|
||||
@@ -317,15 +317,25 @@ class entity_instance(object):
|
||||
|
||||
return self.wrapped_data.to_string(valid_spf)
|
||||
|
||||
def is_a(self, *args) -> Union[str, bool]:
|
||||
@overload
|
||||
def is_a(self) -> str: ...
|
||||
@overload
|
||||
def is_a(self, ifc_class: str) -> bool: ...
|
||||
@overload
|
||||
def is_a(self, with_schema: bool) -> str: ...
|
||||
def is_a(self, *args: Union[str, bool]) -> Union[str, bool]:
|
||||
"""Return the IFC class name of an instance, or checks if an instance belongs to a class.
|
||||
|
||||
The check will also return true if a parent class name is provided.
|
||||
|
||||
:param args: If specified, is a case insensitive IFC class name to check
|
||||
:type args: string
|
||||
or if specified as a boolean then will define whether
|
||||
returned IFC class name should include schema name
|
||||
(e.g. "IFC4.IfcWall" if `True` and "IfcWall" if `False`).
|
||||
If omitted will act as `False`.
|
||||
:type args: Union[str, bool]
|
||||
:returns: Either the name of the class, or a boolean if it passes the check
|
||||
:rtype: string|bool
|
||||
:rtype: Union[str, bool]
|
||||
|
||||
Example:
|
||||
|
||||
|
||||
@@ -23,10 +23,10 @@ from typing import Optional
|
||||
def get_references(element: ifcopenshell.entity_instance, should_inherit=True) -> set[ifcopenshell.entity_instance]:
|
||||
results = set()
|
||||
if not element.is_a("IfcRoot"):
|
||||
if hasattr(element, "HasExternalReferences"):
|
||||
return {r.RelatingReference for r in element.HasExternalReferences or []}
|
||||
elif hasattr(element, "HasExternalReference"): # Seriously, IFC?
|
||||
return {r.RelatingReference for r in element.HasExternalReference or []}
|
||||
if (references := getattr(element, "HasExternalReferences", None)) is not None or (
|
||||
references := getattr(element, "HasExternalReference", None)
|
||||
) is not None:
|
||||
return {r.RelatingReference for r in references}
|
||||
if should_inherit:
|
||||
element_type = ifcopenshell.util.element.get_type(element)
|
||||
if element_type and element_type != element:
|
||||
|
||||
@@ -18,20 +18,59 @@
|
||||
#
|
||||
#
|
||||
|
||||
def get_constraints(product):
|
||||
import ifcopenshell
|
||||
from typing import Union
|
||||
|
||||
|
||||
def get_constraints(product: ifcopenshell.entity_instance) -> list[ifcopenshell.entity_instance]:
|
||||
"""
|
||||
Retrieves the constraints assigned to the `product`.
|
||||
|
||||
:param product: The IFC element.
|
||||
:type product: ifcopenshell.entity_instance.entity_instance
|
||||
:return: List of assigned constraints.
|
||||
:rtype: list[ifcopenshell.entity_instance.entity_instance]
|
||||
"""
|
||||
constraints = []
|
||||
for rel in product.HasAssociations or []:
|
||||
if rel.is_a("IfcRelAssociatesConstraint"):
|
||||
constraints.append(rel.RelatingConstraint)
|
||||
return constraints
|
||||
|
||||
def get_metrics(constraint):
|
||||
|
||||
def get_constrained_elements(constraint: ifcopenshell.entity_instance) -> set[ifcopenshell.entity_instance]:
|
||||
"""
|
||||
Retrieves the elements constrained by a `constraint`.
|
||||
|
||||
:param product: The IFC element.
|
||||
:type product: ifcopenshell.entity_instance.entity_instance
|
||||
:return: Set of elements constrained by a `constrant`.
|
||||
:rtype: set[ifcopenshell.entity_instance.entity_instance]
|
||||
"""
|
||||
elements = set()
|
||||
for rel in constraint.file.get_inverse(constraint):
|
||||
if rel.is_a("IfcRelAssociatesConstraint"):
|
||||
elements.update(rel.RelatedObjects)
|
||||
return elements
|
||||
|
||||
|
||||
def get_metrics(constraint: ifcopenshell.entity_instance) -> list[ifcopenshell.entity_instance]:
|
||||
"""
|
||||
Retrieves the list of nested constraints for a IfcObjective `constraint`.
|
||||
|
||||
:param product: IfcObjective constraint.
|
||||
:type product: ifcopenshell.entity_instance.entity_instance
|
||||
:return: List of nested constraints.
|
||||
:rtype: list[ifcopenshell.entity_instance.entity_instance]
|
||||
"""
|
||||
|
||||
metrics = []
|
||||
for metric in constraint.BenchmarkValues or []:
|
||||
metrics.append(metric)
|
||||
return metrics
|
||||
|
||||
def get_metric_reference(metric, is_deep=True):
|
||||
|
||||
def get_metric_reference(metric: ifcopenshell.entity_instance, is_deep=True):
|
||||
def get_reference_Attribute(ref, path):
|
||||
if ref:
|
||||
if is_deep:
|
||||
@@ -47,7 +86,10 @@ def get_metric_reference(metric, is_deep=True):
|
||||
reference = metric.ReferencePath
|
||||
return get_reference_Attribute(reference, "")
|
||||
|
||||
def get_metric_constraints(resource, attribute):
|
||||
|
||||
def get_metric_constraints(
|
||||
resource: ifcopenshell.entity_instance, attribute
|
||||
) -> Union[list[ifcopenshell.entity_instance], None]:
|
||||
metrics = []
|
||||
for constraint in get_constraints(resource) or []:
|
||||
for metric in get_metrics(constraint) or []:
|
||||
@@ -60,15 +102,14 @@ def get_metric_constraints(resource, attribute):
|
||||
return metrics
|
||||
return None
|
||||
|
||||
def is_hard_constraint(metric):
|
||||
if metric.ConstraintGrade == "HARD" and metric.Benchmark == "EQUALTO":
|
||||
return True
|
||||
|
||||
def is_attribute_locked(product, attribute):
|
||||
def is_hard_constraint(metric: ifcopenshell.entity_instance) -> bool:
|
||||
return metric.ConstraintGrade == "HARD" and metric.Benchmark == "EQUALTO"
|
||||
|
||||
|
||||
def is_attribute_locked(product: ifcopenshell.entity_instance, attribute) -> bool:
|
||||
is_locked = False
|
||||
metrics = get_metric_constraints(
|
||||
product, attribute
|
||||
)
|
||||
metrics = get_metric_constraints(product, attribute)
|
||||
for metric in metrics or []:
|
||||
if is_hard_constraint(metric):
|
||||
is_locked = True
|
||||
|
||||
@@ -20,16 +20,17 @@ from __future__ import annotations
|
||||
import ifcopenshell
|
||||
import ifcopenshell.util.element
|
||||
from typing import Any, Callable, Optional, Union, Literal, overload
|
||||
from collections import namedtuple
|
||||
|
||||
|
||||
def get_pset(
|
||||
element: ifcopenshell.entity_instance,
|
||||
name: str,
|
||||
prop: Optional[str] = None,
|
||||
psets_only=False,
|
||||
qtos_only=False,
|
||||
should_inherit=True,
|
||||
verbose=False,
|
||||
psets_only: bool = False,
|
||||
qtos_only: bool = False,
|
||||
should_inherit: bool = True,
|
||||
verbose: bool = False,
|
||||
) -> Union[Any, dict[str, Any]]:
|
||||
"""Retrieve a single property set or single property
|
||||
|
||||
@@ -429,8 +430,7 @@ def get_predefined_type(element: ifcopenshell.entity_instance) -> str:
|
||||
element = ifcopenshell.by_type("IfcWall")[0]
|
||||
predefined_type = ifcopenshell.util.element.get_predefined_type(element)
|
||||
"""
|
||||
element_type = get_type(element)
|
||||
if element_type:
|
||||
if element_type := get_type(element):
|
||||
predefined_type = getattr(element_type, "PredefinedType", None)
|
||||
if predefined_type == "USERDEFINED" or not predefined_type:
|
||||
predefined_type = getattr(element_type, "ElementType", ...)
|
||||
@@ -563,7 +563,9 @@ def get_material(
|
||||
return get_material(relating_type, should_skip_usage)
|
||||
|
||||
|
||||
def get_materials(element: ifcopenshell.entity_instance, should_inherit=True) -> list[ifcopenshell.entity_instance]:
|
||||
def get_materials(
|
||||
element: ifcopenshell.entity_instance, should_inherit: bool = True
|
||||
) -> list[ifcopenshell.entity_instance]:
|
||||
"""Gets individual materials of an element
|
||||
|
||||
If the element has a material set, the individual materials of that set are
|
||||
@@ -826,7 +828,7 @@ def get_layers(
|
||||
|
||||
|
||||
def get_container(
|
||||
element: ifcopenshell.entity_instance, should_get_direct=False, ifc_class: Optional[str] = None
|
||||
element: ifcopenshell.entity_instance, should_get_direct: bool = False, ifc_class: Optional[str] = None
|
||||
) -> ifcopenshell.entity_instance:
|
||||
"""
|
||||
Retrieves the spatial structure container of an element.
|
||||
@@ -902,6 +904,27 @@ def get_referenced_structures(element: ifcopenshell.entity_instance) -> list[ifc
|
||||
return [r.RelatingStructure for r in getattr(element, "ReferencedInStructures", [])]
|
||||
|
||||
|
||||
def get_structure_referenced_elements(structure: ifcopenshell.entity_instance) -> set[ifcopenshell.entity_instance]:
|
||||
"""Retreives a set of elements referenced by a structure
|
||||
|
||||
:param structure: IfcSpatialElement
|
||||
:type element: ifcopenshell.entity_instance.entity_instance
|
||||
:return: A set of referenced elements, IfcSpatialReferenceSelect
|
||||
:rtype: set[ifcopenshell.entity_instance.entity_instance]
|
||||
|
||||
Example:
|
||||
|
||||
.. code:: python
|
||||
|
||||
element = file.by_type("IfcBuildingStorey")[0]
|
||||
print(ifcopenshell.util.element.get_structure_referenced_elements(element))
|
||||
"""
|
||||
referenced = set()
|
||||
for rel in structure.ReferencesElements:
|
||||
referenced.update(rel.RelatedElements)
|
||||
return referenced
|
||||
|
||||
|
||||
def get_decomposition(element: ifcopenshell.entity_instance, is_recursive=True) -> list[ifcopenshell.entity_instance]:
|
||||
"""
|
||||
Retrieves all subelements of an element based on the spatial decomposition
|
||||
@@ -1092,6 +1115,66 @@ def get_components(element: ifcopenshell.entity_instance, include_ports=False) -
|
||||
return is_decomposed_by[0].RelatedObjects
|
||||
|
||||
|
||||
ReferenceData = namedtuple("ReferenceData", "inverse_attribute, rel_class, relating_element_attribute")
|
||||
|
||||
# References below are omitted because they do not introduce
|
||||
# any additional referenced objects besides the objects
|
||||
# from their supertype IfcExternalReference
|
||||
# - IfcExternallyDefinedHatchStyle
|
||||
# - IfcExternallyDefinedSurfaceStyle
|
||||
# - IfcExternallyDefinedTextFont
|
||||
|
||||
REFERENCE_TYPES: dict[str, ReferenceData] = {
|
||||
"IfcClassificationReference": ReferenceData(
|
||||
"ClassificationRefForObjects",
|
||||
"IfcRelAssociatesClassification",
|
||||
"RelatingClassification",
|
||||
),
|
||||
"IfcDocumentReference": ReferenceData("DocumentRefForObjects", "IfcRelAssociatesDocument", "RelatingDocument"),
|
||||
"IfcLibraryReference": ReferenceData("LibraryRefForObjects", "IfcRelAssociatesLibrary", "RelatingLibrary"),
|
||||
}
|
||||
|
||||
|
||||
def get_referenced_elements(reference: ifcopenshell.entity_instance) -> set[ifcopenshell.entity_instance]:
|
||||
"""Get all elements with assigned `reference`
|
||||
|
||||
:param reference: IfcExternalReference subtype reference
|
||||
:type reference: ifcopenshell.entity_instance.entity_instance
|
||||
:return: The elements with assigned `reference`
|
||||
:rtype: set[ifcopenshell.entity_instance.entity_instance]
|
||||
|
||||
Example:
|
||||
|
||||
.. code:: python
|
||||
|
||||
reference = file.by_type("IfcClassificationReference")[0]
|
||||
elements = ifcopenshell.util.element.get_referenced_elements(reference)
|
||||
"""
|
||||
|
||||
related_objects: set[ifcopenshell.entity_instance] = set()
|
||||
ifc_file = reference.file
|
||||
ifc_class = reference.is_a()
|
||||
|
||||
if ifc_file.schema == "IFC2X3":
|
||||
reference_data = REFERENCE_TYPES.get(ifc_class)
|
||||
if reference_data:
|
||||
for rel in ifc_file.by_type(reference_data.rel_class):
|
||||
if getattr(rel, reference_data.relating_element_attribute) == reference:
|
||||
related_objects.update(rel.RelatedObjects)
|
||||
|
||||
else:
|
||||
# IfcExternalReference
|
||||
for external_rel in reference.ExternalReferenceForResources:
|
||||
related_objects.update(external_rel.RelatedResourceObjects)
|
||||
|
||||
reference_data = REFERENCE_TYPES.get(ifc_class)
|
||||
if reference_data:
|
||||
for rel in getattr(reference, reference_data.inverse_attribute):
|
||||
related_objects.update(rel.RelatedObjects)
|
||||
|
||||
return related_objects
|
||||
|
||||
|
||||
def replace_attribute(element: ifcopenshell.entity_instance, old: Any, new: Any) -> None:
|
||||
for i, attribute_value in enumerate(element):
|
||||
if has_element_reference(attribute_value, old):
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import shapely
|
||||
import shapely.ops
|
||||
import numpy as np
|
||||
import ifcopenshell.util.element
|
||||
import ifcopenshell.util.placement
|
||||
|
||||
@@ -15,7 +15,7 @@ classifiers = [
|
||||
"Programming Language :: Python :: 3",
|
||||
"License :: OSI Approved :: GNU Lesser General Public License v3 or later (LGPLv3+)",
|
||||
]
|
||||
dependencies = ["mathutils", "shapely", "numpy", "isodate", "dateutil", "lark"]
|
||||
dependencies = ["mathutils", "shapely", "numpy", "isodate", "python-dateutil", "lark"]
|
||||
|
||||
[project.urls]
|
||||
"Homepage" = "http://ifcopenshell.org"
|
||||
|
||||
+79
-36
@@ -16,6 +16,7 @@
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import pytest
|
||||
import test.bootstrap
|
||||
import ifcopenshell.api
|
||||
import ifcopenshell.util.classification
|
||||
@@ -23,85 +24,127 @@ import ifcopenshell.util.classification
|
||||
|
||||
class TestAddReference(test.bootstrap.IFC4):
|
||||
def test_adding_a_reference(self):
|
||||
is_ifc2x3 = self.file.schema == "IFC2X3"
|
||||
|
||||
ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcProject")
|
||||
element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall")
|
||||
element2 = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall")
|
||||
result = ifcopenshell.api.run("classification.add_classification", self.file, classification="Name")
|
||||
ifcopenshell.api.run(
|
||||
"classification.add_reference",
|
||||
self.file,
|
||||
product=element,
|
||||
products=[element, element2],
|
||||
identification="X",
|
||||
name="Foobar",
|
||||
classification=result,
|
||||
)
|
||||
references = list(ifcopenshell.util.classification.get_references(element))
|
||||
assert len(references) == 1
|
||||
assert references[0].Identification == "X"
|
||||
assert getattr(references[0], "ItemReference" if is_ifc2x3 else "Identification") == "X"
|
||||
assert references[0].Name == "Foobar"
|
||||
assert references[0].ReferencedSource == self.file.by_type("IfcClassification")[0]
|
||||
|
||||
element2 = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall")
|
||||
ifcopenshell.api.run(
|
||||
"classification.add_reference",
|
||||
self.file,
|
||||
product=element2,
|
||||
identification="X",
|
||||
name="Foobar",
|
||||
classification=result,
|
||||
references2 = list(ifcopenshell.util.classification.get_references(element))
|
||||
assert len(references2) == 1
|
||||
assert getattr(references2[0], "ItemReference" if is_ifc2x3 else "Identification") == "X"
|
||||
assert references2[0].Name == "Foobar"
|
||||
assert references2[0] == references[0]
|
||||
|
||||
rel = next(
|
||||
rel
|
||||
for rel in self.file.by_type("IfcRelAssociatesClassification")
|
||||
if rel.RelatingClassification == references[0]
|
||||
)
|
||||
assert list(ifcopenshell.util.classification.get_references(element2))[0].Identification == "X"
|
||||
assert list(ifcopenshell.util.classification.get_references(element2))[0].Name == "Foobar"
|
||||
assert list(ifcopenshell.util.classification.get_references(element2))[0] == references[0]
|
||||
assert len(rel.RelatedObjects) == 2
|
||||
|
||||
def test_adding_a_library_based_reference(self):
|
||||
is_ifc2x3 = self.file.schema == "IFC2X3"
|
||||
|
||||
library = ifcopenshell.file()
|
||||
classification = library.createIfcClassification(Name="Name")
|
||||
reference = library.createIfcClassificationReference(Identification="1", ReferencedSource=classification)
|
||||
|
||||
ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcProject")
|
||||
element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall")
|
||||
element2 = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall")
|
||||
result = ifcopenshell.api.run("classification.add_classification", self.file, classification=classification)
|
||||
ifcopenshell.api.run(
|
||||
"classification.add_reference",
|
||||
self.file,
|
||||
product=element,
|
||||
products=[element, element2],
|
||||
reference=reference,
|
||||
classification=result,
|
||||
)
|
||||
references = list(ifcopenshell.util.classification.get_references(element))
|
||||
assert len(references) == 1
|
||||
assert references[0].Identification == "1"
|
||||
assert getattr(references[0], "ItemReference" if is_ifc2x3 else "Identification") == "1"
|
||||
assert references[0].ReferencedSource == self.file.by_type("IfcClassification")[0]
|
||||
|
||||
def test_adding_a_reference_to_a_resource(self):
|
||||
references2 = list(ifcopenshell.util.classification.get_references(element2))
|
||||
assert len(references2) == 1
|
||||
assert getattr(references2[0], "ItemReference" if is_ifc2x3 else "Identification") == "1"
|
||||
assert references2[0].ReferencedSource == self.file.by_type("IfcClassification")[0]
|
||||
assert references[0] == references2[0]
|
||||
|
||||
rel = next(
|
||||
rel
|
||||
for rel in self.file.by_type("IfcRelAssociatesClassification")
|
||||
if rel.RelatingClassification == references[0]
|
||||
)
|
||||
assert len(rel.RelatedObjects) == 2
|
||||
|
||||
def test_adding_a_reference_to_a_resource_and_to_a_root(self):
|
||||
ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcProject")
|
||||
element = self.file.createIfcMaterial()
|
||||
element2 = self.file.createIfcCostValue()
|
||||
element3 = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall")
|
||||
result = ifcopenshell.api.run("classification.add_classification", self.file, classification="Name")
|
||||
ifcopenshell.api.run(
|
||||
"classification.add_reference",
|
||||
self.file,
|
||||
product=element,
|
||||
identification="X",
|
||||
name="Foobar",
|
||||
classification=result,
|
||||
)
|
||||
|
||||
if self.file.schema == "IFC2X3":
|
||||
with pytest.raises(TypeError):
|
||||
ifcopenshell.api.run(
|
||||
"classification.add_reference",
|
||||
self.file,
|
||||
products=[element, element2, element3],
|
||||
identification="X",
|
||||
name="Foobar",
|
||||
classification=result,
|
||||
)
|
||||
return
|
||||
else:
|
||||
ifcopenshell.api.run(
|
||||
"classification.add_reference",
|
||||
self.file,
|
||||
products=[element, element2, element3],
|
||||
identification="X",
|
||||
name="Foobar",
|
||||
classification=result,
|
||||
)
|
||||
|
||||
references = list(ifcopenshell.util.classification.get_references(element))
|
||||
assert len(references) == 1
|
||||
assert references[0].Identification == "X"
|
||||
assert references[0].Name == "Foobar"
|
||||
assert references[0].ReferencedSource == self.file.by_type("IfcClassification")[0]
|
||||
|
||||
element2 = self.file.createIfcCostValue()
|
||||
ifcopenshell.api.run(
|
||||
"classification.add_reference",
|
||||
self.file,
|
||||
product=element2,
|
||||
identification="X",
|
||||
name="Foobar",
|
||||
classification=result,
|
||||
)
|
||||
assert list(ifcopenshell.util.classification.get_references(element2))[0].Identification == "X"
|
||||
assert list(ifcopenshell.util.classification.get_references(element2))[0].Name == "Foobar"
|
||||
assert list(ifcopenshell.util.classification.get_references(element2))[0] == references[0]
|
||||
references2 = list(ifcopenshell.util.classification.get_references(element2))
|
||||
assert references2[0].Identification == "X"
|
||||
assert references2[0].Name == "Foobar"
|
||||
assert references2[0] == references[0]
|
||||
|
||||
references3 = list(ifcopenshell.util.classification.get_references(element3))
|
||||
assert references3[0].Identification == "X"
|
||||
assert references3[0].Name == "Foobar"
|
||||
assert references3[0] == references[0]
|
||||
|
||||
assert len(self.file.by_type("IfcExternalReferenceRelationship")[0].RelatedResourceObjects) == 2
|
||||
rel = next(
|
||||
rel
|
||||
for rel in self.file.by_type("IfcRelAssociatesClassification")
|
||||
if rel.RelatingClassification == references[0]
|
||||
)
|
||||
assert len(rel.RelatedObjects) == 1
|
||||
|
||||
|
||||
class TestAddReferenceIFC2X3(test.bootstrap.IFC2X3, TestAddReference):
|
||||
pass
|
||||
@@ -34,7 +34,7 @@ class TestRemoveClassification(test.bootstrap.IFC4):
|
||||
ifcopenshell.api.run(
|
||||
"classification.add_reference",
|
||||
self.file,
|
||||
product=element,
|
||||
products=[element],
|
||||
identification="X",
|
||||
name="Foobar",
|
||||
classification=result,
|
||||
@@ -51,7 +51,7 @@ class TestRemoveClassification(test.bootstrap.IFC4):
|
||||
ifcopenshell.api.run(
|
||||
"classification.add_reference",
|
||||
self.file,
|
||||
product=element,
|
||||
products=[element],
|
||||
identification="X",
|
||||
name="Foobar",
|
||||
classification=result,
|
||||
|
||||
+47
-24
@@ -16,6 +16,7 @@
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import pytest
|
||||
import test.bootstrap
|
||||
import ifcopenshell.api
|
||||
import ifcopenshell.util.classification
|
||||
@@ -25,58 +26,80 @@ class TestRemoveReference(test.bootstrap.IFC4):
|
||||
def test_removing_a_reference(self):
|
||||
ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcProject")
|
||||
element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall")
|
||||
element2 = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall")
|
||||
result = ifcopenshell.api.run("classification.add_classification", self.file, classification="Name")
|
||||
reference = ifcopenshell.api.run(
|
||||
"classification.add_reference",
|
||||
self.file,
|
||||
product=element,
|
||||
products=[element, element2],
|
||||
identification="X",
|
||||
name="Foobar",
|
||||
classification=result,
|
||||
)
|
||||
ifcopenshell.api.run("classification.remove_reference", self.file, product=element, reference=reference)
|
||||
ifcopenshell.api.run(
|
||||
"classification.remove_reference", self.file, products=[element, element2], reference=reference
|
||||
)
|
||||
assert len(ifcopenshell.util.classification.get_references(element)) == 0
|
||||
assert len(ifcopenshell.util.classification.get_references(element2)) == 0
|
||||
assert len(self.file.by_type("IfcClassificationReference")) == 0
|
||||
|
||||
def test_removing_a_reference_from_a_resource(self):
|
||||
def test_removing_a_reference_from_a_resource_and_from_a_root(self):
|
||||
ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcProject")
|
||||
element = self.file.createIfcMaterial()
|
||||
element2 = self.file.createIfcCostValue()
|
||||
element3 = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall")
|
||||
result = ifcopenshell.api.run("classification.add_classification", self.file, classification="Name")
|
||||
reference = ifcopenshell.api.run(
|
||||
"classification.add_reference",
|
||||
self.file,
|
||||
product=element,
|
||||
identification="X",
|
||||
name="Foobar",
|
||||
classification=result,
|
||||
if self.file.schema == "IFC2X3":
|
||||
with pytest.raises(TypeError):
|
||||
reference = ifcopenshell.api.run(
|
||||
"classification.add_reference",
|
||||
self.file,
|
||||
products=[element, element2, element3],
|
||||
identification="X",
|
||||
name="Foobar",
|
||||
classification=result,
|
||||
)
|
||||
return
|
||||
else:
|
||||
reference = ifcopenshell.api.run(
|
||||
"classification.add_reference",
|
||||
self.file,
|
||||
products=[element, element2, element3],
|
||||
identification="X",
|
||||
name="Foobar",
|
||||
classification=result,
|
||||
)
|
||||
|
||||
ifcopenshell.api.run(
|
||||
"classification.remove_reference", self.file, products=[element, element2, element3], reference=reference
|
||||
)
|
||||
ifcopenshell.api.run("classification.remove_reference", self.file, product=element, reference=reference)
|
||||
assert len(ifcopenshell.util.classification.get_references(element)) == 0
|
||||
assert len(ifcopenshell.util.classification.get_references(element2)) == 0
|
||||
assert len(ifcopenshell.util.classification.get_references(element3)) == 0
|
||||
assert len(self.file.by_type("IfcClassificationReference")) == 0
|
||||
|
||||
def test_retaining_the_reference_if_still_in_use(self):
|
||||
ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcProject")
|
||||
element = self.file.createIfcMaterial()
|
||||
element2 = self.file.createIfcMaterial()
|
||||
element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall")
|
||||
element2 = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall")
|
||||
element3 = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall")
|
||||
result = ifcopenshell.api.run("classification.add_classification", self.file, classification="Name")
|
||||
reference = ifcopenshell.api.run(
|
||||
"classification.add_reference",
|
||||
self.file,
|
||||
product=element,
|
||||
identification="X",
|
||||
name="Foobar",
|
||||
classification=result,
|
||||
)
|
||||
reference2 = ifcopenshell.api.run(
|
||||
"classification.add_reference",
|
||||
self.file,
|
||||
product=element2,
|
||||
products=[element, element2, element3],
|
||||
identification="X",
|
||||
name="Foobar",
|
||||
classification=result,
|
||||
)
|
||||
assert len(self.file.by_type("IfcClassificationReference")) == 1
|
||||
ifcopenshell.api.run("classification.remove_reference", self.file, product=element, reference=reference)
|
||||
ifcopenshell.api.run(
|
||||
"classification.remove_reference", self.file, products=[element, element2], reference=reference
|
||||
)
|
||||
assert len(self.file.by_type("IfcClassificationReference")) == 1
|
||||
ifcopenshell.api.run("classification.remove_reference", self.file, product=element2, reference=reference2)
|
||||
ifcopenshell.api.run("classification.remove_reference", self.file, products=[element3], reference=reference)
|
||||
assert len(self.file.by_type("IfcClassificationReference")) == 0
|
||||
|
||||
|
||||
class TestRemoveReferenceIFC2X3(test.bootstrap.IFC2X3, TestRemoveReference):
|
||||
pass
|
||||
@@ -0,0 +1,64 @@
|
||||
# IfcOpenShell - IFC toolkit and geometry engine
|
||||
# Copyright (C) 2022 Dion Moult <dion@thinkmoult.com>
|
||||
#
|
||||
# This file is part of IfcOpenShell.
|
||||
#
|
||||
# IfcOpenShell is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# IfcOpenShell is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import pytest
|
||||
import test.bootstrap
|
||||
import ifcopenshell.api
|
||||
import ifcopenshell.util.constraint
|
||||
|
||||
|
||||
class TestAssignConstraint(test.bootstrap.IFC4):
|
||||
def test_assign_a_constraint(self):
|
||||
element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall")
|
||||
element2 = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall")
|
||||
constraint = ifcopenshell.api.run("constraint.add_objective", self.file)
|
||||
ifcopenshell.api.run(
|
||||
"constraint.assign_constraint", self.file, products=[element, element2], constraint=constraint
|
||||
)
|
||||
assert ifcopenshell.util.constraint.get_constrained_elements(constraint) == {element, element2}
|
||||
assert len(self.file.by_type("IfcRelAssociatesConstraint")) == 1
|
||||
|
||||
def test_doing_nothing_if_the_constraint_is_already_assigned(self):
|
||||
constraint = ifcopenshell.api.run("constraint.add_objective", self.file)
|
||||
element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall")
|
||||
element2 = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall")
|
||||
ifcopenshell.api.run(
|
||||
"constraint.assign_constraint", self.file, products=[element, element2], constraint=constraint
|
||||
)
|
||||
total_elements = len([e for e in self.file])
|
||||
ifcopenshell.api.run(
|
||||
"constraint.assign_constraint", self.file, products=[element, element2], constraint=constraint
|
||||
)
|
||||
assert len([e for e in self.file]) == total_elements
|
||||
|
||||
def test_that_old_relationships_are_updated_if_they_still_contain_elements(self):
|
||||
constraint = ifcopenshell.api.run("constraint.add_objective", self.file)
|
||||
element1 = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall")
|
||||
ifcopenshell.api.run("constraint.assign_constraint", self.file, products=[element1], constraint=constraint)
|
||||
rel = self.file.by_type("IfcRelAssociatesConstraint")[0]
|
||||
|
||||
element2 = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall")
|
||||
element3 = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall")
|
||||
ifcopenshell.api.run(
|
||||
"constraint.assign_constraint", self.file, products=[element2, element3], constraint=constraint
|
||||
)
|
||||
assert len(rel.RelatedObjects) == 3
|
||||
|
||||
|
||||
class TestAssignConstraintIFC2X3(test.bootstrap.IFC2X3, TestAssignConstraint):
|
||||
pass
|
||||
@@ -0,0 +1,67 @@
|
||||
# IfcOpenShell - IFC toolkit and geometry engine
|
||||
# Copyright (C) 2022 Dion Moult <dion@thinkmoult.com>
|
||||
#
|
||||
# This file is part of IfcOpenShell.
|
||||
#
|
||||
# IfcOpenShell is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# IfcOpenShell is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import pytest
|
||||
import test.bootstrap
|
||||
import ifcopenshell.api
|
||||
import ifcopenshell.util.constraint
|
||||
|
||||
|
||||
class TestUnassignConstraint(test.bootstrap.IFC4):
|
||||
def test_unassigning_a_constraint(self):
|
||||
constraint = ifcopenshell.api.run("constraint.add_objective", self.file)
|
||||
element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall")
|
||||
element2 = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall")
|
||||
ifcopenshell.api.run(
|
||||
"constraint.assign_constraint", self.file, products=[element, element2], constraint=constraint
|
||||
)
|
||||
ifcopenshell.api.run(
|
||||
"constraint.unassign_constraint", self.file, products=[element, element2], constraint=constraint
|
||||
)
|
||||
assert ifcopenshell.util.constraint.get_constrained_elements(element) == set()
|
||||
assert len(self.file.by_type("IfcRelAssociatesConstraint")) == 0
|
||||
|
||||
def test_doing_nothing_if_no_constraint(self):
|
||||
constraint = ifcopenshell.api.run("constraint.add_objective", self.file)
|
||||
element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall")
|
||||
element2 = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall")
|
||||
ifcopenshell.api.run(
|
||||
"constraint.unassign_constraint", self.file, products=[element, element2], constraint=constraint
|
||||
)
|
||||
assert ifcopenshell.util.constraint.get_constrained_elements(element) == set()
|
||||
assert ifcopenshell.util.constraint.get_constrained_elements(element2) == set()
|
||||
|
||||
def test_updating_the_rel_when_a_reference_is_removed_with_multipled_elements(self):
|
||||
constraint = ifcopenshell.api.run("constraint.add_objective", self.file)
|
||||
element1 = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall")
|
||||
element2 = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall")
|
||||
element3 = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall")
|
||||
ifcopenshell.api.run("constraint.assign_constraint", self.file, products=[element1], constraint=constraint)
|
||||
rel = self.file.by_type("IfcRelAssociatesConstraint")[0]
|
||||
|
||||
ifcopenshell.api.run(
|
||||
"constraint.assign_constraint", self.file, products=[element2, element3], constraint=constraint
|
||||
)
|
||||
ifcopenshell.api.run(
|
||||
"constraint.unassign_constraint", self.file, products=[element1, element2], constraint=constraint
|
||||
)
|
||||
assert rel.RelatedObjects == (element3,)
|
||||
|
||||
|
||||
class TestUnassignConstraintIFC2X3(test.bootstrap.IFC2X3, TestUnassignConstraint):
|
||||
pass
|
||||
@@ -18,22 +18,25 @@
|
||||
|
||||
import test.bootstrap
|
||||
import ifcopenshell.api
|
||||
import ifcopenshell.util.element
|
||||
|
||||
|
||||
class TestAssignDocument(test.bootstrap.IFC4):
|
||||
def test_assigning_a_document(self):
|
||||
element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall")
|
||||
reference = ifcopenshell.api.run("document.add_reference", self.file, information=None)
|
||||
ifcopenshell.api.run("document.assign_document", self.file, product=element, document=reference)
|
||||
ifcopenshell.api.run("document.assign_document", self.file, products=[element], document=reference)
|
||||
assert element.HasAssociations[0].RelatingDocument == reference
|
||||
assert ifcopenshell.util.element.get_referenced_elements(reference) == {element}
|
||||
|
||||
def test_assigning_multiple_documents(self):
|
||||
element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall")
|
||||
element2 = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall")
|
||||
reference = ifcopenshell.api.run("document.add_reference", self.file, information=None)
|
||||
ifcopenshell.api.run("document.assign_document", self.file, product=element, document=reference)
|
||||
ifcopenshell.api.run("document.assign_document", self.file, product=element2, document=reference)
|
||||
ifcopenshell.api.run("document.assign_document", self.file, products=[element, element2], document=reference)
|
||||
assert len(self.file.by_type("IfcRelAssociatesDocument")) == 1
|
||||
assert element.HasAssociations[0].RelatingDocument == reference
|
||||
assert element2.HasAssociations[0].RelatingDocument == reference
|
||||
assert element.HasAssociations[0] == element.HasAssociations[0]
|
||||
assert ifcopenshell.util.element.get_referenced_elements(reference) == {element, element2}
|
||||
|
||||
|
||||
class TestAssignDocumentIFC2X3(test.bootstrap.IFC2X3, TestAssignDocument):
|
||||
pass
|
||||
|
||||
@@ -35,7 +35,7 @@ class TestRemoveReference(test.bootstrap.IFC4):
|
||||
wall = self.file.createIfcWall()
|
||||
information = ifcopenshell.api.run("document.add_information", self.file, parent=None)
|
||||
reference = ifcopenshell.api.run("document.add_reference", self.file, information=information)
|
||||
ifcopenshell.api.run("document.assign_document", self.file, product=wall, document=reference)
|
||||
ifcopenshell.api.run("document.assign_document", self.file, products=[wall], document=reference)
|
||||
assert len(self.file.by_type("IfcRelAssociatesDocument")) == 2
|
||||
ifcopenshell.api.run("document.remove_reference", self.file, reference=reference)
|
||||
assert len(self.file.by_type("IfcDocumentReference")) == 0
|
||||
|
||||
@@ -18,23 +18,29 @@
|
||||
|
||||
import test.bootstrap
|
||||
import ifcopenshell.api
|
||||
import ifcopenshell.util.element
|
||||
|
||||
|
||||
class TestUnassignDocument(test.bootstrap.IFC4):
|
||||
def test_unassigning_a_document(self):
|
||||
element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall")
|
||||
reference = ifcopenshell.api.run("document.add_reference", self.file, information=None)
|
||||
ifcopenshell.api.run("document.assign_document", self.file, product=element, document=reference)
|
||||
ifcopenshell.api.run("document.unassign_document", self.file, product=element, document=reference)
|
||||
ifcopenshell.api.run("document.assign_document", self.file, products=[element], document=reference)
|
||||
ifcopenshell.api.run("document.unassign_document", self.file, products=[element], document=reference)
|
||||
assert not element.HasAssociations
|
||||
assert not len(self.file.by_type("IfcRelAssociatesDocument"))
|
||||
|
||||
def test_unassigning_a_document_used_by_multiple_entities(self):
|
||||
element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall")
|
||||
element2 = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall")
|
||||
element3 = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall")
|
||||
reference = ifcopenshell.api.run("document.add_reference", self.file, information=None)
|
||||
ifcopenshell.api.run("document.assign_document", self.file, product=element, document=reference)
|
||||
ifcopenshell.api.run("document.assign_document", self.file, product=element2, document=reference)
|
||||
ifcopenshell.api.run("document.unassign_document", self.file, product=element, document=reference)
|
||||
assert not element.HasAssociations
|
||||
assert element2.HasAssociations[0].RelatingDocument == reference
|
||||
ifcopenshell.api.run(
|
||||
"document.assign_document", self.file, products=[element, element2, element3], document=reference
|
||||
)
|
||||
ifcopenshell.api.run("document.unassign_document", self.file, products=[element, element2], document=reference)
|
||||
assert ifcopenshell.util.element.get_referenced_elements(reference) == {element3}
|
||||
|
||||
|
||||
class TestUnassignDocumentIFC2X3(test.bootstrap.IFC2X3, TestUnassignDocument):
|
||||
pass
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -18,12 +18,20 @@
|
||||
|
||||
import test.bootstrap
|
||||
import ifcopenshell.api
|
||||
import ifcopenshell.util.element
|
||||
|
||||
|
||||
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.unassign_reference", self.file, product=product, reference=reference)
|
||||
products = [self.file.createIfcWall() for i in range(3)]
|
||||
ifcopenshell.api.run("library.assign_reference", self.file, products=products, reference=reference)
|
||||
ifcopenshell.api.run("library.unassign_reference", self.file, products=products[:1], reference=reference)
|
||||
assert ifcopenshell.util.element.get_referenced_elements(reference) == set(products[1:])
|
||||
|
||||
ifcopenshell.api.run("library.unassign_reference", self.file, products=products[1:], reference=reference)
|
||||
assert ifcopenshell.util.element.get_referenced_elements(reference) == set()
|
||||
assert len(self.file.by_type("IfcRelAssociatesLibrary")) == 0
|
||||
|
||||
class TestUnassignReferenceIFC2X3(test.bootstrap.IFC2X3, TestUnassignReference):
|
||||
pass
|
||||
|
||||
@@ -26,28 +26,42 @@ class TestDereferenceStructure(test.bootstrap.IFC4):
|
||||
def test_removing_a_container(self):
|
||||
element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcBuilding")
|
||||
subelement = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall")
|
||||
ifcopenshell.api.run("spatial.reference_structure", self.file, product=subelement, relating_structure=element)
|
||||
ifcopenshell.api.run("spatial.dereference_structure", self.file, product=subelement, relating_structure=element)
|
||||
subelement2 = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall")
|
||||
ifcopenshell.api.run(
|
||||
"spatial.reference_structure", self.file, products=[subelement, subelement2], relating_structure=element
|
||||
)
|
||||
ifcopenshell.api.run(
|
||||
"spatial.dereference_structure", self.file, products=[subelement, subelement2], relating_structure=element
|
||||
)
|
||||
assert ifcopenshell.util.element.get_referenced_structures(subelement) == []
|
||||
assert len(self.file.by_type("IfcRelReferencedInSpatialStructure")) == 0
|
||||
|
||||
def test_doing_nothing_if_no_container(self):
|
||||
element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcBuilding")
|
||||
subelement = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall")
|
||||
ifcopenshell.api.run("spatial.dereference_structure", self.file, product=subelement, relating_structure=element)
|
||||
subelement2 = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall")
|
||||
ifcopenshell.api.run(
|
||||
"spatial.dereference_structure", self.file, products=[subelement, subelement2], relating_structure=element
|
||||
)
|
||||
assert ifcopenshell.util.element.get_referenced_structures(subelement) == []
|
||||
assert ifcopenshell.util.element.get_referenced_structures(subelement2) == []
|
||||
|
||||
def test_updating_the_rel_when_a_reference_is_removed_with_multipled_elements(self):
|
||||
element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcBuilding")
|
||||
subelement1 = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall")
|
||||
subelement2 = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall")
|
||||
ifcopenshell.api.run("spatial.reference_structure", self.file, product=subelement1, relating_structure=element)
|
||||
ifcopenshell.api.run("spatial.reference_structure", self.file, product=subelement2, relating_structure=element)
|
||||
ifcopenshell.api.run("spatial.dereference_structure", self.file, product=subelement1, relating_structure=element)
|
||||
assert self.file.by_type("IfcRelReferencedInSpatialStructure")[0].RelatedElements == (subelement2,)
|
||||
subelement3 = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall")
|
||||
ifcopenshell.api.run(
|
||||
"spatial.reference_structure", self.file, products=[subelement1], relating_structure=element
|
||||
)
|
||||
ifcopenshell.api.run(
|
||||
"spatial.reference_structure", self.file, products=[subelement2, subelement3], relating_structure=element
|
||||
)
|
||||
ifcopenshell.api.run(
|
||||
"spatial.dereference_structure", self.file, products=[subelement1, subelement2], relating_structure=element
|
||||
)
|
||||
assert element.ReferencesElements[0].RelatedElements == (subelement3,)
|
||||
|
||||
def test_deleting_the_rel_when_a_container_is_removed_with_no_elements(self):
|
||||
element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcBuilding")
|
||||
subelement = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall")
|
||||
ifcopenshell.api.run("spatial.reference_structure", self.file, product=subelement, relating_structure=element)
|
||||
ifcopenshell.api.run("spatial.dereference_structure", self.file, product=subelement, relating_structure=element)
|
||||
assert len(self.file.by_type("IfcRelReferencedInSpatialStructure")) == 0
|
||||
|
||||
class TestDereferenceStructureIFC2X3(test.bootstrap.IFC2X3, TestDereferenceStructure):
|
||||
pass
|
||||
|
||||
@@ -26,25 +26,39 @@ class TestReferenceStructure(test.bootstrap.IFC4):
|
||||
def test_referencing_a_structure(self):
|
||||
element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcBuilding")
|
||||
subelement = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall")
|
||||
rel = ifcopenshell.api.run(
|
||||
"spatial.reference_structure", self.file, product=subelement, relating_structure=element
|
||||
subelement2 = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall")
|
||||
ifcopenshell.api.run(
|
||||
"spatial.reference_structure", self.file, products=[subelement, subelement2], relating_structure=element
|
||||
)
|
||||
assert ifcopenshell.util.element.get_referenced_structures(subelement) == [element]
|
||||
assert rel.is_a("IfcRelReferencedInSpatialStructure")
|
||||
assert ifcopenshell.util.element.get_structure_referenced_elements(element) == {subelement, subelement2}
|
||||
|
||||
def test_doing_nothing_if_the_structure_is_already_referenced(self):
|
||||
element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcBuilding")
|
||||
subelement = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall")
|
||||
ifcopenshell.api.run("spatial.reference_structure", self.file, product=subelement, relating_structure=element)
|
||||
subelement2 = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall")
|
||||
ifcopenshell.api.run(
|
||||
"spatial.reference_structure", self.file, products=[subelement, subelement2], relating_structure=element
|
||||
)
|
||||
total_elements = len([e for e in self.file])
|
||||
ifcopenshell.api.run("spatial.reference_structure", self.file, product=subelement, relating_structure=element)
|
||||
ifcopenshell.api.run(
|
||||
"spatial.reference_structure", self.file, products=[subelement, subelement2], relating_structure=element
|
||||
)
|
||||
assert len([e for e in self.file]) == total_elements
|
||||
|
||||
def test_that_old_relationships_are_updated_if_they_still_contain_elements(self):
|
||||
element1 = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcBuilding")
|
||||
element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcBuilding")
|
||||
subelement1 = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall")
|
||||
ifcopenshell.api.run(
|
||||
"spatial.reference_structure", self.file, products=[subelement1], relating_structure=element
|
||||
)
|
||||
subelement2 = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall")
|
||||
ifcopenshell.api.run("spatial.reference_structure", self.file, product=subelement1, relating_structure=element1)
|
||||
ifcopenshell.api.run("spatial.reference_structure", self.file, product=subelement2, relating_structure=element1)
|
||||
subelement3 = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall")
|
||||
ifcopenshell.api.run(
|
||||
"spatial.reference_structure", self.file, products=[subelement2, subelement3], relating_structure=element
|
||||
)
|
||||
rel = subelement1.ReferencedInStructures[0]
|
||||
assert len(rel.RelatedElements) == 2
|
||||
assert len(rel.RelatedElements) == 3
|
||||
|
||||
|
||||
class TestReferenceStructureIFC2X3(test.bootstrap.IFC2X3, TestReferenceStructure):
|
||||
pass
|
||||
|
||||
@@ -18,6 +18,8 @@
|
||||
|
||||
import test.bootstrap
|
||||
import ifcopenshell.api
|
||||
import ifcopenshell.util.classification
|
||||
import ifcopenshell.util.constraint
|
||||
import ifcopenshell.util.element
|
||||
import ifcopenshell.util.system
|
||||
from datetime import datetime
|
||||
@@ -186,3 +188,126 @@ class TestTemporarySupportForDeprecatedAPIArguments(test.bootstrap.IFC4):
|
||||
assert len(self.file.by_type("IfcRelAssociatesMaterial")) == 0
|
||||
assert len(self.file.by_type("IfcWall")) == 1
|
||||
assert len(self.file.by_type("IfcMaterial")) == 1
|
||||
|
||||
@deprecation_check
|
||||
def test_adding_a_reference(self):
|
||||
ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcProject")
|
||||
element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall")
|
||||
result = ifcopenshell.api.run("classification.add_classification", self.file, classification="Name")
|
||||
ifcopenshell.api.run(
|
||||
"classification.add_reference",
|
||||
self.file,
|
||||
product=element,
|
||||
identification="X",
|
||||
name="Foobar",
|
||||
classification=result,
|
||||
)
|
||||
references = list(ifcopenshell.util.classification.get_references(element))
|
||||
assert len(references) == 1
|
||||
assert references[0].Identification == "X"
|
||||
assert references[0].Name == "Foobar"
|
||||
assert references[0].ReferencedSource == self.file.by_type("IfcClassification")[0]
|
||||
|
||||
element2 = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall")
|
||||
ifcopenshell.api.run(
|
||||
"classification.add_reference",
|
||||
self.file,
|
||||
product=element2,
|
||||
identification="X",
|
||||
name="Foobar",
|
||||
classification=result,
|
||||
)
|
||||
assert list(ifcopenshell.util.classification.get_references(element2))[0].Identification == "X"
|
||||
assert list(ifcopenshell.util.classification.get_references(element2))[0].Name == "Foobar"
|
||||
assert list(ifcopenshell.util.classification.get_references(element2))[0] == references[0]
|
||||
|
||||
@deprecation_check
|
||||
def test_removing_a_reference(self):
|
||||
ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcProject")
|
||||
element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall")
|
||||
result = ifcopenshell.api.run("classification.add_classification", self.file, classification="Name")
|
||||
reference = ifcopenshell.api.run(
|
||||
"classification.add_reference",
|
||||
self.file,
|
||||
products=[element],
|
||||
identification="X",
|
||||
name="Foobar",
|
||||
classification=result,
|
||||
)
|
||||
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))
|
||||
|
||||
@deprecation_check
|
||||
def test_unassigning_a_reference(self):
|
||||
reference = self.file.createIfcLibraryReference()
|
||||
product = self.file.createIfcWall()
|
||||
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
|
||||
|
||||
@deprecation_check
|
||||
def test_assigning_a_document(self):
|
||||
element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall")
|
||||
reference = ifcopenshell.api.run("document.add_reference", self.file, information=None)
|
||||
ifcopenshell.api.run("document.assign_document", self.file, product=element, document=reference)
|
||||
assert element.HasAssociations[0].RelatingDocument == reference
|
||||
|
||||
@deprecation_check
|
||||
def test_unassigning_a_document(self):
|
||||
element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall")
|
||||
reference = ifcopenshell.api.run("document.add_reference", self.file, information=None)
|
||||
ifcopenshell.api.run("document.assign_document", self.file, products=[element], document=reference)
|
||||
ifcopenshell.api.run("document.unassign_document", self.file, product=element, document=reference)
|
||||
assert not element.HasAssociations
|
||||
assert not len(self.file.by_type("IfcRelAssociatesDocument"))
|
||||
|
||||
@deprecation_check
|
||||
def test_referencing_a_structure(self):
|
||||
element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcBuilding")
|
||||
subelement = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall")
|
||||
rel = ifcopenshell.api.run(
|
||||
"spatial.reference_structure", self.file, product=subelement, relating_structure=element
|
||||
)
|
||||
assert ifcopenshell.util.element.get_referenced_structures(subelement) == [element]
|
||||
assert rel.is_a("IfcRelReferencedInSpatialStructure")
|
||||
|
||||
@deprecation_check
|
||||
def test_removing_a_container(self):
|
||||
element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcBuilding")
|
||||
subelement = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall")
|
||||
ifcopenshell.api.run(
|
||||
"spatial.reference_structure", self.file, products=[subelement], relating_structure=element
|
||||
)
|
||||
ifcopenshell.api.run("spatial.dereference_structure", self.file, product=subelement, relating_structure=element)
|
||||
assert ifcopenshell.util.element.get_referenced_structures(subelement) == []
|
||||
|
||||
@deprecation_check
|
||||
def test_assign_a_constraint(self):
|
||||
element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall")
|
||||
constraint = ifcopenshell.api.run("constraint.add_objective", self.file)
|
||||
ifcopenshell.api.run("constraint.assign_constraint", self.file, product=element, constraint=constraint)
|
||||
assert ifcopenshell.util.constraint.get_constrained_elements(constraint) == {element}
|
||||
|
||||
@deprecation_check
|
||||
def test_unassigning_a_constraint(self):
|
||||
constraint = ifcopenshell.api.run("constraint.add_objective", self.file)
|
||||
element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall")
|
||||
ifcopenshell.api.run(
|
||||
"constraint.assign_constraint", self.file, product=element, constraint=constraint
|
||||
)
|
||||
ifcopenshell.api.run(
|
||||
"constraint.unassign_constraint", self.file, product=element, constraint=constraint
|
||||
)
|
||||
assert ifcopenshell.util.constraint.get_constrained_elements(element) == set()
|
||||
assert len(self.file.by_type("IfcRelAssociatesConstraint")) == 0
|
||||
|
||||
@@ -34,14 +34,14 @@ class TestGetReferences(test.bootstrap.IFC4):
|
||||
ifcopenshell.api.run(
|
||||
"classification.add_reference",
|
||||
self.file,
|
||||
product=element,
|
||||
products=[element],
|
||||
reference=reference1,
|
||||
classification=classification,
|
||||
)
|
||||
ifcopenshell.api.run(
|
||||
"classification.add_reference",
|
||||
self.file,
|
||||
product=element,
|
||||
products=[element],
|
||||
reference=reference2,
|
||||
classification=classification,
|
||||
)
|
||||
@@ -54,7 +54,7 @@ class TestGetReferences(test.bootstrap.IFC4):
|
||||
ifcopenshell.api.run(
|
||||
"classification.add_reference",
|
||||
self.file,
|
||||
product=element,
|
||||
products=[element],
|
||||
identification="X",
|
||||
name="Foobar",
|
||||
classification=result,
|
||||
@@ -74,14 +74,14 @@ class TestGetReferences(test.bootstrap.IFC4):
|
||||
ifcopenshell.api.run(
|
||||
"classification.add_reference",
|
||||
self.file,
|
||||
product=element,
|
||||
products=[element],
|
||||
reference=reference1,
|
||||
classification=classification,
|
||||
)
|
||||
ifcopenshell.api.run(
|
||||
"classification.add_reference",
|
||||
self.file,
|
||||
product=element_type,
|
||||
products=[element_type],
|
||||
reference=reference2,
|
||||
classification=classification,
|
||||
)
|
||||
@@ -103,14 +103,14 @@ class TestGetReferences(test.bootstrap.IFC4):
|
||||
ifcopenshell.api.run(
|
||||
"classification.add_reference",
|
||||
self.file,
|
||||
product=element,
|
||||
products=[element],
|
||||
reference=reference1,
|
||||
classification=classification,
|
||||
)
|
||||
ifcopenshell.api.run(
|
||||
"classification.add_reference",
|
||||
self.file,
|
||||
product=element_type,
|
||||
products=[element_type],
|
||||
reference=reference2,
|
||||
classification=classification,
|
||||
)
|
||||
|
||||
@@ -291,6 +291,16 @@ class TestGetPredefinedTypeIFC4(test.bootstrap.IFC4):
|
||||
element_type.ProcessType = "FOOBAR"
|
||||
assert subject.get_predefined_type(element) == "FOOBAR"
|
||||
|
||||
def test_getting_an_element_type_predefined_type(self):
|
||||
element_type = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWallType")
|
||||
element_type.PredefinedType = "PARTITIONING"
|
||||
assert subject.get_predefined_type(element_type) == "PARTITIONING"
|
||||
|
||||
def test_getting_an_element_type_null_predefined_type(self):
|
||||
element_type = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWallType")
|
||||
element_type.PredefinedType = "NOTDEFINED"
|
||||
assert subject.get_predefined_type(element_type) == "NOTDEFINED"
|
||||
|
||||
|
||||
class TestGetTypeIFC4(test.bootstrap.IFC4):
|
||||
def test_getting_the_type_of_a_product(self):
|
||||
@@ -352,12 +362,16 @@ class TestGetMaterial(test.bootstrap.IFC4):
|
||||
|
||||
def test_getting_a_material_layer_set_of_a_product(self):
|
||||
element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall")
|
||||
rel = ifcopenshell.api.run("material.assign_material", self.file, products=[element], type="IfcMaterialLayerSet")
|
||||
rel = ifcopenshell.api.run(
|
||||
"material.assign_material", self.file, products=[element], type="IfcMaterialLayerSet"
|
||||
)
|
||||
assert subject.get_material(element) == rel.RelatingMaterial
|
||||
|
||||
def test_getting_a_material_profile_set_of_a_product(self):
|
||||
element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall")
|
||||
rel = ifcopenshell.api.run("material.assign_material", self.file, products=[element], type="IfcMaterialProfileSet")
|
||||
rel = ifcopenshell.api.run(
|
||||
"material.assign_material", self.file, products=[element], type="IfcMaterialProfileSet"
|
||||
)
|
||||
assert subject.get_material(element) == rel.RelatingMaterial
|
||||
|
||||
def test_getting_a_material_layer_set_usage_of_a_product(self):
|
||||
@@ -512,7 +526,9 @@ class TestGetElementsByMaterial(test.bootstrap.IFC4):
|
||||
material_set = ifcopenshell.api.run("material.add_material_set", self.file, set_type="IfcMaterialProfileSet")
|
||||
ifcopenshell.api.run("material.add_profile", self.file, profile_set=material_set, material=material)
|
||||
ifcopenshell.api.run("material.assign_material", self.file, products=[element_type], material=material_set)
|
||||
ifcopenshell.api.run("material.assign_material", self.file, products=[element], type="IfcMaterialProfileSetUsage")
|
||||
ifcopenshell.api.run(
|
||||
"material.assign_material", self.file, products=[element], type="IfcMaterialProfileSetUsage"
|
||||
)
|
||||
usage = self.file.by_type("IfcMaterialProfileSetUsage")[0]
|
||||
assert subject.get_elements_by_material(self.file, material) == {element, element_type}
|
||||
assert subject.get_elements_by_material(self.file, material_set) == {element, element_type}
|
||||
@@ -703,13 +719,33 @@ class TestGetReferencedStructures(test.bootstrap.IFC4):
|
||||
element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall")
|
||||
assert subject.get_referenced_structures(element) == []
|
||||
building = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcBuilding")
|
||||
ifcopenshell.api.run("spatial.reference_structure", self.file, product=element, relating_structure=building)
|
||||
ifcopenshell.api.run("spatial.reference_structure", self.file, products=[element], relating_structure=building)
|
||||
assert subject.get_referenced_structures(element) == [building]
|
||||
building2 = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcBuilding")
|
||||
ifcopenshell.api.run("spatial.reference_structure", self.file, product=element, relating_structure=building2)
|
||||
ifcopenshell.api.run("spatial.reference_structure", self.file, products=[element], relating_structure=building2)
|
||||
assert subject.get_referenced_structures(element) == [building, building2]
|
||||
|
||||
|
||||
class TestGetReferencedStructuresIFC2X3(test.bootstrap.IFC2X3, TestGetReferencedStructures):
|
||||
pass
|
||||
|
||||
|
||||
class TestGetStructureReferencedElements(test.bootstrap.IFC4):
|
||||
def test_getting_references_of_an_element(self):
|
||||
building = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcBuilding")
|
||||
assert subject.get_structure_referenced_elements(building) == set()
|
||||
element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall")
|
||||
ifcopenshell.api.run("spatial.reference_structure", self.file, products=[element], relating_structure=building)
|
||||
assert subject.get_structure_referenced_elements(building) == {element}
|
||||
element2 = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall")
|
||||
ifcopenshell.api.run("spatial.reference_structure", self.file, products=[element2], relating_structure=building)
|
||||
assert subject.get_structure_referenced_elements(building) == {element, element2}
|
||||
|
||||
|
||||
class TestGetStructureReferencedElementsIFC2X3(test.bootstrap.IFC2X3, TestGetStructureReferencedElements):
|
||||
pass
|
||||
|
||||
|
||||
class TestGetDecompositionIFC4(test.bootstrap.IFC4):
|
||||
def test_getting_decomposed_subelements_of_an_element(self):
|
||||
element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcElementAssembly")
|
||||
@@ -769,6 +805,50 @@ class TestGetNestIFC2X3(test.bootstrap.IFC2X3, TestGetNestIFC4):
|
||||
pass
|
||||
|
||||
|
||||
class TestGetReferencedElements(test.bootstrap.IFC4):
|
||||
# TODO: test other references:
|
||||
# IfcExternallyDefinedHatchStyle
|
||||
# IfcExternallyDefinedSurfaceStyle
|
||||
# IfcExternallyDefinedTextFont
|
||||
def test_get_elements_referenced_by_classification_reference(self):
|
||||
ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcProject")
|
||||
elements = [ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall")]
|
||||
if self.file.schema != "IFC2X3":
|
||||
elements.append(self.file.create_entity("IfcCostValue"))
|
||||
result = ifcopenshell.api.run("classification.add_classification", self.file, classification="Name")
|
||||
reference = ifcopenshell.api.run(
|
||||
"classification.add_reference",
|
||||
self.file,
|
||||
products=elements,
|
||||
identification="X",
|
||||
name="Foobar",
|
||||
classification=result,
|
||||
)
|
||||
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)
|
||||
|
||||
def test_get_elements_referenced_by_document_reference(self):
|
||||
reference = ifcopenshell.api.run("document.add_reference", self.file, information=None)
|
||||
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("document.assign_document", self.file, document=reference, products=elements)
|
||||
assert subject.get_referenced_elements(reference) == set(elements)
|
||||
|
||||
|
||||
class TestGetReferencedElementsIFC2X3(test.bootstrap.IFC2X3, TestGetReferencedElements):
|
||||
pass
|
||||
|
||||
|
||||
class TestReplaceAttributeIFC4(test.bootstrap.IFC4):
|
||||
def test_replacing_an_elements_attribute(self):
|
||||
element = self.file.createIfcWall("foo")
|
||||
|
||||
@@ -225,7 +225,7 @@ class TestFilterElements(test.bootstrap.IFC4):
|
||||
ifcopenshell.api.run(
|
||||
"classification.add_reference",
|
||||
self.file,
|
||||
product=element,
|
||||
products=[element],
|
||||
identification="X",
|
||||
name="Foobar",
|
||||
classification=result,
|
||||
|
||||
Reference in New Issue
Block a user