mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-09 17:31:45 +00:00
Generate functions for all API usecases for better static code features. See #2693.
This commit is contained in:
@@ -15,3 +15,10 @@
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from .add_classification import add_classification
|
||||
from .add_reference import add_reference
|
||||
from .edit_classification import edit_classification
|
||||
from .edit_reference import edit_reference
|
||||
from .remove_classification import remove_classification
|
||||
from .remove_reference import remove_reference
|
||||
|
||||
@@ -22,67 +22,72 @@ import ifcopenshell.util.date
|
||||
from typing import Union
|
||||
|
||||
|
||||
def add_classification(
|
||||
file: ifcopenshell.file, classification: Union[str, ifcopenshell.entity_instance]
|
||||
) -> ifcopenshell.entity_instance:
|
||||
"""Adds a new classification system to the project
|
||||
|
||||
External classification systems such as Uniclass or Omniclass are
|
||||
ways of categorising elements in the AEC industry, typically
|
||||
standardised or nominated by governments or companies. A system
|
||||
typically contains a series of hierarchical reference codes and labels
|
||||
like Pr_12_23_34.
|
||||
|
||||
Classifications may be applied to many things, not just physical
|
||||
elements, such as doors and windows, spatial elements, tasks, cost
|
||||
items, or even resources.
|
||||
|
||||
Prior to assigning classificaion references, you need to add the name
|
||||
and metadata of the classification system that you will use in your
|
||||
project. Classification systems may be revised over time, so this
|
||||
metadata includes the edition date.
|
||||
|
||||
Common classification systems are provided as an IFC library which may
|
||||
be downloaded from https://github.com/Moult/IfcClassification for your
|
||||
convenience. It is advised to use these to ensure that the
|
||||
classification metadata is standardised.
|
||||
|
||||
Adding a classification system will not add the entire hierarchy of
|
||||
references available in the classification. References need to be added
|
||||
separately. Typically, you'd only add the references that you use in
|
||||
your project, see ifcopenshell.api.classification.add_reference for more
|
||||
information.
|
||||
|
||||
:param classification: If a string is provided, it is assumed to be the
|
||||
name of your classification system. This is necessary if you are
|
||||
creating your own custom classification system. Alternatively, you
|
||||
may provide an entity_instance of an IfcClassification from an IFC
|
||||
classification library. The latter approach is preferred if you are
|
||||
using a commonly known system such as Uniclass, as this will ensure
|
||||
all metadata is added correctly.
|
||||
:type classification: str,ifcopenshell.entity_instance
|
||||
:return: The added IfcClassification element
|
||||
:rtype: ifcopenshell.entity_instance
|
||||
|
||||
Example:
|
||||
|
||||
.. code:: python
|
||||
|
||||
# Option 1: adding a custom clasification from scratch
|
||||
ifcopenshell.api.run("classification.add_classification", model,
|
||||
classification="MyCustomClassification")
|
||||
|
||||
# Option 2: adding a popular classification from a library
|
||||
library = ifcopenshell.open("/path/to/Uniclass.ifc")
|
||||
classification = library.by_type("IfcClassification")[0]
|
||||
ifcopenshell.api.run("classification.add_classification", model,
|
||||
classification=classification)
|
||||
"""
|
||||
usecase = Usecase()
|
||||
usecase.file = file
|
||||
usecase.settings = {
|
||||
"classification": classification,
|
||||
}
|
||||
return usecase.execute()
|
||||
|
||||
|
||||
class Usecase:
|
||||
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
|
||||
ways of categorising elements in the AEC industry, typically
|
||||
standardised or nominated by governments or companies. A system
|
||||
typically contains a series of hierarchical reference codes and labels
|
||||
like Pr_12_23_34.
|
||||
|
||||
Classifications may be applied to many things, not just physical
|
||||
elements, such as doors and windows, spatial elements, tasks, cost
|
||||
items, or even resources.
|
||||
|
||||
Prior to assigning classificaion references, you need to add the name
|
||||
and metadata of the classification system that you will use in your
|
||||
project. Classification systems may be revised over time, so this
|
||||
metadata includes the edition date.
|
||||
|
||||
Common classification systems are provided as an IFC library which may
|
||||
be downloaded from https://github.com/Moult/IfcClassification for your
|
||||
convenience. It is advised to use these to ensure that the
|
||||
classification metadata is standardised.
|
||||
|
||||
Adding a classification system will not add the entire hierarchy of
|
||||
references available in the classification. References need to be added
|
||||
separately. Typically, you'd only add the references that you use in
|
||||
your project, see ifcopenshell.api.classification.add_reference for more
|
||||
information.
|
||||
|
||||
:param classification: If a string is provided, it is assumed to be the
|
||||
name of your classification system. This is necessary if you are
|
||||
creating your own custom classification system. Alternatively, you
|
||||
may provide an entity_instance of an IfcClassification from an IFC
|
||||
classification library. The latter approach is preferred if you are
|
||||
using a commonly known system such as Uniclass, as this will ensure
|
||||
all metadata is added correctly.
|
||||
:type classification: str,ifcopenshell.entity_instance
|
||||
:return: The added IfcClassification element
|
||||
:rtype: ifcopenshell.entity_instance
|
||||
|
||||
Example:
|
||||
|
||||
.. code:: python
|
||||
|
||||
# Option 1: adding a custom clasification from scratch
|
||||
ifcopenshell.api.run("classification.add_classification", model,
|
||||
classification="MyCustomClassification")
|
||||
|
||||
# Option 2: adding a popular classification from a library
|
||||
library = ifcopenshell.open("/path/to/Uniclass.ifc")
|
||||
classification = library.by_type("IfcClassification")[0]
|
||||
ifcopenshell.api.run("classification.add_classification", model,
|
||||
classification=classification)
|
||||
"""
|
||||
self.file = file
|
||||
self.settings = {
|
||||
"classification": classification,
|
||||
}
|
||||
|
||||
def execute(self) -> ifcopenshell.entity_instance:
|
||||
def execute(self):
|
||||
if isinstance(self.settings["classification"], str):
|
||||
classification = self.file.createIfcClassification(Name=self.settings["classification"])
|
||||
self.relate_to_project(classification)
|
||||
|
||||
@@ -23,117 +23,119 @@ import ifcopenshell.util.schema
|
||||
from typing import Optional, Union
|
||||
|
||||
|
||||
def add_reference(
|
||||
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,
|
||||
) -> Union[ifcopenshell.entity_instance, None]:
|
||||
"""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
|
||||
Omniclass).
|
||||
|
||||
References can be added to almost any object in IFC, including physical
|
||||
objects, object types, properties, tasks, costs, resources, or even
|
||||
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 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
|
||||
Uniclass, as the library will be prepopulated with all the valid
|
||||
classifications already.
|
||||
|
||||
Objects are allowed to have multiple classification references from
|
||||
multiple classification systems. This means that adding a new reference
|
||||
will not remove existing references.
|
||||
|
||||
References can be inherited from types. This means that if an
|
||||
IfcWallType has a classification reference of Pr_12_23_34, then all
|
||||
IfcWall occurrences of that type automatically get the same
|
||||
classification of Pr_12_23_34. This means that it is more efficient to
|
||||
assign to types where possible. If a classification reference is
|
||||
assigned to both the type and an occurrence, then the assignment at the
|
||||
occurrence will override the type classification.
|
||||
|
||||
:param product: The list of IFC objects, properties, or resources you want to
|
||||
associate the classification reference to.
|
||||
:type product: list[ifcopenshell.entity_instance]
|
||||
:param reference: The classification reference entity taken from an
|
||||
IFC classification library. If you supply this parameter, you will
|
||||
use option 2.
|
||||
:type reference: ifcopenshell.entity_instance, optional
|
||||
:param identification: If you choose option 1 and do not specify a
|
||||
reference, you may manually specify an identification code. The code
|
||||
is typically a short identifier and may have punctuation to separate
|
||||
the levels of hierarchy in the classificaion (e.g. Pr_12_23_34).
|
||||
:type identification: str, optional
|
||||
:param name: If you choose option 1 and do not specify a reference, you
|
||||
may manually specify a name. The name is typically human readable.
|
||||
:type name: str, optional
|
||||
:param classification: The IfcClassification entity in your IFC model
|
||||
(not the library, if you are doing option 2) that the reference is
|
||||
part of.
|
||||
:type classification: ifcopenshell.entity_instance
|
||||
:param is_lightweight: If you are doing option 2, choose whether or not
|
||||
to only add that particular reference (lighweight) or also add all
|
||||
of its parent references in the classification hierarchy (not
|
||||
lighweight). For example, adding a lightweight reference to
|
||||
Pr_12_23_34 will only add Pr_12_23_34, but adding a heavy reference
|
||||
to Pr_12_23_34 will also add Pr_12_23 and Pr_12. These parent
|
||||
references merely help describe the "tree" of classifications, but
|
||||
is generally unnecessary. Using lightweight classifications are
|
||||
recommended and is the default.
|
||||
:type is_lightweight: bool, optional
|
||||
|
||||
:raises TypeError: If file is IFC2X3 and `products` has non-IfcRoot elements.
|
||||
|
||||
:return: The newly added IfcClassificationReference
|
||||
or `None` if `products` was empty list.
|
||||
:rtype: Union[ifcopenshell.entity_instance, None]
|
||||
|
||||
Example:
|
||||
|
||||
.. code:: python
|
||||
|
||||
# Option 1: adding and assigning a new reference from scratch
|
||||
wall_type = model.by_type("IfcWallType")[0]
|
||||
classification = ifcopenshell.api.run("classification.add_classification",
|
||||
model, classification="MyCustomClassification")
|
||||
ifcopenshell.api.run("classification.add_reference", model,
|
||||
products=[wall_type], classification=classification,
|
||||
identification="W_01", name="Interior Walls")
|
||||
|
||||
# Option 2: adding a popular classification from a library
|
||||
library = ifcopenshell.open("/path/to/Uniclass.ifc")
|
||||
lib_classification = library.by_type("IfcClassification")[0]
|
||||
classification = ifcopenshell.api.run("classification.add_classification",
|
||||
model, classification=lib_classification)
|
||||
reference = [r for r in library.by_type("IfcClassificationReference")
|
||||
if r.Identification == "XYZ"][0]
|
||||
ifcopenshell.api.run("classification.add_reference", model,
|
||||
products=[wall_type], classification=classification,
|
||||
reference=reference)
|
||||
"""
|
||||
usecase = Usecase()
|
||||
usecase.file = file
|
||||
usecase.settings = {
|
||||
"products": products,
|
||||
"reference": reference,
|
||||
"identification": identification,
|
||||
"name": name,
|
||||
"classification": classification,
|
||||
"is_lightweight": is_lightweight,
|
||||
}
|
||||
return usecase.execute()
|
||||
|
||||
|
||||
class Usecase:
|
||||
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
|
||||
Omniclass).
|
||||
|
||||
References can be added to almost any object in IFC, including physical
|
||||
objects, object types, properties, tasks, costs, resources, or even
|
||||
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 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
|
||||
Uniclass, as the library will be prepopulated with all the valid
|
||||
classifications already.
|
||||
|
||||
Objects are allowed to have multiple classification references from
|
||||
multiple classification systems. This means that adding a new reference
|
||||
will not remove existing references.
|
||||
|
||||
References can be inherited from types. This means that if an
|
||||
IfcWallType has a classification reference of Pr_12_23_34, then all
|
||||
IfcWall occurrences of that type automatically get the same
|
||||
classification of Pr_12_23_34. This means that it is more efficient to
|
||||
assign to types where possible. If a classification reference is
|
||||
assigned to both the type and an occurrence, then the assignment at the
|
||||
occurrence will override the type classification.
|
||||
|
||||
:param product: The list of IFC objects, properties, or resources you want to
|
||||
associate the classification reference to.
|
||||
:type product: list[ifcopenshell.entity_instance]
|
||||
:param reference: The classification reference entity taken from an
|
||||
IFC classification library. If you supply this parameter, you will
|
||||
use option 2.
|
||||
:type reference: ifcopenshell.entity_instance, optional
|
||||
:param identification: If you choose option 1 and do not specify a
|
||||
reference, you may manually specify an identification code. The code
|
||||
is typically a short identifier and may have punctuation to separate
|
||||
the levels of hierarchy in the classificaion (e.g. Pr_12_23_34).
|
||||
:type identification: str, optional
|
||||
:param name: If you choose option 1 and do not specify a reference, you
|
||||
may manually specify a name. The name is typically human readable.
|
||||
:type name: str, optional
|
||||
:param classification: The IfcClassification entity in your IFC model
|
||||
(not the library, if you are doing option 2) that the reference is
|
||||
part of.
|
||||
:type classification: ifcopenshell.entity_instance
|
||||
:param is_lightweight: If you are doing option 2, choose whether or not
|
||||
to only add that particular reference (lighweight) or also add all
|
||||
of its parent references in the classification hierarchy (not
|
||||
lighweight). For example, adding a lightweight reference to
|
||||
Pr_12_23_34 will only add Pr_12_23_34, but adding a heavy reference
|
||||
to Pr_12_23_34 will also add Pr_12_23 and Pr_12. These parent
|
||||
references merely help describe the "tree" of classifications, but
|
||||
is generally unnecessary. Using lightweight classifications are
|
||||
recommended and is the default.
|
||||
:type is_lightweight: bool, optional
|
||||
|
||||
:raises TypeError: If file is IFC2X3 and `products` has non-IfcRoot elements.
|
||||
|
||||
:return: The newly added IfcClassificationReference
|
||||
or `None` if `products` was empty list.
|
||||
:rtype: Union[ifcopenshell.entity_instance, None]
|
||||
|
||||
Example:
|
||||
|
||||
.. code:: python
|
||||
|
||||
# Option 1: adding and assigning a new reference from scratch
|
||||
wall_type = model.by_type("IfcWallType")[0]
|
||||
classification = ifcopenshell.api.run("classification.add_classification",
|
||||
model, classification="MyCustomClassification")
|
||||
ifcopenshell.api.run("classification.add_reference", model,
|
||||
products=[wall_type], classification=classification,
|
||||
identification="W_01", name="Interior Walls")
|
||||
|
||||
# Option 2: adding a popular classification from a library
|
||||
library = ifcopenshell.open("/path/to/Uniclass.ifc")
|
||||
lib_classification = library.by_type("IfcClassification")[0]
|
||||
classification = ifcopenshell.api.run("classification.add_classification",
|
||||
model, classification=lib_classification)
|
||||
reference = [r for r in library.by_type("IfcClassificationReference")
|
||||
if r.Identification == "XYZ"][0]
|
||||
ifcopenshell.api.run("classification.add_reference", model,
|
||||
products=[wall_type], classification=classification,
|
||||
reference=reference)
|
||||
"""
|
||||
self.file = file
|
||||
self.settings = {
|
||||
"products": products,
|
||||
"reference": reference,
|
||||
"identification": identification,
|
||||
"name": name,
|
||||
"classification": classification,
|
||||
"is_lightweight": is_lightweight,
|
||||
}
|
||||
|
||||
def execute(self) -> Union[ifcopenshell.entity_instance, None]:
|
||||
def execute(self):
|
||||
if not self.settings["products"]:
|
||||
return
|
||||
|
||||
|
||||
@@ -17,32 +17,29 @@
|
||||
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
class Usecase:
|
||||
def __init__(self, file, classification=None, attributes=None):
|
||||
"""Edits the attributes of an IfcClassification
|
||||
def edit_classification(file, classification=None, attributes=None) -> None:
|
||||
"""Edits the attributes of an IfcClassification
|
||||
|
||||
For more information about the attributes and data types of an
|
||||
IfcClassification, consult the IFC documentation.
|
||||
For more information about the attributes and data types of an
|
||||
IfcClassification, consult the IFC documentation.
|
||||
|
||||
:param classification: The IfcClassification entity you want to edit
|
||||
:type classification: ifcopenshell.entity_instance
|
||||
:param attributes: a dictionary of attribute names and values.
|
||||
:type attributes: dict, optional
|
||||
:return: None
|
||||
:rtype: None
|
||||
:param classification: The IfcClassification entity you want to edit
|
||||
:type classification: ifcopenshell.entity_instance
|
||||
:param attributes: a dictionary of attribute names and values.
|
||||
:type attributes: dict, optional
|
||||
:return: None
|
||||
:rtype: None
|
||||
|
||||
Example:
|
||||
Example:
|
||||
|
||||
.. code:: python
|
||||
.. code:: python
|
||||
|
||||
classification = model.by_type("IfcClassification")[0]
|
||||
# Change the name of the classification system to "Foo"
|
||||
ifcopenshell.api.run("classification.edit_classification", model,
|
||||
classification=classification, attributes={"Name": "Foo"})
|
||||
"""
|
||||
self.file = file
|
||||
self.settings = {"classification": classification, "attributes": attributes or {}}
|
||||
classification = model.by_type("IfcClassification")[0]
|
||||
# Change the name of the classification system to "Foo"
|
||||
ifcopenshell.api.run("classification.edit_classification", model,
|
||||
classification=classification, attributes={"Name": "Foo"})
|
||||
"""
|
||||
settings = {"classification": classification, "attributes": attributes or {}}
|
||||
|
||||
def execute(self):
|
||||
for name, value in self.settings["attributes"].items():
|
||||
setattr(self.settings["classification"], name, value)
|
||||
for name, value in settings["attributes"].items():
|
||||
setattr(settings["classification"], name, value)
|
||||
|
||||
@@ -17,32 +17,29 @@
|
||||
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
class Usecase:
|
||||
def __init__(self, file, reference=None, attributes=None):
|
||||
"""Edits the attributes of an IfcClassificationReference
|
||||
def edit_reference(file, reference=None, attributes=None) -> None:
|
||||
"""Edits the attributes of an IfcClassificationReference
|
||||
|
||||
For more information about the attributes and data types of an
|
||||
IfcClassificationReference, consult the IFC documentation.
|
||||
For more information about the attributes and data types of an
|
||||
IfcClassificationReference, consult the IFC documentation.
|
||||
|
||||
:param reference: The IfcClassificationReference entity you want to edit
|
||||
:type reference: ifcopenshell.entity_instance
|
||||
:param attributes: a dictionary of attribute names and values.
|
||||
:type attributes: dict, optional
|
||||
:return: None
|
||||
:rtype: None
|
||||
:param reference: The IfcClassificationReference entity you want to edit
|
||||
:type reference: ifcopenshell.entity_instance
|
||||
:param attributes: a dictionary of attribute names and values.
|
||||
:type attributes: dict, optional
|
||||
:return: None
|
||||
:rtype: None
|
||||
|
||||
Example:
|
||||
Example:
|
||||
|
||||
.. code:: python
|
||||
.. code:: python
|
||||
|
||||
reference = model.by_type("IfcClassification")[0]
|
||||
# Change the name of the reference to "Foo"
|
||||
ifcopenshell.api.run("classification.edit_reference", model,
|
||||
reference=reference, attributes={"Name": "Foo"})
|
||||
"""
|
||||
self.file = file
|
||||
self.settings = {"reference": reference, "attributes": attributes or {}}
|
||||
reference = model.by_type("IfcClassification")[0]
|
||||
# Change the name of the reference to "Foo"
|
||||
ifcopenshell.api.run("classification.edit_reference", model,
|
||||
reference=reference, attributes={"Name": "Foo"})
|
||||
"""
|
||||
settings = {"reference": reference, "attributes": attributes or {}}
|
||||
|
||||
def execute(self):
|
||||
for name, value in self.settings["attributes"].items():
|
||||
setattr(self.settings["reference"], name, value)
|
||||
for name, value in settings["attributes"].items():
|
||||
setattr(settings["reference"], name, value)
|
||||
|
||||
@@ -20,30 +20,33 @@ import ifcopenshell
|
||||
import ifcopenshell.util.element
|
||||
|
||||
|
||||
def remove_classification(file, classification=None) -> None:
|
||||
"""Removes an IfcClassification from the project and all references
|
||||
|
||||
The classification and all of its relationships, children references,
|
||||
and relationships between objectse and child references are completely
|
||||
removed from a project.
|
||||
|
||||
:param classification: The IfcClassification entity you want to remove
|
||||
:type classification: ifcopenshell.entity_instance
|
||||
:return: None
|
||||
:rtype: None
|
||||
|
||||
Example:
|
||||
|
||||
.. code:: python
|
||||
|
||||
classification = model.by_type("IfcClassification")[0]
|
||||
ifcopenshell.api.run("classification.remove_classification", model,
|
||||
classification=classification)
|
||||
"""
|
||||
usecase = Usecase()
|
||||
usecase.file = file
|
||||
usecase.settings = {"classification": classification}
|
||||
return usecase.execute()
|
||||
|
||||
|
||||
class Usecase:
|
||||
def __init__(self, file, classification=None):
|
||||
"""Removes an IfcClassification from the project and all references
|
||||
|
||||
The classification and all of its relationships, children references,
|
||||
and relationships between objectse and child references are completely
|
||||
removed from a project.
|
||||
|
||||
:param classification: The IfcClassification entity you want to remove
|
||||
:type classification: ifcopenshell.entity_instance
|
||||
:return: None
|
||||
:rtype: None
|
||||
|
||||
Example:
|
||||
|
||||
.. code:: python
|
||||
|
||||
classification = model.by_type("IfcClassification")[0]
|
||||
ifcopenshell.api.run("classification.remove_classification", model,
|
||||
classification=classification)
|
||||
"""
|
||||
self.file = file
|
||||
self.settings = {"classification": classification}
|
||||
|
||||
def execute(self):
|
||||
references = self.get_references(self.settings["classification"])
|
||||
for reference in references:
|
||||
|
||||
@@ -21,107 +21,102 @@ import ifcopenshell.api
|
||||
import ifcopenshell.util.element
|
||||
|
||||
|
||||
class Usecase:
|
||||
def __init__(
|
||||
self,
|
||||
file: ifcopenshell.file,
|
||||
reference: ifcopenshell.entity_instance,
|
||||
products: list[ifcopenshell.entity_instance],
|
||||
):
|
||||
"""Removes a classification reference from the list of products
|
||||
def remove_reference(
|
||||
file: ifcopenshell.file,
|
||||
reference: ifcopenshell.entity_instance,
|
||||
products: list[ifcopenshell.entity_instance],
|
||||
) -> None:
|
||||
"""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.
|
||||
If the classification reference is no longer associated to any products,
|
||||
the classification reference itself is also removed.
|
||||
|
||||
:param reference: The IfcClassificationReference entity of the
|
||||
relationship you want to remove.
|
||||
:type reference: ifcopenshell.entity_instance
|
||||
:param product: The list fo object entities of the relationship you want to
|
||||
remove.
|
||||
:type product: list[ifcopenshell.entity_instance]
|
||||
:param reference: The IfcClassificationReference entity of the
|
||||
relationship you want to remove.
|
||||
:type reference: ifcopenshell.entity_instance
|
||||
:param product: The list fo object entities of the relationship you want to
|
||||
remove.
|
||||
:type product: list[ifcopenshell.entity_instance]
|
||||
|
||||
:raises TypeError: If file is IFC2X3 and `products` has non-IfcRoot elements.
|
||||
:raises TypeError: If file is IFC2X3 and `products` has non-IfcRoot elements.
|
||||
|
||||
:return: None
|
||||
:rtype: None
|
||||
:return: None
|
||||
:rtype: None
|
||||
|
||||
Example:
|
||||
Example:
|
||||
|
||||
.. code:: python
|
||||
.. code:: python
|
||||
|
||||
wall_type = model.by_type("IfcWallType")[0]
|
||||
classification = ifcopenshell.api.run("classification.add_classification",
|
||||
model, classification="MyCustomClassification")
|
||||
reference = ifcopenshell.api.run("classification.add_reference", model,
|
||||
products=[wall_type], classification=classification,
|
||||
identification="W_01", name="Interior Walls")
|
||||
ifcopenshell.api.run("classification.remove_reference", model,
|
||||
reference=reference, products=[wall_type])
|
||||
"""
|
||||
self.file = file
|
||||
self.settings = {"reference": reference, "products": products}
|
||||
wall_type = model.by_type("IfcWallType")[0]
|
||||
classification = ifcopenshell.api.run("classification.add_classification",
|
||||
model, classification="MyCustomClassification")
|
||||
reference = ifcopenshell.api.run("classification.add_reference", model,
|
||||
products=[wall_type], classification=classification,
|
||||
identification="W_01", name="Interior Walls")
|
||||
ifcopenshell.api.run("classification.remove_reference", model,
|
||||
reference=reference, products=[wall_type])
|
||||
"""
|
||||
settings = {"reference": reference, "products": products}
|
||||
|
||||
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)
|
||||
is_ifc2x3 = file.schema == "IFC2X3"
|
||||
products = set(settings["products"])
|
||||
referenced = ifcopenshell.util.element.get_referenced_elements(settings["reference"])
|
||||
products -= products.difference(referenced)
|
||||
|
||||
# all products are already unassigned from a reference
|
||||
if not products:
|
||||
return
|
||||
# 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)
|
||||
rooted_products: set[ifcopenshell.entity_instance] = set()
|
||||
non_rooted_products: set[ifcopenshell.entity_instance] = set()
|
||||
for product in 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 == 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", file, **{"element": rel})
|
||||
else:
|
||||
non_rooted_products.add(product)
|
||||
history = rel.OwnerHistory
|
||||
file.remove(rel)
|
||||
if history:
|
||||
ifcopenshell.util.element.remove_deep2(file, history)
|
||||
|
||||
if non_rooted_products and is_ifc2x3:
|
||||
raise TypeError(f"Cannot add reference to non-IfcRoot element in IFC2X3: {non_rooted_products}.")
|
||||
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)
|
||||
|
||||
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.RelatingReference == settings["reference"]}
|
||||
for rel in reference_rels:
|
||||
related_objects = set(rel.RelatedResourceObjects) - non_rooted_products
|
||||
if related_objects:
|
||||
rel.RelatedResourceObjects = list(related_objects)
|
||||
else:
|
||||
file.remove(rel)
|
||||
|
||||
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
|
||||
referenced_elements = ifcopenshell.util.element.get_referenced_elements(self.settings["reference"])
|
||||
if not referenced_elements:
|
||||
self.file.remove(self.settings["reference"])
|
||||
# TODO: we only handle lightweight classifications here
|
||||
referenced_elements = ifcopenshell.util.element.get_referenced_elements(settings["reference"])
|
||||
if not referenced_elements:
|
||||
file.remove(settings["reference"])
|
||||
|
||||
Reference in New Issue
Block a user