Generate functions for all API usecases for better static code features. See #2693.

This commit is contained in:
Dion Moult
2024-05-06 14:35:39 +10:00
parent 10f894e2ea
commit d11ec67129
330 changed files with 13283 additions and 13751 deletions
@@ -15,3 +15,16 @@
#
# 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_port import add_port
from .add_system import add_system
from .assign_flow_control import assign_flow_control
from .assign_port import assign_port
from .assign_system import assign_system
from .connect_port import connect_port
from .disconnect_port import disconnect_port
from .edit_system import edit_system
from .remove_system import remove_system
from .unassign_flow_control import unassign_flow_control
from .unassign_port import unassign_port
from .unassign_system import unassign_system
@@ -20,44 +20,41 @@ import ifcopenshell
import ifcopenshell.api
class Usecase:
def __init__(self, file, element=None):
"""Adds a new distribution port to an element
def add_port(file, element=None) -> None:
"""Adds a new distribution port to an element
A distribution port represents a connection point on an element, where
a distribution element may be connected to another distribution element.
For example, a duct segment will typically have two ports, one at either
end, because you can attach another segment or fitting to either end of
the duct segment.
A distribution port represents a connection point on an element, where
a distribution element may be connected to another distribution element.
For example, a duct segment will typically have two ports, one at either
end, because you can attach another segment or fitting to either end of
the duct segment.
This will both add a distribution port and automatically assign it to a
distribution element.
This will both add a distribution port and automatically assign it to a
distribution element.
:param element: The IfcDistributionElement you want to add a
distribution port to.
:type element: ifcopenshell.entity_instance
:return: The newly created IfcDistributionPort
:rtype: ifcopenshell.entity_instance
:param element: The IfcDistributionElement you want to add a
distribution port to.
:type element: ifcopenshell.entity_instance
:return: The newly created IfcDistributionPort
:rtype: ifcopenshell.entity_instance
Example:
Example:
.. code:: python
.. code:: python
# Create a duct
duct = ifcopenshell.api.run("root.create_entity", model,
ifc_class="IfcDuctSegment", predefined_type="RIGIDSEGMENT")
# Create a duct
duct = ifcopenshell.api.run("root.create_entity", model,
ifc_class="IfcDuctSegment", predefined_type="RIGIDSEGMENT")
# Create 2 ports, one for either end.
port1 = ifcopenshell.api.run("system.add_port", model, element=duct)
port2 = ifcopenshell.api.run("system.add_port", model, element=duct)
"""
self.file = file
self.settings = {
"element": element,
}
# Create 2 ports, one for either end.
port1 = ifcopenshell.api.run("system.add_port", model, element=duct)
port2 = ifcopenshell.api.run("system.add_port", model, element=duct)
"""
settings = {
"element": element,
}
def execute(self):
port = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcDistributionPort")
if self.settings["element"]:
ifcopenshell.api.run("system.assign_port", self.file, element=self.settings["element"], port=port)
return port
port = ifcopenshell.api.run("root.create_entity", file, ifc_class="IfcDistributionPort")
if settings["element"]:
ifcopenshell.api.run("system.assign_port", file, element=settings["element"], port=port)
return port
@@ -20,45 +20,42 @@ import ifcopenshell
import ifcopenshell.api
class Usecase:
def __init__(self, file: ifcopenshell.file, ifc_class: str = "IfcDistributionSystem"):
"""Add a new distribution system
def add_system(file: ifcopenshell.file, ifc_class: str = "IfcDistributionSystem") -> ifcopenshell.entity_instance:
"""Add a new distribution system
A distribution system is a group of distribution elements, like ducts,
pipes, pumps, filters, fans, and so on that distribute a medium (air,
liquid, or electricity) throughout a facility. Systems may be
hierarchical, with larger systems composed of smaller subsystems.
A distribution system is a group of distribution elements, like ducts,
pipes, pumps, filters, fans, and so on that distribute a medium (air,
liquid, or electricity) throughout a facility. Systems may be
hierarchical, with larger systems composed of smaller subsystems.
:param ifc_class: The type of system, chosen from IfcDistributionSystem
for mechanical, electrical, communications, plumbing, fire, or
security systems. Alternatively you may choose IfcBuildingSystem for
specialised building facade systems or similar. For IFC2X3, choose
IfcSystem.
:type ifc_class: str
:return: The newly created IfcSystem.
:rtype: ifcopenshell.entity_instance
:param ifc_class: The type of system, chosen from IfcDistributionSystem
for mechanical, electrical, communications, plumbing, fire, or
security systems. Alternatively you may choose IfcBuildingSystem for
specialised building facade systems or similar. For IFC2X3, choose
IfcSystem.
:type ifc_class: str
:return: The newly created IfcSystem.
:rtype: ifcopenshell.entity_instance
Example:
Example:
.. code:: python
.. code:: python
# A completely empty distribution system
system = ifcopenshell.api.run("system.add_system", model)
"""
self.file = file
self.settings = {"ifc_class": ifc_class}
# A completely empty distribution system
system = ifcopenshell.api.run("system.add_system", model)
"""
settings = {"ifc_class": ifc_class}
def execute(self) -> ifcopenshell.entity_instance:
ifc_class = self.settings["ifc_class"]
# workaround for failing default argument in ifc2x3
if self.file.schema == "IFC2X3" and ifc_class == "IfcDistributionSystem":
ifc_class = "IfcSystem"
ifc_class = settings["ifc_class"]
# workaround for failing default argument in ifc2x3
if file.schema == "IFC2X3" and ifc_class == "IfcDistributionSystem":
ifc_class = "IfcSystem"
return self.file.create_entity(
ifc_class,
**{
"GlobalId": ifcopenshell.guid.new(),
"OwnerHistory": ifcopenshell.api.run("owner.create_owner_history", self.file),
"Name": "Unnamed",
}
)
return file.create_entity(
ifc_class,
**{
"GlobalId": ifcopenshell.guid.new(),
"OwnerHistory": ifcopenshell.api.run("owner.create_owner_history", file),
"Name": "Unnamed",
}
)
@@ -20,66 +20,63 @@ import ifcopenshell
import ifcopenshell.api
class Usecase:
def __init__(self, file, relating_flow_element=None, related_flow_control=None):
"""Assigns to the flow element control element that either sense or control
some aspect of the flow element.
def assign_flow_control(file, relating_flow_element=None, related_flow_control=None) -> None:
"""Assigns to the flow element control element that either sense or control
some aspect of the flow element.
Note that control can be assigned only to the one flow element.
Note that control can be assigned only to the one flow element.
:param related_flow_control: IfcDistributionControlElement
which may be used to impart control on the flow element
:type related_flow_control: ifcopenshell.entity_instance
:param relating_flow_element: The IfcDistributionFlowElement that is being controlled / sensed
:type relating_flow_element: ifcopenshell.entity_instance
:return: Matching or newly created IfcRelFlowControlElements. If control
is already assigned to some other element method will return None.
:rtype: ifcopenshell.entity_instance, None
:param related_flow_control: IfcDistributionControlElement
which may be used to impart control on the flow element
:type related_flow_control: ifcopenshell.entity_instance
:param relating_flow_element: The IfcDistributionFlowElement that is being controlled / sensed
:type relating_flow_element: ifcopenshell.entity_instance
:return: Matching or newly created IfcRelFlowControlElements. If control
is already assigned to some other element method will return None.
:rtype: ifcopenshell.entity_instance, None
Example:
Example:
.. code:: python
.. code:: python
flow_element = model.createIfcFlowSegment()
flow_control = model.createIfcController()
relation = ifcopenshell.api.run(
"system.assign_flow_control", model,
related_flow_control=flow_control, relating_flow_element=flow_element
)
"""
self.file = file
self.settings = {
"relating_flow_element": relating_flow_element,
"related_flow_control": related_flow_control,
}
flow_element = model.createIfcFlowSegment()
flow_control = model.createIfcController()
relation = ifcopenshell.api.run(
"system.assign_flow_control", model,
related_flow_control=flow_control, relating_flow_element=flow_element
)
"""
settings = {
"relating_flow_element": relating_flow_element,
"related_flow_control": related_flow_control,
}
def execute(self):
if self.settings["related_flow_control"].AssignedToFlowElement:
# only 1 control per 1 flow element is possible
assignment = self.settings["related_flow_control"].AssignedToFlowElement[0]
if assignment.RelatingFlowElement == self.settings["relating_flow_element"]:
return assignment
# return None if this control is already assigned to another flow element
return
if settings["related_flow_control"].AssignedToFlowElement:
# only 1 control per 1 flow element is possible
assignment = settings["related_flow_control"].AssignedToFlowElement[0]
if assignment.RelatingFlowElement == settings["relating_flow_element"]:
return assignment
# return None if this control is already assigned to another flow element
return
if self.settings["relating_flow_element"].HasControlElements:
assignment = self.settings["relating_flow_element"].HasControlElements[0]
if self.settings["related_flow_control"] in assignment.RelatedControlElements:
return assignment
related_flow_controls = set(assignment.RelatedControlElements)
related_flow_controls.add(self.settings["related_flow_control"])
assignment.RelatedControlElements = list(related_flow_controls)
ifcopenshell.api.run("owner.update_owner_history", self.file, **{"element": assignment})
if settings["relating_flow_element"].HasControlElements:
assignment = settings["relating_flow_element"].HasControlElements[0]
if settings["related_flow_control"] in assignment.RelatedControlElements:
return assignment
assignment = self.file.create_entity(
"IfcRelFlowControlElements",
**{
"GlobalId": ifcopenshell.guid.new(),
"OwnerHistory": ifcopenshell.api.run("owner.create_owner_history", self.file),
"RelatedControlElements": [self.settings["related_flow_control"]],
"RelatingFlowElement": self.settings["relating_flow_element"],
},
)
related_flow_controls = set(assignment.RelatedControlElements)
related_flow_controls.add(settings["related_flow_control"])
assignment.RelatedControlElements = list(related_flow_controls)
ifcopenshell.api.run("owner.update_owner_history", file, **{"element": assignment})
return assignment
assignment = file.create_entity(
"IfcRelFlowControlElements",
**{
"GlobalId": ifcopenshell.guid.new(),
"OwnerHistory": ifcopenshell.api.run("owner.create_owner_history", file),
"RelatedControlElements": [settings["related_flow_control"]],
"RelatingFlowElement": settings["relating_flow_element"],
},
)
return assignment
@@ -21,46 +21,49 @@ import ifcopenshell.api
import ifcopenshell.util.placement
def assign_port(file, element=None, port=None) -> None:
"""Assigns a port to an element
If you have an orphaned port, you may assign it to a distribution
element using this function. Ports should typically not be orphaned, but
it may be useful when patching up models.
:param element: The IfcDistributionElement to assign the port to.
:type element: ifcopenshell.entity_instance
:param port: The IfcDistributionPort you want to assign.
:type port: ifcopenshell.entity_instance
:return: The IfcRelNests relationship, or the
IfcRelConnectsPortToElement for IFC2X3.
:rtype: ifcopenshell.entity_instance
Example:
.. code:: python
# Create a duct
duct = ifcopenshell.api.run("root.create_entity", model,
ifc_class="IfcDuctSegment", predefined_type="RIGIDSEGMENT")
# Create 2 ports, one for either end.
port1 = ifcopenshell.api.run("system.add_port", model, element=duct)
port2 = ifcopenshell.api.run("system.add_port", model, element=duct)
# Unassign one port for some weird reason.
ifcopenshell.api.run("system.unassign_port", model, element=duct, port=port1)
# Reassign it back
ifcopenshell.api.run("system.assign_port", model, element=duct, port=port1)
"""
usecase = Usecase()
usecase.file = file
usecase.settings = {
"element": element,
"port": port,
}
return usecase.execute()
class Usecase:
def __init__(self, file, element=None, port=None):
"""Assigns a port to an element
If you have an orphaned port, you may assign it to a distribution
element using this function. Ports should typically not be orphaned, but
it may be useful when patching up models.
:param element: The IfcDistributionElement to assign the port to.
:type element: ifcopenshell.entity_instance
:param port: The IfcDistributionPort you want to assign.
:type port: ifcopenshell.entity_instance
:return: The IfcRelNests relationship, or the
IfcRelConnectsPortToElement for IFC2X3.
:rtype: ifcopenshell.entity_instance
Example:
.. code:: python
# Create a duct
duct = ifcopenshell.api.run("root.create_entity", model,
ifc_class="IfcDuctSegment", predefined_type="RIGIDSEGMENT")
# Create 2 ports, one for either end.
port1 = ifcopenshell.api.run("system.add_port", model, element=duct)
port2 = ifcopenshell.api.run("system.add_port", model, element=duct)
# Unassign one port for some weird reason.
ifcopenshell.api.run("system.unassign_port", model, element=duct, port=port1)
# Reassign it back
ifcopenshell.api.run("system.assign_port", model, element=duct, port=port1)
"""
self.file = file
self.settings = {
"element": element,
"port": port,
}
def execute(self):
if self.file.schema == "IFC2X3":
return self.execute_ifc2x3()
@@ -21,51 +21,47 @@ import ifcopenshell.api
import ifcopenshell.util.system
class Usecase:
def __init__(
self,
file: ifcopenshell.file,
products: list[ifcopenshell.entity_instance],
system: ifcopenshell.entity_instance,
):
"""Assigns distribution elements to a system
def assign_system(
file: ifcopenshell.file,
products: list[ifcopenshell.entity_instance],
system: ifcopenshell.entity_instance,
) -> None:
"""Assigns distribution elements to a system
Note that it is not necessary to assign distribution ports to a system.
Note that it is not necessary to assign distribution ports to a system.
:param products: The list of IfcDistributionElements to assign to the system.
:type products: list[ifcopenshell.entity_instance]
:param system: The IfcSystem you want to assign the element to.
:type system: ifcopenshell.entity_instance
:return: The IfcRelAssignsToGroup relationship
or `None` if `products` was empty list.
:rtype: [ifcopenshell.entity_instance, None]
:param products: The list of IfcDistributionElements to assign to the system.
:type products: list[ifcopenshell.entity_instance]
:param system: The IfcSystem you want to assign the element to.
:type system: ifcopenshell.entity_instance
:return: The IfcRelAssignsToGroup relationship
or `None` if `products` was empty list.
:rtype: [ifcopenshell.entity_instance, None]
Example:
Example:
.. code:: python
.. code:: python
# A completely empty distribution system
system = ifcopenshell.api.run("system.add_system", model)
# A completely empty distribution system
system = ifcopenshell.api.run("system.add_system", model)
# Create a duct
duct = ifcopenshell.api.run("root.create_entity", model,
ifc_class="IfcDuctSegment", predefined_type="RIGIDSEGMENT")
# Create a duct
duct = ifcopenshell.api.run("root.create_entity", model,
ifc_class="IfcDuctSegment", predefined_type="RIGIDSEGMENT")
# This duct is part of the system
ifcopenshell.api.run("system.assign_system", model, products=[duct], system=system)
"""
self.file = file
self.settings = {
"products": products,
"system": system,
}
# This duct is part of the system
ifcopenshell.api.run("system.assign_system", model, products=[duct], system=system)
"""
settings = {
"products": products,
"system": system,
}
def execute(self):
system = self.settings["system"]
products = self.settings["products"]
system = settings["system"]
products = settings["products"]
if not all(ifcopenshell.util.system.is_assignable(failed_product := product, system) for product in products):
raise TypeError(f"You cannot assign an {failed_product.is_a()} to an {system.is_a()}")
if not all(ifcopenshell.util.system.is_assignable(failed_product := product, system) for product in products):
raise TypeError(f"You cannot assign an {failed_product.is_a()} to an {system.is_a()}")
rel = ifcopenshell.api.run("group.assign_group", self.file, products=products, group=system)
return rel
rel = ifcopenshell.api.run("group.assign_group", file, products=products, group=system)
return rel
@@ -21,84 +21,87 @@ import ifcopenshell.api
import ifcopenshell.util.element
def connect_port(file, port1=None, port2=None, direction="NOTDEFINED", element=None) -> None:
"""Connects two ports together
A distribution element (e.g. a duct) may be connected to another
distribution element (e.g. a fitting) by connecting a port at one of the
duct to a port at the same end of the fitting.
Ports may only have one connection, so you cannot have multiple things
connected to the same port. Nor can you have incompatible port
connections, such as an electrical port connected to an airflow port.
Port connectivity may be explicit or implicit. Explicit connections are
where the port connectivity is described for every single distribution
element in detail. For example, a duct segment would have port
connections to a duct fitting, which would have port connections to
another duct segment, all the way from a fan to an air terminal exactly
as constructed on site. Implicit connections only consider the key
distribution control elements (e.g. the fan and the terminal) and ignore
all of the details of the duct segments and fittings in between.
Generally, explicit connectivity is preferred for later detailed design,
and implicit connectivity is preferred for early phase design.
:param port1: The port of the first distribution element to connect.
:type port1: ifcopenshell.entity_instance
:param port2: The port of the second distribution element to connect.
:type port2: ifcopenshell.entity_instance
:param direction: The directionality of distribution flow through the
port connection. NOTDEFINED means that the direction has not yet
been determined. This is useful during preliminary system design.
SOURCE means that the flow is from the first element to the second
element. SINK means that the flow is from the second element to the
first element. SOURCEANDSINK means that flow is bi-directional
between the first and second element. SOURCEANDSINK is a relatively
rare scenario.
:type direction: str
:param element: Optionally set an element through which the port
connectivity is made, such as a segment or fitting. This is only to
be used for implicit port connectivity where the segments and
fittings are less important.
:type element: ifcopenshell.entity_instance
Example:
.. code:: python
# A completely empty distribution system
system = ifcopenshell.api.run("system.add_system", model)
# Create a duct and a 90 degree bend fitting
duct = ifcopenshell.api.run("root.create_entity", model,
ifc_class="IfcDuctSegment", predefined_type="RIGIDSEGMENT")
fitting = ifcopenshell.api.run("root.create_entity", model,
ifc_class="IfcDuctFitting", predefined_type="BEND")
# The duct and fitting is part of the system
ifcopenshell.api.run("system.assign_system", model, products=[duct], system=system)
ifcopenshell.api.run("system.assign_system", model, products=[fitting], system=system)
# Create 2 ports, one for either end of both the duct and fitting.
duct_port1 = ifcopenshell.api.run("system.add_port", model, element=duct)
duct_port2 = ifcopenshell.api.run("system.add_port", model, element=duct)
fitting_port1 = ifcopenshell.api.run("system.add_port", model, element=fitting)
fitting_port2 = ifcopenshell.api.run("system.add_port", model, element=fitting)
# Connect the duct and fitting together. At this point, we have not
# yet determined the direction of the flow, so we leave direction as
# NOTDEFINED.
ifcopenshell.api.run("system.connect_port", model, port1=duct_port2, port2=fitting_port1)
"""
usecase = Usecase()
usecase.file = file
usecase.settings = {
"port1": port1,
"port2": port2,
"direction": direction,
"element": element,
}
return usecase.execute()
class Usecase:
def __init__(self, file, port1=None, port2=None, direction="NOTDEFINED", element=None):
"""Connects two ports together
A distribution element (e.g. a duct) may be connected to another
distribution element (e.g. a fitting) by connecting a port at one of the
duct to a port at the same end of the fitting.
Ports may only have one connection, so you cannot have multiple things
connected to the same port. Nor can you have incompatible port
connections, such as an electrical port connected to an airflow port.
Port connectivity may be explicit or implicit. Explicit connections are
where the port connectivity is described for every single distribution
element in detail. For example, a duct segment would have port
connections to a duct fitting, which would have port connections to
another duct segment, all the way from a fan to an air terminal exactly
as constructed on site. Implicit connections only consider the key
distribution control elements (e.g. the fan and the terminal) and ignore
all of the details of the duct segments and fittings in between.
Generally, explicit connectivity is preferred for later detailed design,
and implicit connectivity is preferred for early phase design.
:param port1: The port of the first distribution element to connect.
:type port1: ifcopenshell.entity_instance
:param port2: The port of the second distribution element to connect.
:type port2: ifcopenshell.entity_instance
:param direction: The directionality of distribution flow through the
port connection. NOTDEFINED means that the direction has not yet
been determined. This is useful during preliminary system design.
SOURCE means that the flow is from the first element to the second
element. SINK means that the flow is from the second element to the
first element. SOURCEANDSINK means that flow is bi-directional
between the first and second element. SOURCEANDSINK is a relatively
rare scenario.
:type direction: str
:param element: Optionally set an element through which the port
connectivity is made, such as a segment or fitting. This is only to
be used for implicit port connectivity where the segments and
fittings are less important.
:type element: ifcopenshell.entity_instance
Example:
.. code:: python
# A completely empty distribution system
system = ifcopenshell.api.run("system.add_system", model)
# Create a duct and a 90 degree bend fitting
duct = ifcopenshell.api.run("root.create_entity", model,
ifc_class="IfcDuctSegment", predefined_type="RIGIDSEGMENT")
fitting = ifcopenshell.api.run("root.create_entity", model,
ifc_class="IfcDuctFitting", predefined_type="BEND")
# The duct and fitting is part of the system
ifcopenshell.api.run("system.assign_system", model, products=[duct], system=system)
ifcopenshell.api.run("system.assign_system", model, products=[fitting], system=system)
# Create 2 ports, one for either end of both the duct and fitting.
duct_port1 = ifcopenshell.api.run("system.add_port", model, element=duct)
duct_port2 = ifcopenshell.api.run("system.add_port", model, element=duct)
fitting_port1 = ifcopenshell.api.run("system.add_port", model, element=fitting)
fitting_port2 = ifcopenshell.api.run("system.add_port", model, element=fitting)
# Connect the duct and fitting together. At this point, we have not
# yet determined the direction of the flow, so we leave direction as
# NOTDEFINED.
ifcopenshell.api.run("system.connect_port", model, port1=duct_port2, port2=fitting_port1)
"""
self.file = file
self.settings = {
"port1": port1,
"port2": port2,
"direction": direction,
"element": element,
}
def execute(self):
# Note: there are a number of ambiguities with port connectivity. We
# assume system topology is represented by a directed graph. In other
@@ -21,63 +21,60 @@ import ifcopenshell.api
import ifcopenshell.util.element
class Usecase:
def __init__(self, file, port=None):
"""Disconnects a port from any other port
def disconnect_port(file, port=None) -> None:
"""Disconnects a port from any other port
A port may only be connected to one other port, so the other port is not
needed to be specified.
A port may only be connected to one other port, so the other port is not
needed to be specified.
:param port: The IfcDistributionPort to disconnect.
:type port: ifcopenshell.entity_instance
:return: None
:rtype: None
:param port: The IfcDistributionPort to disconnect.
:type port: ifcopenshell.entity_instance
:return: None
:rtype: None
Example:
Example:
.. code:: python
.. code:: python
# A completely empty distribution system
system = ifcopenshell.api.run("system.add_system", model)
# A completely empty distribution system
system = ifcopenshell.api.run("system.add_system", model)
# Create a duct and a 90 degree bend fitting
duct = ifcopenshell.api.run("root.create_entity", model,
ifc_class="IfcDuctSegment", predefined_type="RIGIDSEGMENT")
fitting = ifcopenshell.api.run("root.create_entity", model,
ifc_class="IfcDuctFitting", predefined_type="BEND")
# Create a duct and a 90 degree bend fitting
duct = ifcopenshell.api.run("root.create_entity", model,
ifc_class="IfcDuctSegment", predefined_type="RIGIDSEGMENT")
fitting = ifcopenshell.api.run("root.create_entity", model,
ifc_class="IfcDuctFitting", predefined_type="BEND")
# The duct and fitting is part of the system
ifcopenshell.api.run("system.assign_system", model, products=[duct], system=system)
ifcopenshell.api.run("system.assign_system", model, products=[fitting], system=system)
# The duct and fitting is part of the system
ifcopenshell.api.run("system.assign_system", model, products=[duct], system=system)
ifcopenshell.api.run("system.assign_system", model, products=[fitting], system=system)
# Create 2 ports, one for either end of both the duct and fitting.
duct_port1 = ifcopenshell.api.run("system.add_port", model, element=duct)
duct_port2 = ifcopenshell.api.run("system.add_port", model, element=duct)
fitting_port1 = ifcopenshell.api.run("system.add_port", model, element=fitting)
fitting_port2 = ifcopenshell.api.run("system.add_port", model, element=fitting)
# Create 2 ports, one for either end of both the duct and fitting.
duct_port1 = ifcopenshell.api.run("system.add_port", model, element=duct)
duct_port2 = ifcopenshell.api.run("system.add_port", model, element=duct)
fitting_port1 = ifcopenshell.api.run("system.add_port", model, element=fitting)
fitting_port2 = ifcopenshell.api.run("system.add_port", model, element=fitting)
# Connect the duct and fitting together. At this point, we have not
# yet determined the direction of the flow, so we leave direction as
# NOTDEFINED.
ifcopenshell.api.run("system.connect_port", model, port1=duct_port2, port2=fitting_port1)
# Connect the duct and fitting together. At this point, we have not
# yet determined the direction of the flow, so we leave direction as
# NOTDEFINED.
ifcopenshell.api.run("system.connect_port", model, port1=duct_port2, port2=fitting_port1)
# Disconnect the port. note we could've equally disconnected
# fitting_port1 instead of duct_port2
ifcopenshell.api.run("system.disconnect_port", model, port=duct_port2)
"""
self.file = file
self.settings = {
"port": port,
}
# Disconnect the port. note we could've equally disconnected
# fitting_port1 instead of duct_port2
ifcopenshell.api.run("system.disconnect_port", model, port=duct_port2)
"""
settings = {
"port": port,
}
def execute(self):
rels = self.settings["port"].ConnectedTo or ()
rels += self.settings["port"].ConnectedFrom or ()
rels = settings["port"].ConnectedTo or ()
rels += settings["port"].ConnectedFrom or ()
for rel in rels:
rel.RelatingPort.FlowDirection = None
rel.RelatedPort.FlowDirection = None
history = rel.OwnerHistory
self.file.remove(rel)
if history:
ifcopenshell.util.element.remove_deep2(self.file, history)
for rel in rels:
rel.RelatingPort.FlowDirection = None
rel.RelatedPort.FlowDirection = None
history = rel.OwnerHistory
file.remove(rel)
if history:
ifcopenshell.util.element.remove_deep2(file, history)
@@ -17,34 +17,31 @@
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
class Usecase:
def __init__(self, file, system=None, attributes=None):
"""Edits the attributes of an IfcSystem
def edit_system(file, system=None, attributes=None) -> None:
"""Edits the attributes of an IfcSystem
For more information about the attributes and data types of an
IfcSystem, consult the IFC documentation.
For more information about the attributes and data types of an
IfcSystem, consult the IFC documentation.
:param system: The IfcSystem entity you want to edit
:type system: ifcopenshell.entity_instance
:param attributes: a dictionary of attribute names and values.
:type attributes: dict, optional
:return: None
:rtype: None
:param system: The IfcSystem entity you want to edit
:type system: 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
# A completely empty distribution system
system = ifcopenshell.api.run("system.add_system", model)
# A completely empty distribution system
system = ifcopenshell.api.run("system.add_system", model)
# Change the name of the system to "HW" for Hot Water
ifcopenshell.api.run("system.edit_system", model, system=system, attributes={"Name": "HW"})
"""
# Change the name of the system to "HW" for Hot Water
ifcopenshell.api.run("system.edit_system", model, system=system, attributes={"Name": "HW"})
"""
self.file = file
self.settings = {"system": system, "attributes": attributes or {}}
settings = {"system": system, "attributes": attributes or {}}
def execute(self):
for name, value in self.settings["attributes"].items():
setattr(self.settings["system"], name, value)
for name, value in settings["attributes"].items():
setattr(settings["system"], name, value)
@@ -21,55 +21,52 @@ import ifcopenshell.api
import ifcopenshell.util.element
class Usecase:
def __init__(self, file, system=None):
"""Removes a distribution system
def remove_system(file, system=None) -> None:
"""Removes a distribution system
All the distribution elements within the system are retained.
All the distribution elements within the system are retained.
:param system: The IfcSystem to remove.
:type system: ifcopenshell.entity_instance
:return: None
:rtype: None
:param system: The IfcSystem to remove.
:type system: ifcopenshell.entity_instance
:return: None
:rtype: None
Example:
Example:
.. code:: python
.. code:: python
# A completely empty distribution system
system = ifcopenshell.api.run("system.add_system", model)
# A completely empty distribution system
system = ifcopenshell.api.run("system.add_system", model)
# Delete it.
ifcopenshell.api.run("system.remove_system", model, system=system)
"""
self.file = file
self.settings = {"system": system}
# Delete it.
ifcopenshell.api.run("system.remove_system", model, system=system)
"""
settings = {"system": system}
def execute(self):
for inverse_id in [i.id() for i in self.file.get_inverse(self.settings["system"])]:
try:
inverse = self.file.by_id(inverse_id)
except:
continue
if inverse.is_a("IfcRelDefinesByProperties"):
ifcopenshell.api.run(
"pset.remove_pset",
self.file,
product=self.settings["system"],
pset=inverse.RelatingPropertyDefinition,
)
elif inverse.is_a("IfcRelAssignsToGroup"):
if inverse.RelatingGroup == self.settings["system"]:
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)
history = self.settings["system"].OwnerHistory
self.file.remove(self.settings["system"])
if history:
ifcopenshell.util.element.remove_deep2(self.file, history)
for inverse_id in [i.id() for i in file.get_inverse(settings["system"])]:
try:
inverse = file.by_id(inverse_id)
except:
continue
if inverse.is_a("IfcRelDefinesByProperties"):
ifcopenshell.api.run(
"pset.remove_pset",
file,
product=settings["system"],
pset=inverse.RelatingPropertyDefinition,
)
elif inverse.is_a("IfcRelAssignsToGroup"):
if inverse.RelatingGroup == settings["system"]:
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)
history = settings["system"].OwnerHistory
file.remove(settings["system"])
if history:
ifcopenshell.util.element.remove_deep2(file, history)
@@ -21,57 +21,54 @@ import ifcopenshell.api
import ifcopenshell.util.element
class Usecase:
def __init__(self, file, relating_flow_element=None, related_flow_control=None):
"""Unassigns flow control element from the flow element.
def unassign_flow_control(file, relating_flow_element=None, related_flow_control=None) -> None:
"""Unassigns flow control element from the flow element.
:param related_flow_control: IfcDistributionControlElement controling the
flow element
:type related_flow_control: ifcopenshell.entity_instance
:param relating_flow_element: The IfcDistributionFlowElement that is being controlled
:type relating_flow_element: ifcopenshell.entity_instance
:return: If the control still is related to other objects, the
IfcRelFlowControlElements is returned, otherwise None.
:rtype: ifcopenshell.entity_instance, None
:param related_flow_control: IfcDistributionControlElement controling the
flow element
:type related_flow_control: ifcopenshell.entity_instance
:param relating_flow_element: The IfcDistributionFlowElement that is being controlled
:type relating_flow_element: ifcopenshell.entity_instance
:return: If the control still is related to other objects, the
IfcRelFlowControlElements is returned, otherwise None.
:rtype: ifcopenshell.entity_instance, None
Example:
Example:
.. code:: python
.. code:: python
# assign control to the flow element
flow_element = self.file.createIfcFlowSegment()
flow_control = self.file.createIfcController()
relation = ifcopenshell.api.run(
"system.assign_flow_control", self.file,
relating_control=flow_control, related_object=flow_element
)
# assign control to the flow element
flow_element = file.createIfcFlowSegment()
flow_control = file.createIfcController()
relation = ifcopenshell.api.run(
"system.assign_flow_control", file,
relating_control=flow_control, related_object=flow_element
)
# und unassign it
ifcopenshell.api.run("system.unassign_flow_control", self.file,
relating_control=flow_control, related_object=flow_element
)
"""
# und unassign it
ifcopenshell.api.run("system.unassign_flow_control", file,
relating_control=flow_control, related_object=flow_element
)
"""
self.file = file
self.settings = {
"relating_flow_element": relating_flow_element,
"related_flow_control": related_flow_control,
}
settings = {
"relating_flow_element": relating_flow_element,
"related_flow_control": related_flow_control,
}
def execute(self):
if not self.settings["related_flow_control"].AssignedToFlowElement:
return
assignment = self.settings["related_flow_control"].AssignedToFlowElement[0]
if assignment.RelatingFlowElement != self.settings["relating_flow_element"]:
return
if len(assignment.RelatedControlElements) == 1:
history = assignment.OwnerHistory
self.file.remove(assignment)
if history:
ifcopenshell.util.element.remove_deep2(self.file, history)
return
related_flow_controls = list(assignment.RelatedControlElements)
related_flow_controls.remove(self.settings["related_flow_control"])
assignment.RelatedControlElements = related_flow_controls
ifcopenshell.api.run("owner.update_owner_history", self.file, **{"element": assignment})
return assignment
if not settings["related_flow_control"].AssignedToFlowElement:
return
assignment = settings["related_flow_control"].AssignedToFlowElement[0]
if assignment.RelatingFlowElement != settings["relating_flow_element"]:
return
if len(assignment.RelatedControlElements) == 1:
history = assignment.OwnerHistory
file.remove(assignment)
if history:
ifcopenshell.util.element.remove_deep2(file, history)
return
related_flow_controls = list(assignment.RelatedControlElements)
related_flow_controls.remove(settings["related_flow_control"])
assignment.RelatedControlElements = related_flow_controls
ifcopenshell.api.run("owner.update_owner_history", file, **{"element": assignment})
return assignment
@@ -20,42 +20,45 @@ import ifcopenshell
import ifcopenshell.api
def unassign_port(file, element=None, port=None) -> None:
"""Unassigns a port to an element
Ports are typically always assigned to a distribution element, but in
some edge cases you may want to unassign the port to create an orphaned
port for cleaning or patchin purposes.
:param element: The IfcDistributionElement to unassign the port from.
:type element: ifcopenshell.entity_instance
:param port: The IfcDistributionPort you want to unassign.
:type port: ifcopenshell.entity_instance
:return: None
:rtype: None
Example:
.. code:: python
# Create a duct
duct = ifcopenshell.api.run("root.create_entity", model,
ifc_class="IfcDuctSegment", predefined_type="RIGIDSEGMENT")
# Create 2 ports, one for either end.
port1 = ifcopenshell.api.run("system.add_port", model, element=duct)
port2 = ifcopenshell.api.run("system.add_port", model, element=duct)
# Unassign one port for some weird reason.
ifcopenshell.api.run("system.unassign_port", model, element=duct, port=port1)
"""
usecase = Usecase()
usecase.file = file
usecase.settings = {
"element": element,
"port": port,
}
return usecase.execute()
class Usecase:
def __init__(self, file, element=None, port=None):
"""Unassigns a port to an element
Ports are typically always assigned to a distribution element, but in
some edge cases you may want to unassign the port to create an orphaned
port for cleaning or patchin purposes.
:param element: The IfcDistributionElement to unassign the port from.
:type element: ifcopenshell.entity_instance
:param port: The IfcDistributionPort you want to unassign.
:type port: ifcopenshell.entity_instance
:return: None
:rtype: None
Example:
.. code:: python
# Create a duct
duct = ifcopenshell.api.run("root.create_entity", model,
ifc_class="IfcDuctSegment", predefined_type="RIGIDSEGMENT")
# Create 2 ports, one for either end.
port1 = ifcopenshell.api.run("system.add_port", model, element=duct)
port2 = ifcopenshell.api.run("system.add_port", model, element=duct)
# Unassign one port for some weird reason.
ifcopenshell.api.run("system.unassign_port", model, element=duct, port=port1)
"""
self.file = file
self.settings = {
"element": element,
"port": port,
}
def execute(self):
if self.file.schema == "IFC2X3":
return self.execute_ifc2x3()
@@ -21,46 +21,40 @@ import ifcopenshell.api
import ifcopenshell.util.element
class Usecase:
def __init__(
self,
file: ifcopenshell.file,
products: list[ifcopenshell.entity_instance],
system: ifcopenshell.entity_instance,
):
"""Unassigns list of products from a system
def unassign_system(
file: ifcopenshell.file,
products: list[ifcopenshell.entity_instance],
system: ifcopenshell.entity_instance,
) -> None:
"""Unassigns list of products from a system
:param products: The list of IfcDistributionElements to unassign from the system.
:type products: list[ifcopenshell.entity_instance]
:param system: The IfcSystem you want to unassign the element from.
:type system: ifcopenshell.entity_instance
:return: None
:rtype: None
:param products: The list of IfcDistributionElements to unassign from the system.
:type products: list[ifcopenshell.entity_instance]
:param system: The IfcSystem you want to unassign the element from.
:type system: ifcopenshell.entity_instance
:return: None
:rtype: None
Example:
Example:
.. code:: python
.. code:: python
# A completely empty distribution system
system = ifcopenshell.api.run("system.add_system", model)
# A completely empty distribution system
system = ifcopenshell.api.run("system.add_system", model)
# Create a duct
duct = ifcopenshell.api.run("root.create_entity", model,
ifc_class="IfcDuctSegment", predefined_type="RIGIDSEGMENT")
# Create a duct
duct = ifcopenshell.api.run("root.create_entity", model,
ifc_class="IfcDuctSegment", predefined_type="RIGIDSEGMENT")
# This duct is part of the system
ifcopenshell.api.run("system.assign_system", model, products=[duct], system=system)
# This duct is part of the system
ifcopenshell.api.run("system.assign_system", model, products=[duct], system=system)
# Not anymore!
ifcopenshell.api.run("system.unassign_system", model, products=[duct], system=system)
"""
self.file = file
self.settings = {
"products": products,
"system": system,
}
# Not anymore!
ifcopenshell.api.run("system.unassign_system", model, products=[duct], system=system)
"""
settings = {
"products": products,
"system": system,
}
def execute(self):
ifcopenshell.api.run(
"group.unassign_group", self.file, products=self.settings["products"], group=self.settings["system"]
)
ifcopenshell.api.run("group.unassign_group", file, products=settings["products"], group=settings["system"])