mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-10 09:48:32 +00:00
Generate functions for all API usecases for better static code features. See #2693.
This commit is contained in:
@@ -15,3 +15,8 @@
|
||||
#
|
||||
# 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 .copy_class import copy_class
|
||||
from .create_entity import create_entity
|
||||
from .reassign_class import reassign_class
|
||||
from .remove_product import remove_product
|
||||
|
||||
@@ -21,52 +21,55 @@ import ifcopenshell.util.system
|
||||
import ifcopenshell.util.element
|
||||
|
||||
|
||||
def copy_class(file, product=None) -> None:
|
||||
"""Copies a product
|
||||
|
||||
The following relationships are also duplicated:
|
||||
|
||||
* The copy will have the same object placement coordinates as the
|
||||
original.
|
||||
* The copy will have duplicated property sets, properties, and quantities
|
||||
* The copy will have all nested distribution ports copied too
|
||||
* The copy will be part of the same aggregate
|
||||
* The copy will be contained in the same spatial structure
|
||||
* The copy, if it is an occurrence, will have the same type
|
||||
* Voids are duplicated too
|
||||
* The copy will have the same material as the original. Parametric
|
||||
material set usages will be copied.
|
||||
* The copy will be part of the same groups as the original.
|
||||
|
||||
Be warned that:
|
||||
|
||||
* Representations are _not_ copied. Copying representations is an
|
||||
expensive operation so for now the user is responsible for handling
|
||||
representations.
|
||||
* Filled voids are not copied, as there is no guarantee that the filling
|
||||
will also be copied.
|
||||
* Path connectivity is not copied, as there is no guarantee that the
|
||||
connections are still valid.
|
||||
|
||||
:param product: The IfcProduct to copy.
|
||||
:type param: ifcopenshell.entity_instance
|
||||
:return: The copied product
|
||||
:rtype: ifcopenshell.entity_instance
|
||||
|
||||
Example:
|
||||
|
||||
.. code:: python
|
||||
|
||||
# We have a wall
|
||||
wall = ifcopenshell.api.run("root.create_entity", model, ifc_class="IfcWall")
|
||||
|
||||
# And now we have two
|
||||
wall_copy = ifcopenshell.api.run("root.copy_class", model, product=wall)
|
||||
"""
|
||||
usecase = Usecase()
|
||||
usecase.file = file
|
||||
usecase.settings = {"product": product}
|
||||
return usecase.execute()
|
||||
|
||||
|
||||
class Usecase:
|
||||
def __init__(self, file, product=None):
|
||||
"""Copies a product
|
||||
|
||||
The following relationships are also duplicated:
|
||||
|
||||
* The copy will have the same object placement coordinates as the
|
||||
original.
|
||||
* The copy will have duplicated property sets, properties, and quantities
|
||||
* The copy will have all nested distribution ports copied too
|
||||
* The copy will be part of the same aggregate
|
||||
* The copy will be contained in the same spatial structure
|
||||
* The copy, if it is an occurrence, will have the same type
|
||||
* Voids are duplicated too
|
||||
* The copy will have the same material as the original. Parametric
|
||||
material set usages will be copied.
|
||||
* The copy will be part of the same groups as the original.
|
||||
|
||||
Be warned that:
|
||||
|
||||
* Representations are _not_ copied. Copying representations is an
|
||||
expensive operation so for now the user is responsible for handling
|
||||
representations.
|
||||
* Filled voids are not copied, as there is no guarantee that the filling
|
||||
will also be copied.
|
||||
* Path connectivity is not copied, as there is no guarantee that the
|
||||
connections are still valid.
|
||||
|
||||
:param product: The IfcProduct to copy.
|
||||
:type param: ifcopenshell.entity_instance
|
||||
:return: The copied product
|
||||
:rtype: ifcopenshell.entity_instance
|
||||
|
||||
Example:
|
||||
|
||||
.. code:: python
|
||||
|
||||
# We have a wall
|
||||
wall = ifcopenshell.api.run("root.create_entity", model, ifc_class="IfcWall")
|
||||
|
||||
# And now we have two
|
||||
wall_copy = ifcopenshell.api.run("root.copy_class", model, product=wall)
|
||||
"""
|
||||
self.file = file
|
||||
self.settings = {"product": product}
|
||||
|
||||
def execute(self):
|
||||
result = ifcopenshell.util.element.copy(self.file, self.settings["product"])
|
||||
self.copy_direct_attributes(result)
|
||||
|
||||
@@ -21,63 +21,65 @@ import ifcopenshell.api
|
||||
from typing import Optional
|
||||
|
||||
|
||||
def create_entity(
|
||||
file: ifcopenshell.file,
|
||||
ifc_class: str = "IfcBuildingElementProxy",
|
||||
predefined_type: Optional[str] = None,
|
||||
name: Optional[str] = None,
|
||||
) -> ifcopenshell.entity_instance:
|
||||
"""Create a new rooted product
|
||||
|
||||
This is a critical function used to create almost any rooted product or
|
||||
product type. If you want to create walls, spaces, buildings, wall
|
||||
types, and so on, use this function.
|
||||
|
||||
Just specify the class you want to create, as well as the predefined
|
||||
type and name. It will handle the storage of the predefined type and
|
||||
check whether the predefined type is built-in or custom. It will also
|
||||
generate a valid GlobalId and store ownership history. It will also
|
||||
handle some edge cases for default validity where users might forget to
|
||||
populate some mandatory attributes. For example, doors must define an
|
||||
operation type but many people forget.
|
||||
|
||||
:param ifc_class: Any rooted IFC class.
|
||||
:type ifc_class: str,optional
|
||||
:param predefined_type: Any built-in or user-defined predefined type that
|
||||
is applicable to that IFC class. For user-defined predefined types
|
||||
just enter in any value and the API will handle it automatically.
|
||||
:type predefined_type: str,optional
|
||||
:param name: The name of the new element.
|
||||
:type name: str,optional
|
||||
:return: The newly created element based on the specified IFC class.
|
||||
:rtype: ifcopenshell.entity_instance
|
||||
|
||||
Example:
|
||||
|
||||
.. code:: python
|
||||
|
||||
# We have a project.
|
||||
ifcopenshell.api.run("root.create_entity", model, ifc_class="IfcProject")
|
||||
|
||||
# We have a building.
|
||||
ifcopenshell.api.run("root.create_entity", model, ifc_class="IfcBuilding")
|
||||
|
||||
# We have a wall.
|
||||
ifcopenshell.api.run("root.create_entity", model, ifc_class="IfcWall")
|
||||
|
||||
# We have a wall type.
|
||||
ifcopenshell.api.run("root.create_entity", model, ifc_class="IfcWallType")
|
||||
"""
|
||||
usecase = Usecase()
|
||||
usecase.file = file
|
||||
usecase.settings = {
|
||||
"ifc_class": ifc_class,
|
||||
"predefined_type": predefined_type,
|
||||
"name": name,
|
||||
}
|
||||
return usecase.execute()
|
||||
|
||||
|
||||
class Usecase:
|
||||
def __init__(
|
||||
self,
|
||||
file: ifcopenshell.file,
|
||||
ifc_class: str = "IfcBuildingElementProxy",
|
||||
predefined_type: Optional[str] = None,
|
||||
name: Optional[str] = None,
|
||||
):
|
||||
"""Create a new rooted product
|
||||
|
||||
This is a critical function used to create almost any rooted product or
|
||||
product type. If you want to create walls, spaces, buildings, wall
|
||||
types, and so on, use this function.
|
||||
|
||||
Just specify the class you want to create, as well as the predefined
|
||||
type and name. It will handle the storage of the predefined type and
|
||||
check whether the predefined type is built-in or custom. It will also
|
||||
generate a valid GlobalId and store ownership history. It will also
|
||||
handle some edge cases for default validity where users might forget to
|
||||
populate some mandatory attributes. For example, doors must define an
|
||||
operation type but many people forget.
|
||||
|
||||
:param ifc_class: Any rooted IFC class.
|
||||
:type ifc_class: str,optional
|
||||
:param predefined_type: Any built-in or user-defined predefined type that
|
||||
is applicable to that IFC class. For user-defined predefined types
|
||||
just enter in any value and the API will handle it automatically.
|
||||
:type predefined_type: str,optional
|
||||
:param name: The name of the new element.
|
||||
:type name: str,optional
|
||||
:return: The newly created element based on the specified IFC class.
|
||||
:rtype: ifcopenshell.entity_instance
|
||||
|
||||
Example:
|
||||
|
||||
.. code:: python
|
||||
|
||||
# We have a project.
|
||||
ifcopenshell.api.run("root.create_entity", model, ifc_class="IfcProject")
|
||||
|
||||
# We have a building.
|
||||
ifcopenshell.api.run("root.create_entity", model, ifc_class="IfcBuilding")
|
||||
|
||||
# We have a wall.
|
||||
ifcopenshell.api.run("root.create_entity", model, ifc_class="IfcWall")
|
||||
|
||||
# We have a wall type.
|
||||
ifcopenshell.api.run("root.create_entity", model, ifc_class="IfcWallType")
|
||||
"""
|
||||
self.file = file
|
||||
self.settings = {
|
||||
"ifc_class": ifc_class,
|
||||
"predefined_type": predefined_type,
|
||||
"name": name,
|
||||
}
|
||||
|
||||
def execute(self) -> ifcopenshell.entity_instance:
|
||||
def execute(self):
|
||||
element = self.file.create_entity(
|
||||
self.settings["ifc_class"],
|
||||
**{
|
||||
|
||||
@@ -22,61 +22,63 @@ import ifcopenshell.util.schema
|
||||
import ifcopenshell.util.element
|
||||
|
||||
|
||||
def reassign_class(
|
||||
file,
|
||||
product=None,
|
||||
ifc_class="IfcBuildingElementProxy",
|
||||
predefined_type=None,
|
||||
) -> None:
|
||||
"""Changes the class of a product
|
||||
|
||||
If you ever created a wall then realised it's meant to be something
|
||||
else, this function lets you change the IFC class whilst retaining all
|
||||
other geometry and relationships.
|
||||
|
||||
This is especially useful when dealing with poorly classified data from
|
||||
proprietary software with limited IFC capabilities.
|
||||
|
||||
If you are reassigning a type, the occurrence classes are also
|
||||
reassigned to maintain validity.
|
||||
|
||||
Vice versa, if you are reassigning an occurrence, the type is also
|
||||
reassigned in IFC4 and up. In IFC2X3, this may not occur if the type
|
||||
cannot be unambiguously derived, so you are required to manually check
|
||||
this.
|
||||
|
||||
:param product: The IfcProduct that you want to change the class of.
|
||||
:type product: ifcopenshell.entity_instance
|
||||
:param ifc_class: The new IFC class you want to change it to.
|
||||
:type ifc_class: str,optional
|
||||
:param predefined_type: In case you want to change the predefined type
|
||||
too. User defined types are also allowed, just type what you want.
|
||||
:type predefined_type: str,optional
|
||||
:return: The newly modified product.
|
||||
:rtype: ifcopenshell.entity_instance
|
||||
|
||||
Example:
|
||||
|
||||
.. code:: python
|
||||
|
||||
# We have a wall.
|
||||
wall = ifcopenshell.api.run("root.create_entity", model, ifc_class="IfcWall")
|
||||
|
||||
# Oh, did I say wall? I meant slab.
|
||||
slab = ifcopenshell.api.run("root.reassign_class", model, product=wall, ifc_class="IfcSlab")
|
||||
|
||||
# Warning: this will crash since wall doesn't exist any more.
|
||||
print(wall) # Kaboom.
|
||||
"""
|
||||
usecase = Usecase()
|
||||
usecase.file = file
|
||||
usecase.settings = {
|
||||
"product": product,
|
||||
"ifc_class": ifc_class,
|
||||
"predefined_type": predefined_type,
|
||||
}
|
||||
return usecase.execute()
|
||||
|
||||
|
||||
class Usecase:
|
||||
def __init__(
|
||||
self,
|
||||
file,
|
||||
product=None,
|
||||
ifc_class="IfcBuildingElementProxy",
|
||||
predefined_type=None,
|
||||
):
|
||||
"""Changes the class of a product
|
||||
|
||||
If you ever created a wall then realised it's meant to be something
|
||||
else, this function lets you change the IFC class whilst retaining all
|
||||
other geometry and relationships.
|
||||
|
||||
This is especially useful when dealing with poorly classified data from
|
||||
proprietary software with limited IFC capabilities.
|
||||
|
||||
If you are reassigning a type, the occurrence classes are also
|
||||
reassigned to maintain validity.
|
||||
|
||||
Vice versa, if you are reassigning an occurrence, the type is also
|
||||
reassigned in IFC4 and up. In IFC2X3, this may not occur if the type
|
||||
cannot be unambiguously derived, so you are required to manually check
|
||||
this.
|
||||
|
||||
:param product: The IfcProduct that you want to change the class of.
|
||||
:type product: ifcopenshell.entity_instance
|
||||
:param ifc_class: The new IFC class you want to change it to.
|
||||
:type ifc_class: str,optional
|
||||
:param predefined_type: In case you want to change the predefined type
|
||||
too. User defined types are also allowed, just type what you want.
|
||||
:type predefined_type: str,optional
|
||||
:return: The newly modified product.
|
||||
:rtype: ifcopenshell.entity_instance
|
||||
|
||||
Example:
|
||||
|
||||
.. code:: python
|
||||
|
||||
# We have a wall.
|
||||
wall = ifcopenshell.api.run("root.create_entity", model, ifc_class="IfcWall")
|
||||
|
||||
# Oh, did I say wall? I meant slab.
|
||||
slab = ifcopenshell.api.run("root.reassign_class", model, product=wall, ifc_class="IfcSlab")
|
||||
|
||||
# Warning: this will crash since wall doesn't exist any more.
|
||||
print(wall) # Kaboom.
|
||||
"""
|
||||
self.file = file
|
||||
self.settings = {
|
||||
"product": product,
|
||||
"ifc_class": ifc_class,
|
||||
"predefined_type": predefined_type,
|
||||
}
|
||||
|
||||
def execute(self):
|
||||
element = self.reassign_class(self.settings["product"], self.settings["ifc_class"])
|
||||
|
||||
|
||||
@@ -20,212 +20,207 @@ import ifcopenshell.api
|
||||
import ifcopenshell.util.element
|
||||
|
||||
|
||||
class Usecase:
|
||||
def __init__(self, file: ifcopenshell.file, product: ifcopenshell.entity_instance):
|
||||
"""Removes a product
|
||||
def remove_product(file: ifcopenshell.file, product: ifcopenshell.entity_instance) -> None:
|
||||
"""Removes a product
|
||||
|
||||
This is effectively a smart delete function that not only removes a
|
||||
product, but also all of its relationships. It is always recommended to
|
||||
use this function to prevent orphaned data in your IFC model.
|
||||
This is effectively a smart delete function that not only removes a
|
||||
product, but also all of its relationships. It is always recommended to
|
||||
use this function to prevent orphaned data in your IFC model.
|
||||
|
||||
This is intended to be used for removing:
|
||||
This is intended to be used for removing:
|
||||
|
||||
- IfcAnnotation
|
||||
- IfcElement
|
||||
- IfcElementType
|
||||
- IfcSpatialElement
|
||||
- IfcSpatialElementType
|
||||
- IfcAnnotation
|
||||
- IfcElement
|
||||
- IfcElementType
|
||||
- IfcSpatialElement
|
||||
- IfcSpatialElementType
|
||||
|
||||
For example, geometric representations are removed. Placement
|
||||
coordinates are also removed. Properties are removed. Material, type,
|
||||
containment, aggregation, and nesting relationships are removed (but
|
||||
naturally, the materials, types, containers, etc themselves remain).
|
||||
For example, geometric representations are removed. Placement
|
||||
coordinates are also removed. Properties are removed. Material, type,
|
||||
containment, aggregation, and nesting relationships are removed (but
|
||||
naturally, the materials, types, containers, etc themselves remain).
|
||||
|
||||
:param product: The element to remove.
|
||||
:type product: ifcopenshell.entity_instance
|
||||
:return: None
|
||||
:rtype: None
|
||||
:param product: The element to remove.
|
||||
:type product: ifcopenshell.entity_instance
|
||||
:return: None
|
||||
:rtype: None
|
||||
|
||||
Example:
|
||||
Example:
|
||||
|
||||
.. code:: python
|
||||
.. code:: python
|
||||
|
||||
# We have a wall.
|
||||
wall = ifcopenshell.api.run("root.create_entity", model, ifc_class="IfcWall")
|
||||
# We have a wall.
|
||||
wall = ifcopenshell.api.run("root.create_entity", model, ifc_class="IfcWall")
|
||||
|
||||
# No we don't.
|
||||
ifcopenshell.api.run("root.remove_product", model, product=wall)
|
||||
"""
|
||||
self.file = file
|
||||
self.settings = {"product": product}
|
||||
# No we don't.
|
||||
ifcopenshell.api.run("root.remove_product", model, product=wall)
|
||||
"""
|
||||
settings = {"product": product}
|
||||
|
||||
def execute(self) -> None:
|
||||
representations = []
|
||||
if self.settings["product"].is_a("IfcProduct"):
|
||||
if self.settings["product"].Representation:
|
||||
representations = self.settings["product"].Representation.Representations or []
|
||||
else:
|
||||
representations = []
|
||||
representations = []
|
||||
if settings["product"].is_a("IfcProduct"):
|
||||
if settings["product"].Representation:
|
||||
representations = settings["product"].Representation.Representations or []
|
||||
else:
|
||||
representations = []
|
||||
|
||||
# remove object placements
|
||||
object_placement = self.settings["product"].ObjectPlacement
|
||||
if object_placement:
|
||||
if self.file.get_total_inverses(object_placement) == 1:
|
||||
self.settings["product"].ObjectPlacement = None # remove the inverse for remove_deep2 to work
|
||||
ifcopenshell.util.element.remove_deep2(self.file, object_placement)
|
||||
# remove object placements
|
||||
object_placement = settings["product"].ObjectPlacement
|
||||
if object_placement:
|
||||
if file.get_total_inverses(object_placement) == 1:
|
||||
settings["product"].ObjectPlacement = None # remove the inverse for remove_deep2 to work
|
||||
ifcopenshell.util.element.remove_deep2(file, object_placement)
|
||||
|
||||
elif self.settings["product"].is_a("IfcTypeProduct"):
|
||||
representations = [rm.MappedRepresentation for rm in self.settings["product"].RepresentationMaps or []]
|
||||
elif settings["product"].is_a("IfcTypeProduct"):
|
||||
representations = [rm.MappedRepresentation for rm in settings["product"].RepresentationMaps or []]
|
||||
|
||||
# remove psets
|
||||
psets = self.settings["product"].HasPropertySets or []
|
||||
for pset in psets:
|
||||
if self.file.get_total_inverses(pset) != 1:
|
||||
continue
|
||||
ifcopenshell.api.run(
|
||||
"pset.remove_pset",
|
||||
self.file,
|
||||
product=self.settings["product"],
|
||||
pset=pset,
|
||||
)
|
||||
|
||||
for representation in representations:
|
||||
ifcopenshell.api.run(
|
||||
"geometry.unassign_representation",
|
||||
self.file,
|
||||
**{"product": self.settings["product"], "representation": representation}
|
||||
)
|
||||
ifcopenshell.api.run("geometry.remove_representation", self.file, **{"representation": representation})
|
||||
for opening in getattr(self.settings["product"], "HasOpenings", []) or []:
|
||||
ifcopenshell.api.run("void.remove_opening", self.file, opening=opening.RelatedOpeningElement)
|
||||
|
||||
if self.settings["product"].is_a("IfcGrid"):
|
||||
for axis in (
|
||||
self.settings["product"].UAxes + self.settings["product"].VAxes + (self.settings["product"].WAxes or ())
|
||||
):
|
||||
ifcopenshell.api.run("grid.remove_grid_axis", self.file, axis=axis)
|
||||
|
||||
def element_exists(element_id):
|
||||
try:
|
||||
self.file.by_id(element_id)
|
||||
return True
|
||||
except RuntimeError:
|
||||
return False
|
||||
|
||||
# TODO: remove object placement and other relationships
|
||||
for inverse_id in [i.id() for i in self.file.get_inverse(self.settings["product"])]:
|
||||
try:
|
||||
inverse = self.file.by_id(inverse_id)
|
||||
except:
|
||||
# remove psets
|
||||
psets = settings["product"].HasPropertySets or []
|
||||
for pset in psets:
|
||||
if file.get_total_inverses(pset) != 1:
|
||||
continue
|
||||
if inverse.is_a("IfcRelDefinesByProperties"):
|
||||
ifcopenshell.api.run(
|
||||
"pset.remove_pset",
|
||||
self.file,
|
||||
product=self.settings["product"],
|
||||
pset=inverse.RelatingPropertyDefinition,
|
||||
)
|
||||
elif inverse.is_a("IfcRelAssociatesMaterial"):
|
||||
ifcopenshell.api.run("material.unassign_material", self.file, products=[self.settings["product"]])
|
||||
elif inverse.is_a("IfcRelDefinesByType"):
|
||||
if inverse.RelatingType == self.settings["product"]:
|
||||
ifcopenshell.api.run("type.unassign_type", self.file, related_objects=inverse.RelatedObjects)
|
||||
else:
|
||||
ifcopenshell.api.run("type.unassign_type", self.file, related_objects=[self.settings["product"]])
|
||||
elif inverse.is_a("IfcRelSpaceBoundary"):
|
||||
ifcopenshell.api.run("boundary.remove_boundary", self.file, boundary=inverse)
|
||||
elif inverse.is_a("IfcRelFillsElement"):
|
||||
history = inverse.OwnerHistory
|
||||
self.file.remove(inverse)
|
||||
if history:
|
||||
ifcopenshell.util.element.remove_deep2(self.file, history)
|
||||
elif inverse.is_a("IfcRelVoidsElement"):
|
||||
history = inverse.OwnerHistory
|
||||
self.file.remove(inverse)
|
||||
if history:
|
||||
ifcopenshell.util.element.remove_deep2(self.file, history)
|
||||
elif inverse.is_a("IfcRelServicesBuildings"):
|
||||
history = inverse.OwnerHistory
|
||||
self.file.remove(inverse)
|
||||
if history:
|
||||
ifcopenshell.util.element.remove_deep2(self.file, history)
|
||||
elif inverse.is_a("IfcRelNests"):
|
||||
if inverse.RelatingObject == self.settings["product"]:
|
||||
inverse_id = inverse.id()
|
||||
for subelement in inverse.RelatedObjects:
|
||||
if subelement.is_a("IfcDistributionPort"):
|
||||
ifcopenshell.api.run("root.remove_product", self.file, product=subelement)
|
||||
# IfcRelNests could have been already deleted after removing one of the products
|
||||
if element_exists(inverse_id):
|
||||
history = inverse.OwnerHistory
|
||||
self.file.remove(inverse)
|
||||
if history:
|
||||
ifcopenshell.util.element.remove_deep2(self.file, history)
|
||||
elif inverse.RelatedObjects == (self.settings["product"],):
|
||||
ifcopenshell.api.run(
|
||||
"pset.remove_pset",
|
||||
file,
|
||||
product=settings["product"],
|
||||
pset=pset,
|
||||
)
|
||||
|
||||
for representation in representations:
|
||||
ifcopenshell.api.run(
|
||||
"geometry.unassign_representation",
|
||||
file,
|
||||
**{"product": settings["product"], "representation": representation}
|
||||
)
|
||||
ifcopenshell.api.run("geometry.remove_representation", file, **{"representation": representation})
|
||||
for opening in getattr(settings["product"], "HasOpenings", []) or []:
|
||||
ifcopenshell.api.run("void.remove_opening", file, opening=opening.RelatedOpeningElement)
|
||||
|
||||
if settings["product"].is_a("IfcGrid"):
|
||||
for axis in settings["product"].UAxes + settings["product"].VAxes + (settings["product"].WAxes or ()):
|
||||
ifcopenshell.api.run("grid.remove_grid_axis", file, axis=axis)
|
||||
|
||||
def element_exists(element_id):
|
||||
try:
|
||||
file.by_id(element_id)
|
||||
return True
|
||||
except RuntimeError:
|
||||
return False
|
||||
|
||||
# TODO: remove object placement and other relationships
|
||||
for inverse_id in [i.id() for i in file.get_inverse(settings["product"])]:
|
||||
try:
|
||||
inverse = file.by_id(inverse_id)
|
||||
except:
|
||||
continue
|
||||
if inverse.is_a("IfcRelDefinesByProperties"):
|
||||
ifcopenshell.api.run(
|
||||
"pset.remove_pset",
|
||||
file,
|
||||
product=settings["product"],
|
||||
pset=inverse.RelatingPropertyDefinition,
|
||||
)
|
||||
elif inverse.is_a("IfcRelAssociatesMaterial"):
|
||||
ifcopenshell.api.run("material.unassign_material", file, products=[settings["product"]])
|
||||
elif inverse.is_a("IfcRelDefinesByType"):
|
||||
if inverse.RelatingType == settings["product"]:
|
||||
ifcopenshell.api.run("type.unassign_type", file, related_objects=inverse.RelatedObjects)
|
||||
else:
|
||||
ifcopenshell.api.run("type.unassign_type", file, related_objects=[settings["product"]])
|
||||
elif inverse.is_a("IfcRelSpaceBoundary"):
|
||||
ifcopenshell.api.run("boundary.remove_boundary", file, boundary=inverse)
|
||||
elif inverse.is_a("IfcRelFillsElement"):
|
||||
history = inverse.OwnerHistory
|
||||
file.remove(inverse)
|
||||
if history:
|
||||
ifcopenshell.util.element.remove_deep2(file, history)
|
||||
elif inverse.is_a("IfcRelVoidsElement"):
|
||||
history = inverse.OwnerHistory
|
||||
file.remove(inverse)
|
||||
if history:
|
||||
ifcopenshell.util.element.remove_deep2(file, history)
|
||||
elif inverse.is_a("IfcRelServicesBuildings"):
|
||||
history = inverse.OwnerHistory
|
||||
file.remove(inverse)
|
||||
if history:
|
||||
ifcopenshell.util.element.remove_deep2(file, history)
|
||||
elif inverse.is_a("IfcRelNests"):
|
||||
if inverse.RelatingObject == settings["product"]:
|
||||
inverse_id = inverse.id()
|
||||
for subelement in inverse.RelatedObjects:
|
||||
if subelement.is_a("IfcDistributionPort"):
|
||||
ifcopenshell.api.run("root.remove_product", file, product=subelement)
|
||||
# IfcRelNests could have been already deleted after removing one of the products
|
||||
if element_exists(inverse_id):
|
||||
history = inverse.OwnerHistory
|
||||
self.file.remove(inverse)
|
||||
file.remove(inverse)
|
||||
if history:
|
||||
ifcopenshell.util.element.remove_deep2(self.file, history)
|
||||
elif inverse.is_a("IfcRelAggregates"):
|
||||
if inverse.RelatingObject == self.settings["product"] or len(inverse.RelatedObjects) == 1:
|
||||
history = inverse.OwnerHistory
|
||||
self.file.remove(inverse)
|
||||
if history:
|
||||
ifcopenshell.util.element.remove_deep2(self.file, history)
|
||||
elif inverse.is_a("IfcRelContainedInSpatialStructure"):
|
||||
if inverse.RelatingStructure == self.settings["product"] or len(inverse.RelatedElements) == 1:
|
||||
history = inverse.OwnerHistory
|
||||
self.file.remove(inverse)
|
||||
if history:
|
||||
ifcopenshell.util.element.remove_deep2(self.file, history)
|
||||
elif inverse.is_a("IfcRelConnectsElements"):
|
||||
if inverse.is_a("IfcRelConnectsWithRealizingElements"):
|
||||
if self.settings["product"] not in (inverse.RelatingElement, inverse.RelatedElement) and any(
|
||||
el for el in inverse.RealizingElements if el != self.settings["product"]
|
||||
):
|
||||
continue
|
||||
ifcopenshell.util.element.remove_deep2(file, history)
|
||||
elif inverse.RelatedObjects == (settings["product"],):
|
||||
history = inverse.OwnerHistory
|
||||
self.file.remove(inverse)
|
||||
file.remove(inverse)
|
||||
if history:
|
||||
ifcopenshell.util.element.remove_deep2(self.file, history)
|
||||
elif inverse.is_a("IfcRelConnectsPorts"):
|
||||
if self.settings["product"] not in (inverse.RelatingPort, inverse.RelatedPort):
|
||||
# if it's not RelatingPort/RelatedPort then it's optional RealizingElement
|
||||
# so we keep the relationship
|
||||
ifcopenshell.util.element.remove_deep2(file, history)
|
||||
elif inverse.is_a("IfcRelAggregates"):
|
||||
if inverse.RelatingObject == settings["product"] or len(inverse.RelatedObjects) == 1:
|
||||
history = inverse.OwnerHistory
|
||||
file.remove(inverse)
|
||||
if history:
|
||||
ifcopenshell.util.element.remove_deep2(file, history)
|
||||
elif inverse.is_a("IfcRelContainedInSpatialStructure"):
|
||||
if inverse.RelatingStructure == settings["product"] or len(inverse.RelatedElements) == 1:
|
||||
history = inverse.OwnerHistory
|
||||
file.remove(inverse)
|
||||
if history:
|
||||
ifcopenshell.util.element.remove_deep2(file, history)
|
||||
elif inverse.is_a("IfcRelConnectsElements"):
|
||||
if inverse.is_a("IfcRelConnectsWithRealizingElements"):
|
||||
if settings["product"] not in (inverse.RelatingElement, inverse.RelatedElement) and any(
|
||||
el for el in inverse.RealizingElements if el != settings["product"]
|
||||
):
|
||||
continue
|
||||
history = inverse.OwnerHistory
|
||||
file.remove(inverse)
|
||||
if history:
|
||||
ifcopenshell.util.element.remove_deep2(file, history)
|
||||
elif inverse.is_a("IfcRelConnectsPorts"):
|
||||
if settings["product"] not in (inverse.RelatingPort, inverse.RelatedPort):
|
||||
# if it's not RelatingPort/RelatedPort then it's optional RealizingElement
|
||||
# so we keep the relationship
|
||||
continue
|
||||
history = inverse.OwnerHistory
|
||||
file.remove(inverse)
|
||||
if history:
|
||||
ifcopenshell.util.element.remove_deep2(file, history)
|
||||
elif inverse.is_a("IfcRelAssignsToGroup"):
|
||||
if len(inverse.RelatedObjects) == 1:
|
||||
history = inverse.OwnerHistory
|
||||
self.file.remove(inverse)
|
||||
file.remove(inverse)
|
||||
if history:
|
||||
ifcopenshell.util.element.remove_deep2(self.file, history)
|
||||
elif inverse.is_a("IfcRelAssignsToGroup"):
|
||||
if len(inverse.RelatedObjects) == 1:
|
||||
history = inverse.OwnerHistory
|
||||
self.file.remove(inverse)
|
||||
if history:
|
||||
ifcopenshell.util.element.remove_deep2(self.file, history)
|
||||
elif inverse.is_a("IfcRelAssignsToProduct"):
|
||||
if inverse.RelatingProduct == self.settings["product"]:
|
||||
history = inverse.OwnerHistory
|
||||
self.file.remove(inverse)
|
||||
if history:
|
||||
ifcopenshell.util.element.remove_deep2(self.file, history)
|
||||
elif len(inverse.RelatedObjects) == 1:
|
||||
history = inverse.OwnerHistory
|
||||
self.file.remove(inverse)
|
||||
if history:
|
||||
ifcopenshell.util.element.remove_deep2(self.file, history)
|
||||
elif inverse.is_a("IfcRelFlowControlElements"):
|
||||
if inverse.RelatingFlowElement == self.settings["product"]:
|
||||
history = inverse.OwnerHistory
|
||||
self.file.remove(inverse)
|
||||
if history:
|
||||
ifcopenshell.util.element.remove_deep2(self.file, history)
|
||||
elif inverse.RelatedControlElements == (self.settings["product"],):
|
||||
history = inverse.OwnerHistory
|
||||
self.file.remove(inverse)
|
||||
if history:
|
||||
ifcopenshell.util.element.remove_deep2(self.file, history)
|
||||
history = self.settings["product"].OwnerHistory
|
||||
self.file.remove(self.settings["product"])
|
||||
if history:
|
||||
ifcopenshell.util.element.remove_deep2(self.file, history)
|
||||
ifcopenshell.util.element.remove_deep2(file, history)
|
||||
elif inverse.is_a("IfcRelAssignsToProduct"):
|
||||
if inverse.RelatingProduct == settings["product"]:
|
||||
history = inverse.OwnerHistory
|
||||
file.remove(inverse)
|
||||
if history:
|
||||
ifcopenshell.util.element.remove_deep2(file, history)
|
||||
elif len(inverse.RelatedObjects) == 1:
|
||||
history = inverse.OwnerHistory
|
||||
file.remove(inverse)
|
||||
if history:
|
||||
ifcopenshell.util.element.remove_deep2(file, history)
|
||||
elif inverse.is_a("IfcRelFlowControlElements"):
|
||||
if inverse.RelatingFlowElement == settings["product"]:
|
||||
history = inverse.OwnerHistory
|
||||
file.remove(inverse)
|
||||
if history:
|
||||
ifcopenshell.util.element.remove_deep2(file, history)
|
||||
elif inverse.RelatedControlElements == (settings["product"],):
|
||||
history = inverse.OwnerHistory
|
||||
file.remove(inverse)
|
||||
if history:
|
||||
ifcopenshell.util.element.remove_deep2(file, history)
|
||||
history = settings["product"].OwnerHistory
|
||||
file.remove(settings["product"])
|
||||
if history:
|
||||
ifcopenshell.util.element.remove_deep2(file, history)
|
||||
|
||||
Reference in New Issue
Block a user