mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-19 06:39:13 +00:00
You can now manage actor assignments to products
This commit is contained in:
@@ -28,6 +28,7 @@ classes = (
|
|||||||
operator.AddPersonAndOrganisation,
|
operator.AddPersonAndOrganisation,
|
||||||
operator.AddPersonAttribute,
|
operator.AddPersonAttribute,
|
||||||
operator.AddRole,
|
operator.AddRole,
|
||||||
|
operator.AssignActor,
|
||||||
operator.ClearUser,
|
operator.ClearUser,
|
||||||
operator.DisableEditingActor,
|
operator.DisableEditingActor,
|
||||||
operator.DisableEditingAddress,
|
operator.DisableEditingAddress,
|
||||||
@@ -53,11 +54,13 @@ classes = (
|
|||||||
operator.RemovePersonAttribute,
|
operator.RemovePersonAttribute,
|
||||||
operator.RemoveRole,
|
operator.RemoveRole,
|
||||||
operator.SetUser,
|
operator.SetUser,
|
||||||
|
operator.UnassignActor,
|
||||||
prop.BIMOwnerProperties,
|
prop.BIMOwnerProperties,
|
||||||
ui.BIM_PT_people,
|
ui.BIM_PT_people,
|
||||||
ui.BIM_PT_organisations,
|
ui.BIM_PT_organisations,
|
||||||
ui.BIM_PT_owner,
|
ui.BIM_PT_owner,
|
||||||
ui.BIM_PT_actor,
|
ui.BIM_PT_actor,
|
||||||
|
ui.BIM_PT_object_actor,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ def refresh():
|
|||||||
OrganisationsData.is_loaded = False
|
OrganisationsData.is_loaded = False
|
||||||
OwnerData.is_loaded = False
|
OwnerData.is_loaded = False
|
||||||
ActorData.is_loaded = False
|
ActorData.is_loaded = False
|
||||||
|
ObjectActorData.is_loaded = False
|
||||||
|
|
||||||
|
|
||||||
class RolesAddressesData:
|
class RolesAddressesData:
|
||||||
@@ -243,3 +244,46 @@ class ActorData:
|
|||||||
{"id": actor.id(), "name": actor.Name or "Unnamed", "the_actor": the_actor, "is_editing": is_editing}
|
{"id": actor.id(), "name": actor.Name or "Unnamed", "the_actor": the_actor, "is_editing": is_editing}
|
||||||
)
|
)
|
||||||
return actors
|
return actors
|
||||||
|
|
||||||
|
|
||||||
|
class ObjectActorData:
|
||||||
|
data = {}
|
||||||
|
is_loaded = False
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def load(cls):
|
||||||
|
cls.is_loaded = True
|
||||||
|
cls.data = {
|
||||||
|
"actor": cls.actor(),
|
||||||
|
"actors": cls.actors()
|
||||||
|
}
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def actor(cls):
|
||||||
|
return [(str(p.id()), p.Name or "Unnamed", "") for p in tool.Ifc.get().by_type("IfcActor")]
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def actors(cls):
|
||||||
|
results = []
|
||||||
|
element = tool.Ifc.get_entity(bpy.context.active_object)
|
||||||
|
if not element:
|
||||||
|
return results
|
||||||
|
for rel in getattr(element, "HasAssignments", []):
|
||||||
|
if rel.is_a("IfcRelAssignsToActor"):
|
||||||
|
actor = rel.RelatingActor
|
||||||
|
if actor.TheActor.is_a("IfcPerson"):
|
||||||
|
roles = cls.get_roles(actor.TheActor)
|
||||||
|
elif actor.TheActor.is_a("IfcOrganization"):
|
||||||
|
roles = cls.get_roles(actor.TheActor)
|
||||||
|
elif actor.TheActor.is_a("IfcPersonAndOrganization"):
|
||||||
|
roles = cls.get_roles(actor.TheActor.ThePerson)
|
||||||
|
roles.extend(cls.get_roles(actor.TheActor.TheOrganization))
|
||||||
|
role = ", ".join(roles)
|
||||||
|
results.append({
|
||||||
|
"id": actor.id(), "name": actor.Name or "Unnamed", "role": role, "ifc_class": actor.is_a()
|
||||||
|
})
|
||||||
|
return results
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_roles(cls, parent):
|
||||||
|
return [r.UserDefinedRole or r.Role for r in parent.Roles or []]
|
||||||
|
|||||||
@@ -355,3 +355,27 @@ class RemoveActor(bpy.types.Operator, Operator):
|
|||||||
|
|
||||||
def _execute(self, context):
|
def _execute(self, context):
|
||||||
core.remove_actor(tool.Ifc, actor=tool.Ifc.get().by_id(self.actor))
|
core.remove_actor(tool.Ifc, actor=tool.Ifc.get().by_id(self.actor))
|
||||||
|
|
||||||
|
|
||||||
|
class AssignActor(bpy.types.Operator, Operator):
|
||||||
|
bl_idname = "bim.assign_actor"
|
||||||
|
bl_label = "Assign Actor"
|
||||||
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
|
actor: bpy.props.IntProperty()
|
||||||
|
|
||||||
|
def _execute(self, context):
|
||||||
|
core.assign_actor(
|
||||||
|
tool.Ifc, actor=tool.Ifc.get().by_id(self.actor), element=tool.Ifc.get_entity(context.active_object)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class UnassignActor(bpy.types.Operator, Operator):
|
||||||
|
bl_idname = "bim.unassign_actor"
|
||||||
|
bl_label = "Unassign Actor"
|
||||||
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
|
actor: bpy.props.IntProperty()
|
||||||
|
|
||||||
|
def _execute(self, context):
|
||||||
|
core.unassign_actor(
|
||||||
|
tool.Ifc, actor=tool.Ifc.get().by_id(self.actor), element=tool.Ifc.get_entity(context.active_object)
|
||||||
|
)
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
|
|
||||||
import bpy
|
import bpy
|
||||||
from blenderbim.bim.prop import StrProperty, Attribute
|
from blenderbim.bim.prop import StrProperty, Attribute
|
||||||
from blenderbim.bim.module.owner.data import OwnerData, ActorData
|
from blenderbim.bim.module.owner.data import OwnerData, ActorData, ObjectActorData
|
||||||
from bpy.types import PropertyGroup
|
from bpy.types import PropertyGroup
|
||||||
from bpy.props import (
|
from bpy.props import (
|
||||||
PointerProperty,
|
PointerProperty,
|
||||||
@@ -50,6 +50,12 @@ def get_the_actor(self, context):
|
|||||||
return ActorData.data["the_actor"]
|
return ActorData.data["the_actor"]
|
||||||
|
|
||||||
|
|
||||||
|
def get_actor(self, context):
|
||||||
|
if not ObjectActorData.is_loaded:
|
||||||
|
ObjectActorData.load()
|
||||||
|
return ObjectActorData.data["actor"]
|
||||||
|
|
||||||
|
|
||||||
def update_actor_type(self, context):
|
def update_actor_type(self, context):
|
||||||
ActorData.data["the_actor"] = ActorData.the_actor()
|
ActorData.data["the_actor"] = ActorData.the_actor()
|
||||||
|
|
||||||
@@ -95,3 +101,4 @@ class BIMOwnerProperties(PropertyGroup):
|
|||||||
update=update_actor_type,
|
update=update_actor_type,
|
||||||
)
|
)
|
||||||
the_actor: EnumProperty(items=get_the_actor, name="Actor")
|
the_actor: EnumProperty(items=get_the_actor, name="Actor")
|
||||||
|
actor: EnumProperty(items=get_actor, name="Actor")
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
import bpy
|
import bpy
|
||||||
import blenderbim.bim.helper
|
import blenderbim.bim.helper
|
||||||
import blenderbim.tool as tool
|
import blenderbim.tool as tool
|
||||||
from blenderbim.bim.module.owner.data import PeopleData, OrganisationsData, OwnerData, ActorData
|
from blenderbim.bim.module.owner.data import PeopleData, OrganisationsData, OwnerData, ActorData, ObjectActorData
|
||||||
|
|
||||||
|
|
||||||
def draw_roles(box, parent):
|
def draw_roles(box, parent):
|
||||||
@@ -281,3 +281,38 @@ class BIM_PT_actor(bpy.types.Panel):
|
|||||||
row.label(text=actor["the_actor"])
|
row.label(text=actor["the_actor"])
|
||||||
row.operator("bim.enable_editing_actor", icon="GREASEPENCIL", text="").actor = actor["id"]
|
row.operator("bim.enable_editing_actor", icon="GREASEPENCIL", text="").actor = actor["id"]
|
||||||
row.operator("bim.remove_actor", icon="X", text="").actor = actor["id"]
|
row.operator("bim.remove_actor", icon="X", text="").actor = actor["id"]
|
||||||
|
|
||||||
|
|
||||||
|
class BIM_PT_object_actor(bpy.types.Panel):
|
||||||
|
bl_label = "IFC Actor"
|
||||||
|
bl_idname = "BIM_PT_object_actor"
|
||||||
|
bl_options = {"DEFAULT_CLOSED"}
|
||||||
|
bl_space_type = "PROPERTIES"
|
||||||
|
bl_region_type = "WINDOW"
|
||||||
|
bl_context = "object"
|
||||||
|
bl_parent_id = "BIM_PT_misc_object"
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def poll(cls, context):
|
||||||
|
return tool.Ifc.get()
|
||||||
|
|
||||||
|
def draw(self, context):
|
||||||
|
if not ObjectActorData.is_loaded:
|
||||||
|
ObjectActorData.load()
|
||||||
|
|
||||||
|
self.props = context.scene.BIMOwnerProperties
|
||||||
|
|
||||||
|
if not ObjectActorData.data["actor"]:
|
||||||
|
row = self.layout.row(align=True)
|
||||||
|
row.label(text="No Actors Found", icon="USER")
|
||||||
|
return
|
||||||
|
|
||||||
|
row = self.layout.row(align=True)
|
||||||
|
row.prop(self.props, "actor", text="")
|
||||||
|
row.operator("bim.assign_actor", icon="ADD", text="").actor = int(self.props.actor)
|
||||||
|
|
||||||
|
for actor in ObjectActorData.data["actors"]:
|
||||||
|
row = self.layout.row(align=True)
|
||||||
|
row.label(text=actor["name"], icon="USER")
|
||||||
|
row.label(text=actor["role"])
|
||||||
|
row.operator("bim.unassign_actor", icon="X", text="").actor = actor["id"]
|
||||||
|
|||||||
@@ -165,3 +165,11 @@ def disable_editing_actor(owner):
|
|||||||
def edit_actor(ifc, owner):
|
def edit_actor(ifc, owner):
|
||||||
ifc.run("owner.edit_actor", actor=owner.get_actor(), attributes=owner.export_actor_attributes())
|
ifc.run("owner.edit_actor", actor=owner.get_actor(), attributes=owner.export_actor_attributes())
|
||||||
disable_editing_actor(owner)
|
disable_editing_actor(owner)
|
||||||
|
|
||||||
|
|
||||||
|
def assign_actor(ifc, actor=None, element=None):
|
||||||
|
ifc.run("owner.assign_actor", relating_actor=actor, related_object=element)
|
||||||
|
|
||||||
|
|
||||||
|
def unassign_actor(ifc, actor=None, element=None):
|
||||||
|
ifc.run("owner.unassign_actor", relating_actor=actor, related_object=element)
|
||||||
|
|||||||
@@ -277,3 +277,30 @@ Scenario: Edit actor
|
|||||||
And I press "bim.enable_editing_actor(actor={actor})"
|
And I press "bim.enable_editing_actor(actor={actor})"
|
||||||
When I press "bim.edit_actor"
|
When I press "bim.edit_actor"
|
||||||
Then "scene.BIMOwnerProperties.active_actor_id" is "0"
|
Then "scene.BIMOwnerProperties.active_actor_id" is "0"
|
||||||
|
|
||||||
|
Scenario: Assign actor
|
||||||
|
Given an empty IFC project
|
||||||
|
And I press "bim.add_person"
|
||||||
|
And I press "bim.add_actor"
|
||||||
|
And I add a cube
|
||||||
|
And the object "Cube" is selected
|
||||||
|
And I set "scene.BIMRootProperties.ifc_class" to "IfcWall"
|
||||||
|
And I press "bim.assign_class"
|
||||||
|
And the variable "actor" is "{ifc}.by_type('IfcActor')[0].id()"
|
||||||
|
And the object "IfcWall/Cube" is selected
|
||||||
|
When I press "bim.assign_actor(actor={actor})"
|
||||||
|
Then nothing happens
|
||||||
|
|
||||||
|
Scenario: Unassign actor
|
||||||
|
Given an empty IFC project
|
||||||
|
And I press "bim.add_person"
|
||||||
|
And I press "bim.add_actor"
|
||||||
|
And I add a cube
|
||||||
|
And the object "Cube" is selected
|
||||||
|
And I set "scene.BIMRootProperties.ifc_class" to "IfcWall"
|
||||||
|
And I press "bim.assign_class"
|
||||||
|
And the variable "actor" is "{ifc}.by_type('IfcActor')[0].id()"
|
||||||
|
And the object "IfcWall/Cube" is selected
|
||||||
|
And I press "bim.assign_actor(actor={actor})"
|
||||||
|
When I press "bim.unassign_actor(actor={actor})"
|
||||||
|
Then nothing happens
|
||||||
|
|||||||
@@ -259,3 +259,15 @@ class TestEditActor:
|
|||||||
ifc.run("owner.edit_actor", actor="actor", attributes="attributes").should_be_called()
|
ifc.run("owner.edit_actor", actor="actor", attributes="attributes").should_be_called()
|
||||||
owner.clear_actor().should_be_called()
|
owner.clear_actor().should_be_called()
|
||||||
subject.edit_actor(ifc, owner)
|
subject.edit_actor(ifc, owner)
|
||||||
|
|
||||||
|
|
||||||
|
class TestAssignActor:
|
||||||
|
def test_run(self, ifc, owner):
|
||||||
|
ifc.run("owner.assign_actor", relating_actor="actor", related_object="element").should_be_called()
|
||||||
|
subject.assign_actor(ifc, actor="actor", element="element")
|
||||||
|
|
||||||
|
|
||||||
|
class TestUnassignActor:
|
||||||
|
def test_run(self, ifc, owner):
|
||||||
|
ifc.run("owner.unassign_actor", relating_actor="actor", related_object="element").should_be_called()
|
||||||
|
subject.unassign_actor(ifc, actor="actor", element="element")
|
||||||
|
|||||||
@@ -0,0 +1,59 @@
|
|||||||
|
# IfcOpenShell - IFC toolkit and geometry engine
|
||||||
|
# Copyright (C) 2021 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 ifcopenshell
|
||||||
|
import ifcopenshell.api
|
||||||
|
|
||||||
|
|
||||||
|
class Usecase:
|
||||||
|
def __init__(self, file, **settings):
|
||||||
|
self.file = file
|
||||||
|
self.settings = {
|
||||||
|
"relating_actor": None,
|
||||||
|
"related_object": None,
|
||||||
|
}
|
||||||
|
for key, value in settings.items():
|
||||||
|
self.settings[key] = value
|
||||||
|
|
||||||
|
def execute(self):
|
||||||
|
if self.settings["related_object"].HasAssignments:
|
||||||
|
for rel in self.settings["related_object"].HasAssignments:
|
||||||
|
if rel.is_a("IfcRelAssignsToActor") and rel.RelatingActor == self.settings["relating_actor"]:
|
||||||
|
return
|
||||||
|
|
||||||
|
rel = None
|
||||||
|
|
||||||
|
if self.settings["relating_actor"].IsActingUpon:
|
||||||
|
rel = self.settings["relating_actor"].IsActingUpon[0]
|
||||||
|
|
||||||
|
if rel:
|
||||||
|
related_objects = list(rel.RelatedObjects)
|
||||||
|
related_objects.append(self.settings["related_object"])
|
||||||
|
rel.RelatedObjects = related_objects
|
||||||
|
ifcopenshell.api.run("owner.update_owner_history", self.file, **{"element": rel})
|
||||||
|
else:
|
||||||
|
rel = self.file.create_entity(
|
||||||
|
"IfcRelAssignsToActor",
|
||||||
|
**{
|
||||||
|
"GlobalId": ifcopenshell.guid.new(),
|
||||||
|
"OwnerHistory": ifcopenshell.api.run("owner.create_owner_history", self.file),
|
||||||
|
"RelatedObjects": [self.settings["related_object"]],
|
||||||
|
"RelatingActor": self.settings["relating_actor"],
|
||||||
|
}
|
||||||
|
)
|
||||||
|
return rel
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
# IfcOpenShell - IFC toolkit and geometry engine
|
||||||
|
# Copyright (C) 2021 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 ifcopenshell
|
||||||
|
import ifcopenshell.api
|
||||||
|
|
||||||
|
|
||||||
|
class Usecase:
|
||||||
|
def __init__(self, file, **settings):
|
||||||
|
self.file = file
|
||||||
|
self.settings = {
|
||||||
|
"relating_actor": None,
|
||||||
|
"related_object": None,
|
||||||
|
}
|
||||||
|
for key, value in settings.items():
|
||||||
|
self.settings[key] = value
|
||||||
|
|
||||||
|
def execute(self):
|
||||||
|
for rel in self.settings["related_object"].HasAssignments or []:
|
||||||
|
if not rel.is_a("IfcRelAssignsToActor") or rel.RelatingActor != self.settings["relating_actor"]:
|
||||||
|
continue
|
||||||
|
if len(rel.RelatedObjects) == 1:
|
||||||
|
return self.file.remove(rel)
|
||||||
|
related_objects = list(rel.RelatedObjects)
|
||||||
|
related_objects.remove(self.settings["related_object"])
|
||||||
|
rel.RelatedObjects = related_objects
|
||||||
|
ifcopenshell.api.run("owner.update_owner_history", self.file, **{"element": rel})
|
||||||
|
return rel
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
# IfcOpenShell - IFC toolkit and geometry engine
|
||||||
|
# Copyright (C) 2021 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 test.bootstrap
|
||||||
|
import ifcopenshell.api
|
||||||
|
|
||||||
|
|
||||||
|
class TestAssignProduct(test.bootstrap.IFC4):
|
||||||
|
def test_assigning_an_actor(self):
|
||||||
|
wall = self.file.createIfcWall()
|
||||||
|
wall2 = self.file.createIfcWall()
|
||||||
|
actor = self.file.createIfcActor()
|
||||||
|
ifcopenshell.api.run("owner.assign_actor", self.file, relating_actor=actor, related_object=wall)
|
||||||
|
assert actor.IsActingUpon[0].RelatedObjects == (wall,)
|
||||||
|
ifcopenshell.api.run("owner.assign_actor", self.file, relating_actor=actor, related_object=wall2)
|
||||||
|
assert actor.IsActingUpon[0].RelatedObjects == (wall, wall2)
|
||||||
|
|
||||||
|
def test_not_assigning_twice(self):
|
||||||
|
wall = self.file.createIfcWall()
|
||||||
|
actor = self.file.createIfcActor()
|
||||||
|
ifcopenshell.api.run("owner.assign_actor", self.file, relating_actor=actor, related_object=wall)
|
||||||
|
ifcopenshell.api.run("owner.assign_actor", self.file, relating_actor=actor, related_object=wall)
|
||||||
|
assert actor.IsActingUpon[0].RelatedObjects == (wall,)
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
# IfcOpenShell - IFC toolkit and geometry engine
|
||||||
|
# Copyright (C) 2021 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 test.bootstrap
|
||||||
|
import ifcopenshell.api
|
||||||
|
|
||||||
|
|
||||||
|
class TestUnassignActor(test.bootstrap.IFC4):
|
||||||
|
def test_unassigning_an_actor(self):
|
||||||
|
wall = self.file.createIfcWall()
|
||||||
|
actor = self.file.createIfcActor()
|
||||||
|
ifcopenshell.api.run("owner.assign_actor", self.file, relating_actor=actor, related_object=wall)
|
||||||
|
ifcopenshell.api.run("owner.unassign_actor", self.file, relating_actor=actor, related_object=wall)
|
||||||
|
assert len(self.file.by_type("IfcRelAssignsToActor")) == 0
|
||||||
Reference in New Issue
Block a user