This commit is contained in:
Andrej730
2025-03-14 10:43:47 +05:00
parent 10ecac33b8
commit 0e8810c1f5
118 changed files with 869 additions and 1203 deletions
@@ -22,7 +22,9 @@ import ifcopenshell.api.system
from typing import Optional
def add_port(file: ifcopenshell.file, element: Optional[ifcopenshell.entity_instance] = None) -> None:
def add_port(
file: ifcopenshell.file, element: Optional[ifcopenshell.entity_instance] = None
) -> ifcopenshell.entity_instance:
"""Adds a new distribution port to an element
A distribution port represents a connection point on an element, where
@@ -36,9 +38,7 @@ def add_port(file: ifcopenshell.file, element: Optional[ifcopenshell.entity_inst
:param element: The IfcDistributionElement you want to add a
distribution port to.
:type element: ifcopenshell.entity_instance, optional
:return: The newly created IfcDistributionPort
:rtype: ifcopenshell.entity_instance
Example:
@@ -52,11 +52,7 @@ def add_port(file: ifcopenshell.file, element: Optional[ifcopenshell.entity_inst
port1 = ifcopenshell.api.system.add_port(model, element=duct)
port2 = ifcopenshell.api.system.add_port(model, element=duct)
"""
settings = {
"element": element,
}
port = ifcopenshell.api.root.create_entity(file, ifc_class="IfcDistributionPort")
if settings["element"]:
ifcopenshell.api.system.assign_port(file, element=settings["element"], port=port)
if element:
ifcopenshell.api.system.assign_port(file, element=element, port=port)
return port
@@ -34,9 +34,7 @@ def add_system(file: ifcopenshell.file, ifc_class: str = "IfcDistributionSystem"
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:
@@ -45,9 +43,7 @@ def add_system(file: ifcopenshell.file, ifc_class: str = "IfcDistributionSystem"
# A completely empty distribution system
system = ifcopenshell.api.system.add_system(model)
"""
settings = {"ifc_class": ifc_class}
ifc_class = settings["ifc_class"]
ifc_class = ifc_class
# workaround for failing default argument in ifc2x3
if file.schema == "IFC2X3" and ifc_class == "IfcDistributionSystem":
ifc_class = "IfcSystem"
@@ -34,12 +34,9 @@ def assign_flow_control(
: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:
@@ -51,26 +48,21 @@ def 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,
}
if settings["related_flow_control"].AssignedToFlowElement:
if 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"]:
assignment = related_flow_control.AssignedToFlowElement[0]
if assignment.RelatingFlowElement == relating_flow_element:
return assignment
# return None if this control is already assigned to another flow element
return
if settings["relating_flow_element"].HasControlElements:
assignment = settings["relating_flow_element"].HasControlElements[0]
if settings["related_flow_control"] in assignment.RelatedControlElements:
if relating_flow_element.HasControlElements:
assignment = relating_flow_element.HasControlElements[0]
if related_flow_control in assignment.RelatedControlElements:
return assignment
related_flow_controls = set(assignment.RelatedControlElements)
related_flow_controls.add(settings["related_flow_control"])
related_flow_controls.add(related_flow_control)
assignment.RelatedControlElements = list(related_flow_controls)
ifcopenshell.api.owner.update_owner_history(file, **{"element": assignment})
return assignment
@@ -80,8 +72,8 @@ def assign_flow_control(
**{
"GlobalId": ifcopenshell.guid.new(),
"OwnerHistory": ifcopenshell.api.owner.create_owner_history(file),
"RelatedControlElements": [settings["related_flow_control"]],
"RelatingFlowElement": settings["relating_flow_element"],
"RelatedControlElements": [related_flow_control],
"RelatingFlowElement": relating_flow_element,
},
)
return assignment
@@ -34,12 +34,9 @@ def assign_port(
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:
@@ -61,31 +58,30 @@ def assign_port(
"""
usecase = Usecase()
usecase.file = file
usecase.settings = {
"element": element,
"port": port,
}
return usecase.execute()
return usecase.execute(element, port)
class Usecase:
file: ifcopenshell.file
settings: dict[str, Any]
def execute(self):
def execute(
self, element: ifcopenshell.entity_instance, port: ifcopenshell.entity_instance
) -> ifcopenshell.entity_instance:
self.element = element
self.port = port
if self.file.schema == "IFC2X3":
return self.execute_ifc2x3()
rels = self.settings["element"].IsNestedBy or []
rels = self.element.IsNestedBy or []
for rel in rels:
if self.settings["port"] in rel.RelatedObjects:
if self.port in rel.RelatedObjects:
return rel
if rels:
rel = rels[0]
related_objects = set(rel.RelatedObjects) or set()
related_objects.add(self.settings["port"])
related_objects.add(self.port)
rel.RelatedObjects = list(related_objects)
ifcopenshell.api.owner.update_owner_history(self.file, **{"element": rel})
else:
@@ -93,34 +89,34 @@ class Usecase:
"IfcRelNests",
GlobalId=ifcopenshell.guid.new(),
OwnerHistory=ifcopenshell.api.owner.create_owner_history(self.file),
RelatedObjects=[self.settings["port"]],
RelatingObject=self.settings["element"],
RelatedObjects=[self.port],
RelatingObject=self.element,
)
self.update_port_placement()
return rel
def execute_ifc2x3(self):
for rel in self.settings["element"].HasPorts or []:
if rel.RelatingPort == self.settings["port"]:
def execute_ifc2x3(self) -> ifcopenshell.entity_instance:
for rel in self.element.HasPorts or []:
if rel.RelatingPort == self.port:
return rel
rel = self.file.create_entity(
"IfcRelConnectsPortToElement",
GlobalId=ifcopenshell.guid.new(),
OwnerHistory=ifcopenshell.api.owner.create_owner_history(self.file),
RelatingPort=self.settings["port"],
RelatedElement=self.settings["element"],
RelatingPort=self.port,
RelatedElement=self.element,
)
self.update_port_placement()
return rel
def update_port_placement(self):
placement = getattr(self.settings["port"], "ObjectPlacement", None)
def update_port_placement(self) -> None:
placement = getattr(self.port, "ObjectPlacement", None)
if placement and placement.is_a("IfcLocalPlacement"):
ifcopenshell.api.geometry.edit_object_placement(
self.file,
product=self.settings["port"],
matrix=ifcopenshell.util.placement.get_local_placement(self.settings["port"].ObjectPlacement),
product=self.port,
matrix=ifcopenshell.util.placement.get_local_placement(self.port.ObjectPlacement),
is_si=False,
)
@@ -64,12 +64,8 @@ def disconnect_port(file: ifcopenshell.file, port: ifcopenshell.entity_instance)
# fitting_port1 instead of duct_port2
ifcopenshell.api.system.disconnect_port(model, port=duct_port2)
"""
settings = {
"port": port,
}
rels = settings["port"].ConnectedTo or ()
rels += settings["port"].ConnectedFrom or ()
rels = port.ConnectedTo or ()
rels += port.ConnectedFrom or ()
for rel in rels:
rel.RelatingPort.FlowDirection = None
@@ -27,9 +27,7 @@ def remove_system(file: ifcopenshell.file, system: ifcopenshell.entity_instance)
All the distribution elements within the system are retained.
:param system: The IfcSystem to remove.
:type system: ifcopenshell.entity_instance
:return: None
:rtype: None
Example:
@@ -41,9 +39,7 @@ def remove_system(file: ifcopenshell.file, system: ifcopenshell.entity_instance)
# Delete it.
ifcopenshell.api.system.remove_system(model, system=system)
"""
settings = {"system": system}
for inverse_id in [i.id() for i in file.get_inverse(settings["system"])]:
for inverse_id in [i.id() for i in file.get_inverse(system)]:
try:
inverse = file.by_id(inverse_id)
except:
@@ -51,11 +47,11 @@ def remove_system(file: ifcopenshell.file, system: ifcopenshell.entity_instance)
if inverse.is_a("IfcRelDefinesByProperties"):
ifcopenshell.api.pset.remove_pset(
file,
product=settings["system"],
product=system,
pset=inverse.RelatingPropertyDefinition,
)
elif inverse.is_a("IfcRelAssignsToGroup"):
if inverse.RelatingGroup == settings["system"]:
if inverse.RelatingGroup == system:
history = inverse.OwnerHistory
file.remove(inverse)
if history:
@@ -65,7 +61,7 @@ def remove_system(file: ifcopenshell.file, system: ifcopenshell.entity_instance)
file.remove(inverse)
if history:
ifcopenshell.util.element.remove_deep2(file, history)
history = settings["system"].OwnerHistory
file.remove(settings["system"])
history = system.OwnerHistory
file.remove(system)
if history:
ifcopenshell.util.element.remove_deep2(file, history)
@@ -30,11 +30,8 @@ def unassign_flow_control(
: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: None
:rtype: None
Example:
@@ -53,15 +50,10 @@ def unassign_flow_control(
)
"""
settings = {
"relating_flow_element": relating_flow_element,
"related_flow_control": related_flow_control,
}
if not settings["related_flow_control"].AssignedToFlowElement:
if not related_flow_control.AssignedToFlowElement:
return
assignment = settings["related_flow_control"].AssignedToFlowElement[0]
if assignment.RelatingFlowElement != settings["relating_flow_element"]:
assignment = related_flow_control.AssignedToFlowElement[0]
if assignment.RelatingFlowElement != relating_flow_element:
return
if len(assignment.RelatedControlElements) == 1:
history = assignment.OwnerHistory
@@ -70,6 +62,6 @@ def unassign_flow_control(
ifcopenshell.util.element.remove_deep2(file, history)
return
related_flow_controls = list(assignment.RelatedControlElements)
related_flow_controls.remove(settings["related_flow_control"])
related_flow_controls.remove(related_flow_control)
assignment.RelatedControlElements = related_flow_controls
ifcopenshell.api.owner.update_owner_history(file, **{"element": assignment})
@@ -19,7 +19,6 @@
import ifcopenshell
import ifcopenshell.api.owner
import ifcopenshell.util.element
from typing import Any
def unassign_port(
@@ -32,11 +31,8 @@ def unassign_port(
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:
@@ -55,23 +51,20 @@ def unassign_port(
"""
usecase = Usecase()
usecase.file = file
usecase.settings = {
"element": element,
"port": port,
}
return usecase.execute()
return usecase.execute(element, port)
class Usecase:
file: ifcopenshell.file
settings: dict[str, Any]
def execute(self):
def execute(self, element: ifcopenshell.entity_instance, port: ifcopenshell.entity_instance) -> None:
if self.file.schema == "IFC2X3":
self.element = element
self.port = port
return self.execute_ifc2x3()
for rel in self.settings["element"].IsNestedBy or []:
if self.settings["port"] in rel.RelatedObjects:
for rel in element.IsNestedBy or []:
if port in rel.RelatedObjects:
if len(rel.RelatedObjects) == 1:
history = rel.OwnerHistory
self.file.remove(rel)
@@ -79,13 +72,13 @@ class Usecase:
ifcopenshell.util.element.remove_deep2(self.file, history)
return
related_objects = set(rel.RelatedObjects) or set()
related_objects.remove(self.settings["port"])
related_objects.remove(port)
rel.RelatedObjects = list(related_objects)
ifcopenshell.api.owner.update_owner_history(self.file, **{"element": rel})
def execute_ifc2x3(self):
for rel in self.settings["element"].HasPorts or []:
if rel.RelatingPort == self.settings["port"]:
def execute_ifc2x3(self) -> None:
for rel in self.element.HasPorts or []:
if rel.RelatingPort == self.port:
history = rel.OwnerHistory
self.file.remove(rel)
if history: