mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-22 05:00:53 +00:00
system.assign_system - support batching #4474
This commit is contained in:
@@ -55,7 +55,7 @@ def disable_editing_system(system):
|
|||||||
|
|
||||||
|
|
||||||
def assign_system(ifc, system=None, product=None):
|
def assign_system(ifc, system=None, product=None):
|
||||||
ifc.run("system.assign_system", product=product, system=system)
|
ifc.run("system.assign_system", products=[product], system=system)
|
||||||
|
|
||||||
|
|
||||||
def unassign_system(ifc, system=None, product=None):
|
def unassign_system(ifc, system=None, product=None):
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ class TestDisableEditingSystem:
|
|||||||
|
|
||||||
class TestAssignSystem:
|
class TestAssignSystem:
|
||||||
def test_run(self, ifc):
|
def test_run(self, ifc):
|
||||||
ifc.run("system.assign_system", product="product", system="system").should_be_called()
|
ifc.run("system.assign_system", products=["product"], system="system").should_be_called()
|
||||||
subject.assign_system(ifc, system="system", product="product")
|
subject.assign_system(ifc, system="system", product="product")
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -262,7 +262,7 @@ class TestSelectSystemProducts(NewFile):
|
|||||||
tool.Ifc().set(ifc)
|
tool.Ifc().set(ifc)
|
||||||
element = ifcopenshell.api.run("root.create_entity", ifc, ifc_class="IfcPump")
|
element = ifcopenshell.api.run("root.create_entity", ifc, ifc_class="IfcPump")
|
||||||
system = ifcopenshell.api.run("system.add_system", ifc, ifc_class="IfcSystem")
|
system = ifcopenshell.api.run("system.add_system", ifc, ifc_class="IfcSystem")
|
||||||
ifcopenshell.api.run("system.assign_system", ifc, product=element, system=system)
|
ifcopenshell.api.run("system.assign_system", ifc, products=[element], system=system)
|
||||||
obj = bpy.data.objects.new("Object", None)
|
obj = bpy.data.objects.new("Object", None)
|
||||||
bpy.context.scene.collection.objects.link(obj)
|
bpy.context.scene.collection.objects.link(obj)
|
||||||
tool.Ifc.link(element, obj)
|
tool.Ifc.link(element, obj)
|
||||||
|
|||||||
@@ -79,6 +79,9 @@ ARGUMENTS_DEPRECATION = {
|
|||||||
"type.unassign_type": partial(
|
"type.unassign_type": partial(
|
||||||
batching_argument_deprecation, prev_argument="related_object", new_argument="related_objects"
|
batching_argument_deprecation, prev_argument="related_object", new_argument="related_objects"
|
||||||
),
|
),
|
||||||
|
"system.assign_system": partial(
|
||||||
|
batching_argument_deprecation, prev_argument="product", new_argument="products"
|
||||||
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
|
|
||||||
import ifcopenshell
|
import ifcopenshell
|
||||||
import ifcopenshell.api
|
import ifcopenshell.api
|
||||||
|
from typing import Union
|
||||||
|
|
||||||
|
|
||||||
class Usecase:
|
class Usecase:
|
||||||
@@ -34,7 +35,8 @@ class Usecase:
|
|||||||
:param group: The IfcGroup to assign the products to
|
:param group: The IfcGroup to assign the products to
|
||||||
:type group: ifcopenshell.entity_instance.entity_instance
|
:type group: ifcopenshell.entity_instance.entity_instance
|
||||||
:return: The IfcRelAssignsToGroup relationship
|
:return: The IfcRelAssignsToGroup relationship
|
||||||
:rtype: ifcopenshell.entity_instance.entity_instance
|
or `None` if `products` was empty list.
|
||||||
|
:rtype: Union[ifcopenshell.entity_instance.entity_instance, None]
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
@@ -50,7 +52,10 @@ class Usecase:
|
|||||||
"group": group,
|
"group": group,
|
||||||
}
|
}
|
||||||
|
|
||||||
def execute(self) -> ifcopenshell.entity_instance:
|
def execute(self) -> Union[ifcopenshell.entity_instance, None]:
|
||||||
|
if not self.settings["products"]:
|
||||||
|
return
|
||||||
|
|
||||||
if not self.settings["group"].IsGroupedBy:
|
if not self.settings["group"].IsGroupedBy:
|
||||||
return self.file.create_entity(
|
return self.file.create_entity(
|
||||||
"IfcRelAssignsToGroup",
|
"IfcRelAssignsToGroup",
|
||||||
|
|||||||
@@ -22,17 +22,23 @@ import ifcopenshell.util.system
|
|||||||
|
|
||||||
|
|
||||||
class Usecase:
|
class Usecase:
|
||||||
def __init__(self, file, product=None, system=None):
|
def __init__(
|
||||||
"""Assigns a distribution element to a system
|
self,
|
||||||
|
file: ifcopenshell.file,
|
||||||
|
products: list[ifcopenshell.entity_instance],
|
||||||
|
system: ifcopenshell.entity_instance,
|
||||||
|
):
|
||||||
|
"""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 product: The IfcDistributionElement to assign to the system.
|
:param products: The list of IfcDistributionElements to assign to the system.
|
||||||
:type product: ifcopenshell.entity_instance.entity_instance
|
:type products: list[ifcopenshell.entity_instance.entity_instance]
|
||||||
:param system: The IfcSystem you want to assign the element to.
|
:param system: The IfcSystem you want to assign the element to.
|
||||||
:type system: ifcopenshell.entity_instance.entity_instance
|
:type system: ifcopenshell.entity_instance.entity_instance
|
||||||
:return: The IfcRelAssignsToGroup relationship
|
:return: The IfcRelAssignsToGroup relationship
|
||||||
:rtype: ifcopenshell.entity_instance.entity_instance
|
or `None` if `products` was empty list.
|
||||||
|
:rtype: [ifcopenshell.entity_instance.entity_instance, None]
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
@@ -46,32 +52,20 @@ class Usecase:
|
|||||||
ifc_class="IfcDuctSegment", predefined_type="RIGIDSEGMENT")
|
ifc_class="IfcDuctSegment", predefined_type="RIGIDSEGMENT")
|
||||||
|
|
||||||
# This duct is part of the system
|
# This duct is part of the system
|
||||||
ifcopenshell.api.run("system.assign_system", model, product=duct, system=system)
|
ifcopenshell.api.run("system.assign_system", model, products=[duct], system=system)
|
||||||
"""
|
"""
|
||||||
self.file = file
|
self.file = file
|
||||||
self.settings = {
|
self.settings = {
|
||||||
"product": product,
|
"products": products,
|
||||||
"system": system,
|
"system": system,
|
||||||
}
|
}
|
||||||
|
|
||||||
def execute(self):
|
def execute(self):
|
||||||
system = self.settings["system"]
|
system = self.settings["system"]
|
||||||
product = self.settings["product"]
|
products = self.settings["products"]
|
||||||
if not ifcopenshell.util.system.is_assignable(product, system):
|
|
||||||
raise TypeError(f"You cannot assign an {product.is_a()} to an {system.is_a()}")
|
|
||||||
|
|
||||||
if not self.settings["system"].IsGroupedBy:
|
if not all(ifcopenshell.util.system.is_assignable(failed_product := product, system) for product in products):
|
||||||
return self.file.create_entity(
|
raise TypeError(f"You cannot assign an {failed_product.is_a()} to an {system.is_a()}")
|
||||||
"IfcRelAssignsToGroup",
|
|
||||||
**{
|
rel = ifcopenshell.api.run("group.assign_group", self.file, products=products, group=system)
|
||||||
"GlobalId": ifcopenshell.guid.new(),
|
return rel
|
||||||
"OwnerHistory": ifcopenshell.api.run("owner.create_owner_history", self.file),
|
|
||||||
"RelatedObjects": [self.settings["product"]],
|
|
||||||
"RelatingGroup": self.settings["system"],
|
|
||||||
},
|
|
||||||
)
|
|
||||||
rel = self.settings["system"].IsGroupedBy[0]
|
|
||||||
related_objects = set(rel.RelatedObjects) or set()
|
|
||||||
related_objects.add(self.settings["product"])
|
|
||||||
rel.RelatedObjects = list(related_objects)
|
|
||||||
ifcopenshell.api.run("owner.update_owner_history", self.file, **{"element": rel})
|
|
||||||
|
|||||||
@@ -77,8 +77,8 @@ class Usecase:
|
|||||||
ifc_class="IfcDuctFitting", predefined_type="BEND")
|
ifc_class="IfcDuctFitting", predefined_type="BEND")
|
||||||
|
|
||||||
# The duct and fitting is part of the system
|
# The duct and fitting is part of the system
|
||||||
ifcopenshell.api.run("system.assign_system", model, product=duct, system=system)
|
ifcopenshell.api.run("system.assign_system", model, products=[duct], system=system)
|
||||||
ifcopenshell.api.run("system.assign_system", model, product=fitting, 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.
|
# 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_port1 = ifcopenshell.api.run("system.add_port", model, element=duct)
|
||||||
|
|||||||
@@ -47,8 +47,8 @@ class Usecase:
|
|||||||
ifc_class="IfcDuctFitting", predefined_type="BEND")
|
ifc_class="IfcDuctFitting", predefined_type="BEND")
|
||||||
|
|
||||||
# The duct and fitting is part of the system
|
# The duct and fitting is part of the system
|
||||||
ifcopenshell.api.run("system.assign_system", model, product=duct, system=system)
|
ifcopenshell.api.run("system.assign_system", model, products=[duct], system=system)
|
||||||
ifcopenshell.api.run("system.assign_system", model, product=fitting, 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.
|
# 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_port1 = ifcopenshell.api.run("system.add_port", model, element=duct)
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ class Usecase:
|
|||||||
ifc_class="IfcDuctSegment", predefined_type="RIGIDSEGMENT")
|
ifc_class="IfcDuctSegment", predefined_type="RIGIDSEGMENT")
|
||||||
|
|
||||||
# This duct is part of the system
|
# This duct is part of the system
|
||||||
ifcopenshell.api.run("system.assign_system", model, product=duct, system=system)
|
ifcopenshell.api.run("system.assign_system", model, products=[duct], system=system)
|
||||||
|
|
||||||
# Not anymore!
|
# Not anymore!
|
||||||
ifcopenshell.api.run("system.unassign_system", model, product=duct, system=system)
|
ifcopenshell.api.run("system.unassign_system", model, product=duct, system=system)
|
||||||
|
|||||||
@@ -18,28 +18,30 @@
|
|||||||
|
|
||||||
import test.bootstrap
|
import test.bootstrap
|
||||||
import ifcopenshell.api
|
import ifcopenshell.api
|
||||||
|
import ifcopenshell.util.element
|
||||||
|
|
||||||
|
|
||||||
class TestAssignGroup(test.bootstrap.IFC4):
|
class TestAssignGroup(test.bootstrap.IFC4):
|
||||||
def test_assign_group_for_multiple_elements(self):
|
def test_assign_group_for_multiple_elements(self):
|
||||||
element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcPump")
|
element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall")
|
||||||
element2 = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcPump")
|
element2 = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall")
|
||||||
group = ifcopenshell.api.run("group.add_group", self.file)
|
group = ifcopenshell.api.run("group.add_group", self.file)
|
||||||
|
|
||||||
# assign group for multiple elements
|
# assign group for multiple elements
|
||||||
ifcopenshell.api.run("group.assign_group", self.file, products=[element, element2], group=group)
|
ifcopenshell.api.run("group.assign_group", self.file, products=[element, element2], group=group)
|
||||||
assert len(rels := self.file.by_type("IfcRelAssignsToGroup")) == 1
|
assert len(self.file.by_type("IfcRelAssignsToGroup")) == 1
|
||||||
rel = rels[0]
|
assert set(ifcopenshell.util.element.get_grouped_by(group)) == set(self.file.by_type("IfcWall"))
|
||||||
assert rel.RelatingGroup == group
|
|
||||||
assert rel.RelatedObjects == (element, element2)
|
|
||||||
|
|
||||||
def test_reuse_existing_relationship(self):
|
def test_reuse_existing_relationship(self):
|
||||||
self.test_assign_group_for_multiple_elements()
|
self.test_assign_group_for_multiple_elements()
|
||||||
rel = self.file.by_type("IfcRelAssignsToGroup")[0]
|
rel = self.file.by_type("IfcRelAssignsToGroup")[0]
|
||||||
element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcPump")
|
element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall")
|
||||||
group = self.file.by_type("IfcGroup")[0]
|
group = self.file.by_type("IfcGroup")[0]
|
||||||
ifcopenshell.api.run("group.assign_group", self.file, products=[element], group=group)
|
ifcopenshell.api.run("group.assign_group", self.file, products=[element], group=group)
|
||||||
|
|
||||||
assert len(self.file.by_type("IfcRelAssignsToGroup")) == 1
|
assert len(self.file.by_type("IfcRelAssignsToGroup")) == 1
|
||||||
assert rel.RelatingGroup == group
|
assert set(ifcopenshell.util.element.get_grouped_by(group)) == set(self.file.by_type("IfcWall"))
|
||||||
assert set(rel.RelatedObjects) == set(self.file.by_type("IfcPump"))
|
|
||||||
|
|
||||||
|
class TestAssignGroupIFC2X3(test.bootstrap.IFC2X3, TestAssignGroup):
|
||||||
|
pass
|
||||||
|
|||||||
@@ -0,0 +1,45 @@
|
|||||||
|
# IfcOpenShell - IFC toolkit and geometry engine
|
||||||
|
# Copyright (C) 2022 Dion Moult <dion@thinkmoult.com>
|
||||||
|
#
|
||||||
|
# This file is part of IfcOpenShell.
|
||||||
|
#
|
||||||
|
# IfcOpenShell is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# IfcOpenShell is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU Lesser General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Lesser General Public License
|
||||||
|
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
import test.bootstrap
|
||||||
|
import ifcopenshell.api
|
||||||
|
import ifcopenshell.util.system
|
||||||
|
|
||||||
|
|
||||||
|
class TestAssignSystem(test.bootstrap.IFC4):
|
||||||
|
def test_assign_system(self):
|
||||||
|
element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcFlowSegment")
|
||||||
|
element2 = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcFlowSegment")
|
||||||
|
system = ifcopenshell.api.run("system.add_system", self.file)
|
||||||
|
ifcopenshell.api.run("system.assign_system", self.file, products=[element, element2], system=system)
|
||||||
|
assert len(self.file.by_type("IfcRelAssignsToGroup")) == 1
|
||||||
|
assert set(ifcopenshell.util.system.get_system_elements(system)) == set(self.file.by_type("IfcFlowSegment"))
|
||||||
|
|
||||||
|
def test_exception_on_unassignable_elements(self):
|
||||||
|
element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcFlowSegment")
|
||||||
|
proj = self.file.createIfcProject()
|
||||||
|
system = ifcopenshell.api.run("system.add_system", self.file)
|
||||||
|
with pytest.raises(TypeError):
|
||||||
|
ifcopenshell.api.run("system.assign_system", self.file, products=[element, proj], system=system)
|
||||||
|
with pytest.raises(TypeError):
|
||||||
|
ifcopenshell.api.run("system.assign_system", self.file, products=[element], system=proj)
|
||||||
|
|
||||||
|
|
||||||
|
class TestAssignSystemIFC2X3(test.bootstrap.IFC2X3, TestAssignSystem):
|
||||||
|
pass
|
||||||
@@ -139,3 +139,15 @@ class TestTemporarySupportForDeprecatedAPIArguments(test.bootstrap.IFC4):
|
|||||||
ifcopenshell.api.run("type.assign_type", self.file, related_objects=[element], relating_type=element_type)
|
ifcopenshell.api.run("type.assign_type", self.file, related_objects=[element], relating_type=element_type)
|
||||||
ifcopenshell.api.run("type.unassign_type", self.file, related_object=element)
|
ifcopenshell.api.run("type.unassign_type", self.file, related_object=element)
|
||||||
assert ifcopenshell.util.element.get_type(element) is None
|
assert ifcopenshell.util.element.get_type(element) is None
|
||||||
|
|
||||||
|
@deprecation_check
|
||||||
|
def test_assign_system(self):
|
||||||
|
element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcPump")
|
||||||
|
system = ifcopenshell.api.run("system.add_system", self.file)
|
||||||
|
|
||||||
|
# assign group for multiple elements
|
||||||
|
ifcopenshell.api.run("system.assign_system", self.file, product=element, system=system)
|
||||||
|
assert len(rels := self.file.by_type("IfcRelAssignsToGroup")) == 1
|
||||||
|
rel = rels[0]
|
||||||
|
assert rel.RelatingGroup == system
|
||||||
|
assert rel.RelatedObjects == (element,)
|
||||||
|
|||||||
@@ -22,11 +22,21 @@ import ifcopenshell.api
|
|||||||
import ifcopenshell.util.system as subject
|
import ifcopenshell.util.system as subject
|
||||||
|
|
||||||
|
|
||||||
|
class TestIsAssignable(test.bootstrap.IFC4):
|
||||||
|
def test_run(self):
|
||||||
|
project = self.file.createIfcProject()
|
||||||
|
system = self.file.createIfcSystem()
|
||||||
|
pump = self.file.createIfcPump()
|
||||||
|
assert subject.is_assignable(pump, system)
|
||||||
|
assert not subject.is_assignable(project, system)
|
||||||
|
assert not subject.is_assignable(pump, project)
|
||||||
|
|
||||||
|
|
||||||
class TestGetSystemElements(test.bootstrap.IFC4):
|
class TestGetSystemElements(test.bootstrap.IFC4):
|
||||||
def test_run(self):
|
def test_run(self):
|
||||||
element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcPump")
|
element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcPump")
|
||||||
system = ifcopenshell.api.run("system.add_system", self.file, ifc_class="IfcSystem")
|
system = ifcopenshell.api.run("system.add_system", self.file, ifc_class="IfcSystem")
|
||||||
ifcopenshell.api.run("system.assign_system", self.file, product=element, system=system)
|
ifcopenshell.api.run("system.assign_system", self.file, products=[element], system=system)
|
||||||
assert subject.get_system_elements(system) == [element]
|
assert subject.get_system_elements(system) == [element]
|
||||||
|
|
||||||
|
|
||||||
@@ -34,7 +44,7 @@ class TestGetElementSystems(test.bootstrap.IFC4):
|
|||||||
def test_run(self):
|
def test_run(self):
|
||||||
element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcPump")
|
element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcPump")
|
||||||
system = ifcopenshell.api.run("system.add_system", self.file, ifc_class="IfcSystem")
|
system = ifcopenshell.api.run("system.add_system", self.file, ifc_class="IfcSystem")
|
||||||
ifcopenshell.api.run("system.assign_system", self.file, product=element, system=system)
|
ifcopenshell.api.run("system.assign_system", self.file, products=[element], system=system)
|
||||||
assert subject.get_element_systems(element) == [system]
|
assert subject.get_element_systems(element) == [system]
|
||||||
|
|
||||||
def test_do_not_get_non_services_groups(self):
|
def test_do_not_get_non_services_groups(self):
|
||||||
@@ -42,7 +52,7 @@ class TestGetElementSystems(test.bootstrap.IFC4):
|
|||||||
ifcopenshell.api.run(
|
ifcopenshell.api.run(
|
||||||
"system.assign_system",
|
"system.assign_system",
|
||||||
self.file,
|
self.file,
|
||||||
product=element,
|
products=[element],
|
||||||
system=self.file.createIfcGroup(),
|
system=self.file.createIfcGroup(),
|
||||||
)
|
)
|
||||||
for not_assignable_system_class in ("IfcZone", "IfcStructuralAnalysisModel"):
|
for not_assignable_system_class in ("IfcZone", "IfcStructuralAnalysisModel"):
|
||||||
@@ -50,7 +60,7 @@ class TestGetElementSystems(test.bootstrap.IFC4):
|
|||||||
ifcopenshell.api.run(
|
ifcopenshell.api.run(
|
||||||
"system.assign_system",
|
"system.assign_system",
|
||||||
self.file,
|
self.file,
|
||||||
product=element,
|
products=[element],
|
||||||
system=self.file.create_entity(not_assignable_system_class),
|
system=self.file.create_entity(not_assignable_system_class),
|
||||||
)
|
)
|
||||||
assert not subject.get_element_systems(element)
|
assert not subject.get_element_systems(element)
|
||||||
|
|||||||
Reference in New Issue
Block a user