mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-27 02:31:09 +00:00
Fix #1576. Managing IfcSystem subtypes is now possible.
This commit is contained in:
@@ -20,17 +20,16 @@ import bpy
|
|||||||
from . import ui, prop, operator
|
from . import ui, prop, operator
|
||||||
|
|
||||||
classes = (
|
classes = (
|
||||||
operator.LoadSystems,
|
|
||||||
operator.DisableSystemEditingUI,
|
|
||||||
operator.AddSystem,
|
operator.AddSystem,
|
||||||
operator.EditSystem,
|
|
||||||
operator.RemoveSystem,
|
|
||||||
operator.ToggleAssigningSystem,
|
|
||||||
operator.AssignSystem,
|
operator.AssignSystem,
|
||||||
operator.UnassignSystem,
|
|
||||||
operator.EnableEditingSystem,
|
|
||||||
operator.DisableEditingSystem,
|
operator.DisableEditingSystem,
|
||||||
|
operator.DisableSystemEditingUI,
|
||||||
|
operator.EditSystem,
|
||||||
|
operator.EnableEditingSystem,
|
||||||
|
operator.LoadSystems,
|
||||||
|
operator.RemoveSystem,
|
||||||
operator.SelectSystemProducts,
|
operator.SelectSystemProducts,
|
||||||
|
operator.UnassignSystem,
|
||||||
prop.System,
|
prop.System,
|
||||||
prop.BIMSystemProperties,
|
prop.BIMSystemProperties,
|
||||||
ui.BIM_PT_systems,
|
ui.BIM_PT_systems,
|
||||||
|
|||||||
@@ -0,0 +1,82 @@
|
|||||||
|
# BlenderBIM Add-on - OpenBIM Blender Add-on
|
||||||
|
# Copyright (C) 2022 Dion Moult <dion@thinkmoult.com>
|
||||||
|
#
|
||||||
|
# This file is part of BlenderBIM Add-on.
|
||||||
|
#
|
||||||
|
# BlenderBIM Add-on is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# BlenderBIM Add-on 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 General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import bpy
|
||||||
|
import ifcopenshell
|
||||||
|
import ifcopenshell.util.schema
|
||||||
|
import blenderbim.tool as tool
|
||||||
|
|
||||||
|
|
||||||
|
def refresh():
|
||||||
|
SystemData.is_loaded = False
|
||||||
|
ObjectSystemData.is_loaded = False
|
||||||
|
|
||||||
|
|
||||||
|
class SystemData:
|
||||||
|
data = {}
|
||||||
|
is_loaded = False
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def load(cls):
|
||||||
|
cls.data = {
|
||||||
|
"system_class": cls.system_class(),
|
||||||
|
"total_systems": cls.total_systems(),
|
||||||
|
}
|
||||||
|
cls.is_loaded = True
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def system_class(cls):
|
||||||
|
declaration = tool.Ifc.schema().declaration_by_name("IfcSystem")
|
||||||
|
declarations = ifcopenshell.util.schema.get_subtypes(declaration)
|
||||||
|
# We're only interested in systems for services. Not sure why IFC groups these together.
|
||||||
|
return [
|
||||||
|
(c, c, "")
|
||||||
|
for c in sorted([d.name() for d in declarations])
|
||||||
|
if c not in ("IfcZone", "IfcStructuralAnalysisModel")
|
||||||
|
]
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def total_systems(cls):
|
||||||
|
return len(tool.Ifc.get().by_type("IfcSystem"))
|
||||||
|
|
||||||
|
|
||||||
|
class ObjectSystemData:
|
||||||
|
data = {}
|
||||||
|
is_loaded = False
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def load(cls):
|
||||||
|
cls.data = {
|
||||||
|
"systems": cls.systems(),
|
||||||
|
"total_systems": cls.total_systems(),
|
||||||
|
}
|
||||||
|
cls.is_loaded = True
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def systems(cls):
|
||||||
|
results = []
|
||||||
|
element = tool.Ifc.get_entity(bpy.context.active_object)
|
||||||
|
if not element:
|
||||||
|
return results
|
||||||
|
for system in ifcopenshell.util.system.get_element_systems(element):
|
||||||
|
results.append({"id": system.id(), "name": system.Name or "Unnamed", "ifc_class": system.is_a()})
|
||||||
|
return results
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def total_systems(cls):
|
||||||
|
return len(tool.Ifc.get().by_type("IfcSystem"))
|
||||||
@@ -17,208 +17,118 @@
|
|||||||
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
|
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import bpy
|
import bpy
|
||||||
import ifcopenshell.util.attribute
|
|
||||||
import ifcopenshell.api
|
import ifcopenshell.api
|
||||||
import blenderbim.bim.helper
|
import blenderbim.tool as tool
|
||||||
|
import blenderbim.core.system as core
|
||||||
|
import blenderbim.bim.handler
|
||||||
from blenderbim.bim.ifc import IfcStore
|
from blenderbim.bim.ifc import IfcStore
|
||||||
from ifcopenshell.api.system.data import Data
|
|
||||||
|
|
||||||
|
|
||||||
class LoadSystems(bpy.types.Operator):
|
class Operator:
|
||||||
|
def execute(self, context):
|
||||||
|
IfcStore.execute_ifc_operator(self, context)
|
||||||
|
blenderbim.bim.handler.refresh_ui_data()
|
||||||
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
|
class LoadSystems(bpy.types.Operator, Operator):
|
||||||
bl_idname = "bim.load_systems"
|
bl_idname = "bim.load_systems"
|
||||||
bl_label = "Load Systems"
|
bl_label = "Load Systems"
|
||||||
bl_options = {"REGISTER", "UNDO"}
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
|
|
||||||
def execute(self, context):
|
def _execute(self, context):
|
||||||
props = context.scene.BIMSystemProperties
|
core.load_systems(tool.System)
|
||||||
props.systems.clear()
|
|
||||||
for ifc_definition_id, system in Data.systems.items():
|
|
||||||
new = props.systems.add()
|
|
||||||
new.ifc_definition_id = ifc_definition_id
|
|
||||||
new.name = system["Name"]
|
|
||||||
props.is_editing = True
|
|
||||||
bpy.ops.bim.disable_editing_system()
|
|
||||||
return {"FINISHED"}
|
|
||||||
|
|
||||||
|
|
||||||
class DisableSystemEditingUI(bpy.types.Operator):
|
class DisableSystemEditingUI(bpy.types.Operator, Operator):
|
||||||
bl_idname = "bim.disable_system_editing_ui"
|
bl_idname = "bim.disable_system_editing_ui"
|
||||||
bl_label = "Disable System Editing UI"
|
bl_label = "Disable System Editing UI"
|
||||||
bl_options = {"REGISTER", "UNDO"}
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
|
|
||||||
def execute(self, context):
|
def _execute(self, context):
|
||||||
context.scene.BIMSystemProperties.is_editing = False
|
core.disable_system_editing_ui(tool.System)
|
||||||
context.scene.BIMSystemProperties.active_system_id = 0
|
|
||||||
return {"FINISHED"}
|
|
||||||
|
|
||||||
|
|
||||||
class AddSystem(bpy.types.Operator):
|
class AddSystem(bpy.types.Operator, Operator):
|
||||||
bl_idname = "bim.add_system"
|
bl_idname = "bim.add_system"
|
||||||
bl_label = "Add System"
|
bl_label = "Add System"
|
||||||
bl_options = {"REGISTER", "UNDO"}
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
|
|
||||||
def execute(self, context):
|
|
||||||
return IfcStore.execute_ifc_operator(self, context)
|
|
||||||
|
|
||||||
def _execute(self, context):
|
def _execute(self, context):
|
||||||
result = ifcopenshell.api.run("system.add_system", IfcStore.get_file())
|
core.add_system(tool.Ifc, tool.System, ifc_class=context.scene.BIMSystemProperties.system_class)
|
||||||
Data.load(IfcStore.get_file())
|
|
||||||
bpy.ops.bim.load_systems()
|
|
||||||
bpy.ops.bim.enable_editing_system(system=result.id())
|
|
||||||
return {"FINISHED"}
|
|
||||||
|
|
||||||
|
|
||||||
class EditSystem(bpy.types.Operator):
|
class EditSystem(bpy.types.Operator, Operator):
|
||||||
bl_idname = "bim.edit_system"
|
bl_idname = "bim.edit_system"
|
||||||
bl_label = "Edit System"
|
bl_label = "Edit System"
|
||||||
bl_options = {"REGISTER", "UNDO"}
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
|
|
||||||
def execute(self, context):
|
|
||||||
return IfcStore.execute_ifc_operator(self, context)
|
|
||||||
|
|
||||||
def _execute(self, context):
|
def _execute(self, context):
|
||||||
props = context.scene.BIMSystemProperties
|
core.edit_system(
|
||||||
attributes = {}
|
tool.Ifc, tool.System, system=tool.Ifc.get().by_id(context.scene.BIMSystemProperties.active_system_id)
|
||||||
for attribute in props.system_attributes:
|
|
||||||
if attribute.is_null:
|
|
||||||
attributes[attribute.name] = None
|
|
||||||
else:
|
|
||||||
attributes[attribute.name] = attribute.string_value
|
|
||||||
self.file = IfcStore.get_file()
|
|
||||||
ifcopenshell.api.run(
|
|
||||||
"system.edit_system",
|
|
||||||
self.file,
|
|
||||||
**{"system": self.file.by_id(props.active_system_id), "attributes": attributes}
|
|
||||||
)
|
)
|
||||||
Data.load(IfcStore.get_file())
|
|
||||||
bpy.ops.bim.load_systems()
|
|
||||||
return {"FINISHED"}
|
|
||||||
|
|
||||||
|
|
||||||
class RemoveSystem(bpy.types.Operator):
|
class RemoveSystem(bpy.types.Operator, Operator):
|
||||||
bl_idname = "bim.remove_system"
|
bl_idname = "bim.remove_system"
|
||||||
bl_label = "Remove System"
|
bl_label = "Remove System"
|
||||||
bl_options = {"REGISTER", "UNDO"}
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
system: bpy.props.IntProperty()
|
system: bpy.props.IntProperty()
|
||||||
|
|
||||||
def execute(self, context):
|
|
||||||
return IfcStore.execute_ifc_operator(self, context)
|
|
||||||
|
|
||||||
def _execute(self, context):
|
def _execute(self, context):
|
||||||
props = context.scene.BIMSystemProperties
|
core.remove_system(tool.Ifc, tool.System, system=tool.Ifc.get().by_id(self.system))
|
||||||
self.file = IfcStore.get_file()
|
|
||||||
ifcopenshell.api.run("system.remove_system", self.file, **{"system": self.file.by_id(self.system)})
|
|
||||||
Data.load(IfcStore.get_file())
|
|
||||||
bpy.ops.bim.load_systems()
|
|
||||||
return {"FINISHED"}
|
|
||||||
|
|
||||||
|
|
||||||
class EnableEditingSystem(bpy.types.Operator):
|
class EnableEditingSystem(bpy.types.Operator, Operator):
|
||||||
bl_idname = "bim.enable_editing_system"
|
bl_idname = "bim.enable_editing_system"
|
||||||
bl_label = "Enable Editing System"
|
bl_label = "Enable Editing System"
|
||||||
bl_options = {"REGISTER", "UNDO"}
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
system: bpy.props.IntProperty()
|
system: bpy.props.IntProperty()
|
||||||
|
|
||||||
def execute(self, context):
|
def _execute(self, context):
|
||||||
props = context.scene.BIMSystemProperties
|
core.enable_editing_system(tool.System, system=tool.Ifc.get().by_id(self.system))
|
||||||
props.system_attributes.clear()
|
|
||||||
|
|
||||||
blenderbim.bim.helper.import_attributes("IfcSystem", props.system_attributes, Data.systems[self.system])
|
|
||||||
props.active_system_id = self.system
|
|
||||||
return {"FINISHED"}
|
|
||||||
|
|
||||||
|
|
||||||
class DisableEditingSystem(bpy.types.Operator):
|
class DisableEditingSystem(bpy.types.Operator, Operator):
|
||||||
bl_idname = "bim.disable_editing_system"
|
bl_idname = "bim.disable_editing_system"
|
||||||
bl_label = "Disable Editing System"
|
bl_label = "Disable Editing System"
|
||||||
bl_options = {"REGISTER", "UNDO"}
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
|
|
||||||
def execute(self, context):
|
def _execute(self, context):
|
||||||
context.scene.BIMSystemProperties.active_system_id = 0
|
core.disable_editing_system(tool.System)
|
||||||
return {"FINISHED"}
|
|
||||||
|
|
||||||
|
|
||||||
class ToggleAssigningSystem(bpy.types.Operator):
|
class AssignSystem(bpy.types.Operator, Operator):
|
||||||
bl_idname = "bim.toggle_assigning_system"
|
|
||||||
bl_label = "Toggle Assigning System"
|
|
||||||
bl_options = {"REGISTER", "UNDO"}
|
|
||||||
|
|
||||||
def execute(self, context):
|
|
||||||
context.scene.BIMSystemProperties.is_adding = not context.scene.BIMSystemProperties.is_adding
|
|
||||||
return {"FINISHED"}
|
|
||||||
|
|
||||||
|
|
||||||
class AssignSystem(bpy.types.Operator):
|
|
||||||
bl_idname = "bim.assign_system"
|
bl_idname = "bim.assign_system"
|
||||||
bl_label = "Assign System"
|
bl_label = "Assign System"
|
||||||
bl_options = {"REGISTER", "UNDO"}
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
product: bpy.props.StringProperty()
|
|
||||||
system: bpy.props.IntProperty()
|
system: bpy.props.IntProperty()
|
||||||
|
|
||||||
def execute(self, context):
|
|
||||||
return IfcStore.execute_ifc_operator(self, context)
|
|
||||||
|
|
||||||
def _execute(self, context):
|
def _execute(self, context):
|
||||||
self.file = IfcStore.get_file()
|
for obj in context.selected_objects:
|
||||||
products = [bpy.data.objects.get(self.product)] if self.product else context.selected_objects
|
element = tool.Ifc.get_entity(obj)
|
||||||
for product in products:
|
if element:
|
||||||
if not product.BIMObjectProperties.ifc_definition_id:
|
core.assign_system(tool.Ifc, system=tool.Ifc.get().by_id(self.system), product=element)
|
||||||
continue
|
|
||||||
ifcopenshell.api.run(
|
|
||||||
"system.assign_system",
|
|
||||||
self.file,
|
|
||||||
**{
|
|
||||||
"product": self.file.by_id(product.BIMObjectProperties.ifc_definition_id),
|
|
||||||
"system": self.file.by_id(self.system),
|
|
||||||
}
|
|
||||||
)
|
|
||||||
Data.load(self.file)
|
|
||||||
return {"FINISHED"}
|
|
||||||
|
|
||||||
|
|
||||||
class UnassignSystem(bpy.types.Operator):
|
class UnassignSystem(bpy.types.Operator, Operator):
|
||||||
bl_idname = "bim.unassign_system"
|
bl_idname = "bim.unassign_system"
|
||||||
bl_label = "Unassign System"
|
bl_label = "Unassign System"
|
||||||
bl_options = {"REGISTER", "UNDO"}
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
product: bpy.props.StringProperty()
|
|
||||||
system: bpy.props.IntProperty()
|
system: bpy.props.IntProperty()
|
||||||
|
|
||||||
def execute(self, context):
|
|
||||||
return IfcStore.execute_ifc_operator(self, context)
|
|
||||||
|
|
||||||
def _execute(self, context):
|
def _execute(self, context):
|
||||||
self.file = IfcStore.get_file()
|
for obj in context.selected_objects:
|
||||||
products = [bpy.data.objects.get(self.product)] if self.product else context.selected_objects
|
element = tool.Ifc.get_entity(obj)
|
||||||
for product in products:
|
if element:
|
||||||
props = product.BIMObjectProperties
|
core.unassign_system(tool.Ifc, system=tool.Ifc.get().by_id(self.system), product=element)
|
||||||
if not props.ifc_definition_id:
|
|
||||||
continue
|
|
||||||
if not (props.ifc_definition_id in Data.products and self.system in Data.products[props.ifc_definition_id]):
|
|
||||||
continue
|
|
||||||
ifcopenshell.api.run(
|
|
||||||
"system.unassign_system",
|
|
||||||
self.file,
|
|
||||||
**{
|
|
||||||
"product": self.file.by_id(product.BIMObjectProperties.ifc_definition_id),
|
|
||||||
"system": self.file.by_id(self.system),
|
|
||||||
}
|
|
||||||
)
|
|
||||||
Data.load(self.file)
|
|
||||||
return {"FINISHED"}
|
|
||||||
|
|
||||||
|
|
||||||
class SelectSystemProducts(bpy.types.Operator):
|
class SelectSystemProducts(bpy.types.Operator, Operator):
|
||||||
bl_idname = "bim.select_system_products"
|
bl_idname = "bim.select_system_products"
|
||||||
bl_label = "Select System Products"
|
bl_label = "Select System Products"
|
||||||
bl_options = {"REGISTER", "UNDO"}
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
system: bpy.props.IntProperty()
|
system: bpy.props.IntProperty()
|
||||||
|
|
||||||
def execute(self, context):
|
def _execute(self, context):
|
||||||
for obj in context.visible_objects:
|
core.select_system_products(tool.System, system=tool.Ifc.get().by_id(self.system))
|
||||||
obj.select_set(False)
|
|
||||||
if not obj.BIMObjectProperties.ifc_definition_id:
|
|
||||||
continue
|
|
||||||
product_systems = Data.products.get(obj.BIMObjectProperties.ifc_definition_id, [])
|
|
||||||
if self.system in product_systems:
|
|
||||||
obj.select_set(True)
|
|
||||||
return {"FINISHED"}
|
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
|
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import bpy
|
import bpy
|
||||||
|
from blenderbim.bim.module.system.data import SystemData
|
||||||
from blenderbim.bim.prop import StrProperty, Attribute
|
from blenderbim.bim.prop import StrProperty, Attribute
|
||||||
from bpy.types import PropertyGroup
|
from bpy.types import PropertyGroup
|
||||||
from bpy.props import (
|
from bpy.props import (
|
||||||
@@ -31,8 +32,15 @@ from bpy.props import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def get_system_class(self, context):
|
||||||
|
if not SystemData.is_loaded:
|
||||||
|
SystemData.load()
|
||||||
|
return SystemData.data["system_class"]
|
||||||
|
|
||||||
|
|
||||||
class System(PropertyGroup):
|
class System(PropertyGroup):
|
||||||
name: StringProperty(name="Name")
|
name: StringProperty(name="Name")
|
||||||
|
ifc_class: StringProperty(name="IFC Class")
|
||||||
ifc_definition_id: IntProperty(name="IFC Definition ID")
|
ifc_definition_id: IntProperty(name="IFC Definition ID")
|
||||||
|
|
||||||
|
|
||||||
@@ -43,3 +51,4 @@ class BIMSystemProperties(PropertyGroup):
|
|||||||
systems: CollectionProperty(name="Systems", type=System)
|
systems: CollectionProperty(name="Systems", type=System)
|
||||||
active_system_index: IntProperty(name="Active System Index")
|
active_system_index: IntProperty(name="Active System Index")
|
||||||
active_system_id: IntProperty(name="Active System Id")
|
active_system_id: IntProperty(name="Active System Id")
|
||||||
|
system_class: EnumProperty(items=get_system_class, name="Class")
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
|
|
||||||
from bpy.types import Panel, UIList
|
from bpy.types import Panel, UIList
|
||||||
from blenderbim.bim.ifc import IfcStore
|
from blenderbim.bim.ifc import IfcStore
|
||||||
from ifcopenshell.api.system.data import Data
|
from blenderbim.bim.module.system.data import SystemData, ObjectSystemData
|
||||||
|
|
||||||
|
|
||||||
class BIM_PT_systems(Panel):
|
class BIM_PT_systems(Panel):
|
||||||
@@ -35,15 +35,18 @@ class BIM_PT_systems(Panel):
|
|||||||
return IfcStore.get_file()
|
return IfcStore.get_file()
|
||||||
|
|
||||||
def draw(self, context):
|
def draw(self, context):
|
||||||
if not Data.is_loaded:
|
if not SystemData.is_loaded:
|
||||||
Data.load(IfcStore.get_file())
|
SystemData.load()
|
||||||
self.props = context.scene.BIMSystemProperties
|
self.props = context.scene.BIMSystemProperties
|
||||||
|
|
||||||
row = self.layout.row(align=True)
|
row = self.layout.row(align=True)
|
||||||
row.label(text="{} Systems Found".format(len(Data.systems)), icon="OUTLINER")
|
row.label(text="{} Systems Found".format(SystemData.data["total_systems"]), icon="OUTLINER")
|
||||||
if self.props.is_editing:
|
if self.props.is_editing:
|
||||||
row.operator("bim.add_system", text="", icon="ADD")
|
|
||||||
row.operator("bim.disable_system_editing_ui", text="", icon="CANCEL")
|
row.operator("bim.disable_system_editing_ui", text="", icon="CANCEL")
|
||||||
|
|
||||||
|
row = self.layout.row(align=True)
|
||||||
|
row.prop(self.props, "system_class", text="")
|
||||||
|
row.operator("bim.add_system", text="", icon="ADD")
|
||||||
else:
|
else:
|
||||||
row.operator("bim.load_systems", text="", icon="GREASEPENCIL")
|
row.operator("bim.load_systems", text="", icon="GREASEPENCIL")
|
||||||
|
|
||||||
@@ -84,13 +87,13 @@ class BIM_PT_object_systems(Panel):
|
|||||||
return IfcStore.get_file() and context.active_object.BIMObjectProperties.ifc_definition_id
|
return IfcStore.get_file() and context.active_object.BIMObjectProperties.ifc_definition_id
|
||||||
|
|
||||||
def draw(self, context):
|
def draw(self, context):
|
||||||
if not Data.is_loaded:
|
if not ObjectSystemData.is_loaded:
|
||||||
Data.load(IfcStore.get_file())
|
ObjectSystemData.load()
|
||||||
self.props = context.scene.BIMSystemProperties
|
self.props = context.scene.BIMSystemProperties
|
||||||
row = self.layout.row(align=True)
|
if self.props.is_editing:
|
||||||
if self.props.is_adding:
|
row = self.layout.row()
|
||||||
row.label(text="Adding Systems", icon="OUTLINER")
|
row.alignment = "RIGHT"
|
||||||
row.operator("bim.toggle_assigning_system", text="", icon="CANCEL")
|
row.operator("bim.disable_system_editing_ui", text="", icon="CANCEL")
|
||||||
self.layout.template_list(
|
self.layout.template_list(
|
||||||
"BIM_UL_object_systems",
|
"BIM_UL_object_systems",
|
||||||
"",
|
"",
|
||||||
@@ -100,17 +103,23 @@ class BIM_PT_object_systems(Panel):
|
|||||||
"active_system_index",
|
"active_system_index",
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
row.label(text=f"{len(Data.systems)} Systems in IFC Project", icon="OUTLINER")
|
|
||||||
row.operator("bim.toggle_assigning_system", text="", icon="ADD")
|
|
||||||
|
|
||||||
systems_object = Data.products.get(context.active_object.BIMObjectProperties.ifc_definition_id, [])
|
|
||||||
for system_id in systems_object:
|
|
||||||
row = self.layout.row(align=True)
|
row = self.layout.row(align=True)
|
||||||
row.label(text=Data.systems[system_id].get("Name", "Unnamed"))
|
row.label(text=f"{ObjectSystemData.data['total_systems']} Systems in IFC Project", icon="OUTLINER")
|
||||||
|
row.operator("bim.load_systems", text="", icon="GREASEPENCIL")
|
||||||
|
|
||||||
|
system_icons = {
|
||||||
|
"IfcSystem": "EXTERNAL_DRIVE",
|
||||||
|
"IfcDistributionSystem": "NETWORK_DRIVE",
|
||||||
|
"IfcDistributionCircuit": "DRIVER",
|
||||||
|
"IfcBuildingSystem": "MOD_BUILD",
|
||||||
|
}
|
||||||
|
for system in ObjectSystemData.data["systems"]:
|
||||||
|
row = self.layout.row(align=True)
|
||||||
|
row.label(text=system["name"], icon=system_icons[system["ifc_class"]])
|
||||||
op = row.operator("bim.select_system_products", text="", icon="RESTRICT_SELECT_OFF")
|
op = row.operator("bim.select_system_products", text="", icon="RESTRICT_SELECT_OFF")
|
||||||
op.system = system_id
|
op.system = system["id"]
|
||||||
op = row.operator("bim.unassign_system", text="", icon="X")
|
op = row.operator("bim.unassign_system", text="", icon="X")
|
||||||
op.system = system_id
|
op.system = system["id"]
|
||||||
|
|
||||||
if not systems_object:
|
if not systems_object:
|
||||||
self.layout.label(text="No System associated with Active Object")
|
self.layout.label(text="No System associated with Active Object")
|
||||||
@@ -118,9 +127,15 @@ class BIM_PT_object_systems(Panel):
|
|||||||
|
|
||||||
class BIM_UL_systems(UIList):
|
class BIM_UL_systems(UIList):
|
||||||
def draw_item(self, context, layout, data, item, icon, active_data, active_propname):
|
def draw_item(self, context, layout, data, item, icon, active_data, active_propname):
|
||||||
|
system_icons = {
|
||||||
|
"IfcSystem": "EXTERNAL_DRIVE",
|
||||||
|
"IfcDistributionSystem": "NETWORK_DRIVE",
|
||||||
|
"IfcDistributionCircuit": "DRIVER",
|
||||||
|
"IfcBuildingSystem": "MOD_BUILD",
|
||||||
|
}
|
||||||
if item:
|
if item:
|
||||||
row = layout.row(align=True)
|
row = layout.row(align=True)
|
||||||
row.label(text=item.name)
|
row.label(text=item.name, icon=system_icons[item.ifc_class])
|
||||||
system_id = item.ifc_definition_id
|
system_id = item.ifc_definition_id
|
||||||
if context.scene.BIMSystemProperties.active_system_id == system_id:
|
if context.scene.BIMSystemProperties.active_system_id == system_id:
|
||||||
op = row.operator("bim.select_system_products", text="", icon="RESTRICT_SELECT_OFF")
|
op = row.operator("bim.select_system_products", text="", icon="RESTRICT_SELECT_OFF")
|
||||||
@@ -143,8 +158,13 @@ class BIM_UL_systems(UIList):
|
|||||||
|
|
||||||
class BIM_UL_object_systems(UIList):
|
class BIM_UL_object_systems(UIList):
|
||||||
def draw_item(self, context, layout, data, item, icon, active_data, active_propname):
|
def draw_item(self, context, layout, data, item, icon, active_data, active_propname):
|
||||||
|
system_icons = {
|
||||||
|
"IfcSystem": "EXTERNAL_DRIVE",
|
||||||
|
"IfcDistributionSystem": "NETWORK_DRIVE",
|
||||||
|
"IfcDistributionCircuit": "DRIVER",
|
||||||
|
"IfcBuildingSystem": "MOD_BUILD",
|
||||||
|
}
|
||||||
if item:
|
if item:
|
||||||
row = layout.row(align=True)
|
row = layout.row(align=True)
|
||||||
row.label(text=item.name)
|
row.label(text=item.name, icon=system_icons[item.ifc_class])
|
||||||
op = row.operator("bim.assign_system", text="", icon="ADD")
|
row.operator("bim.assign_system", text="", icon="ADD").system = item.ifc_definition_id
|
||||||
op.system = item.ifc_definition_id
|
|
||||||
|
|||||||
@@ -0,0 +1,66 @@
|
|||||||
|
# BlenderBIM Add-on - OpenBIM Blender Add-on
|
||||||
|
# Copyright (C) 2022 Dion Moult <dion@thinkmoult.com>
|
||||||
|
#
|
||||||
|
# This file is part of BlenderBIM Add-on.
|
||||||
|
#
|
||||||
|
# BlenderBIM Add-on is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# BlenderBIM Add-on 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 General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
|
||||||
|
def load_systems(system):
|
||||||
|
system.import_systems()
|
||||||
|
system.enable_system_editing_ui()
|
||||||
|
system.disable_editing_system()
|
||||||
|
|
||||||
|
|
||||||
|
def disable_system_editing_ui(system):
|
||||||
|
system.disable_editing_system()
|
||||||
|
system.disable_system_editing_ui()
|
||||||
|
|
||||||
|
|
||||||
|
def add_system(ifc, system, ifc_class=None):
|
||||||
|
ifc.run("system.add_system", ifc_class=ifc_class)
|
||||||
|
system.import_systems()
|
||||||
|
|
||||||
|
|
||||||
|
def edit_system(ifc, system_tool, system=None):
|
||||||
|
attributes = system_tool.export_system_attributes()
|
||||||
|
ifc.run("system.edit_system", system=system, attributes=attributes)
|
||||||
|
system_tool.disable_editing_system()
|
||||||
|
system_tool.import_systems()
|
||||||
|
|
||||||
|
|
||||||
|
def remove_system(ifc, system_tool, system=None):
|
||||||
|
ifc.run("system.remove_system", system=system)
|
||||||
|
system_tool.import_systems()
|
||||||
|
|
||||||
|
|
||||||
|
def enable_editing_system(system_tool, system=None):
|
||||||
|
system_tool.import_system_attributes(system)
|
||||||
|
system_tool.set_active_system(system)
|
||||||
|
|
||||||
|
|
||||||
|
def disable_editing_system(system):
|
||||||
|
system.disable_editing_system()
|
||||||
|
|
||||||
|
|
||||||
|
def assign_system(ifc, system=None, product=None):
|
||||||
|
ifc.run("system.assign_system", product=product, system=system)
|
||||||
|
|
||||||
|
|
||||||
|
def unassign_system(ifc, system=None, product=None):
|
||||||
|
ifc.run("system.unassign_system", product=product, system=system)
|
||||||
|
|
||||||
|
|
||||||
|
def select_system_products(system_tool, system=None):
|
||||||
|
system_tool.select_system_products(system)
|
||||||
@@ -315,6 +315,18 @@ class Surveyor:
|
|||||||
def get_absolute_matrix(cls, obj): pass
|
def get_absolute_matrix(cls, obj): pass
|
||||||
|
|
||||||
|
|
||||||
|
@interface
|
||||||
|
class System:
|
||||||
|
def disable_editing_system(cls): pass
|
||||||
|
def disable_system_editing_ui(cls): pass
|
||||||
|
def enable_system_editing_ui(cls): pass
|
||||||
|
def export_system_attributes(cls): pass
|
||||||
|
def import_system_attributes(cls, system): pass
|
||||||
|
def import_systems(cls): pass
|
||||||
|
def select_system_products(cls, system): pass
|
||||||
|
def set_active_system(cls, system): pass
|
||||||
|
|
||||||
|
|
||||||
@interface
|
@interface
|
||||||
class Type:
|
class Type:
|
||||||
def change_object_data(cls, obj, data, is_global=False): pass
|
def change_object_data(cls, obj, data, is_global=False): pass
|
||||||
|
|||||||
@@ -37,5 +37,6 @@ from blenderbim.tool.spatial import Spatial
|
|||||||
from blenderbim.tool.structural import Structural
|
from blenderbim.tool.structural import Structural
|
||||||
from blenderbim.tool.style import Style
|
from blenderbim.tool.style import Style
|
||||||
from blenderbim.tool.surveyor import Surveyor
|
from blenderbim.tool.surveyor import Surveyor
|
||||||
|
from blenderbim.tool.system import System
|
||||||
from blenderbim.tool.type import Type
|
from blenderbim.tool.type import Type
|
||||||
from blenderbim.tool.unit import Unit
|
from blenderbim.tool.unit import Unit
|
||||||
|
|||||||
@@ -0,0 +1,67 @@
|
|||||||
|
# BlenderBIM Add-on - OpenBIM Blender Add-on
|
||||||
|
# Copyright (C) 2022 Dion Moult <dion@thinkmoult.com>
|
||||||
|
#
|
||||||
|
# This file is part of BlenderBIM Add-on.
|
||||||
|
#
|
||||||
|
# BlenderBIM Add-on is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# BlenderBIM Add-on 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 General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import bpy
|
||||||
|
import ifcopenshell.util.system
|
||||||
|
import blenderbim.core.tool
|
||||||
|
import blenderbim.tool as tool
|
||||||
|
|
||||||
|
|
||||||
|
class System(blenderbim.core.tool.System):
|
||||||
|
@classmethod
|
||||||
|
def disable_editing_system(cls):
|
||||||
|
bpy.context.scene.BIMSystemProperties.active_system_id = 0
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def disable_system_editing_ui(cls):
|
||||||
|
bpy.context.scene.BIMSystemProperties.is_editing = False
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def enable_system_editing_ui(cls):
|
||||||
|
bpy.context.scene.BIMSystemProperties.is_editing = True
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def export_system_attributes(cls):
|
||||||
|
return blenderbim.bim.helper.export_attributes(bpy.context.scene.BIMSystemProperties.system_attributes)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def import_system_attributes(cls, system):
|
||||||
|
blenderbim.bim.helper.import_attributes2(system, bpy.context.scene.BIMSystemProperties.system_attributes)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def import_systems(cls):
|
||||||
|
props = bpy.context.scene.BIMSystemProperties
|
||||||
|
props.systems.clear()
|
||||||
|
for system in tool.Ifc.get().by_type("IfcSystem"):
|
||||||
|
if system.is_a() in ["IfcZone", "IfcStructuralAnalysisModel"]:
|
||||||
|
continue
|
||||||
|
new = props.systems.add()
|
||||||
|
new.ifc_definition_id = system.id()
|
||||||
|
new.name = system.Name or "Unnamed"
|
||||||
|
new.ifc_class = system.is_a()
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def select_system_products(cls, system):
|
||||||
|
for element in ifcopenshell.util.system.get_system_elements(system):
|
||||||
|
obj = tool.Ifc.get_object(element)
|
||||||
|
if obj:
|
||||||
|
obj.select_set(True)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def set_active_system(cls, system):
|
||||||
|
bpy.context.scene.BIMSystemProperties.active_system_id = system.id()
|
||||||
@@ -23,6 +23,7 @@ markers =
|
|||||||
spatial
|
spatial
|
||||||
structural
|
structural
|
||||||
style
|
style
|
||||||
|
system
|
||||||
type
|
type
|
||||||
unit
|
unit
|
||||||
void
|
void
|
||||||
|
|||||||
@@ -0,0 +1,97 @@
|
|||||||
|
@system
|
||||||
|
Feature: System
|
||||||
|
|
||||||
|
Scenario: Load systems
|
||||||
|
Given an empty IFC project
|
||||||
|
When I press "bim.load_systems"
|
||||||
|
Then nothing happens
|
||||||
|
|
||||||
|
Scenario: Disable system editing UI
|
||||||
|
Given an empty IFC project
|
||||||
|
When I press "bim.load_systems"
|
||||||
|
And I press "bim.disable_system_editing_ui"
|
||||||
|
Then nothing happens
|
||||||
|
|
||||||
|
Scenario: Add system
|
||||||
|
Given an empty IFC project
|
||||||
|
And I press "bim.load_systems"
|
||||||
|
When I press "bim.add_system"
|
||||||
|
Then nothing happens
|
||||||
|
|
||||||
|
Scenario: Edit system
|
||||||
|
Given an empty IFC project
|
||||||
|
And I press "bim.load_systems"
|
||||||
|
And I press "bim.add_system"
|
||||||
|
And the variable "system" is "{ifc}.by_type('IfcSystem')[0].id()"
|
||||||
|
And I press "bim.enable_editing_system(system={system})"
|
||||||
|
When I press "bim.edit_system"
|
||||||
|
Then nothing happens
|
||||||
|
|
||||||
|
Scenario: Edit system
|
||||||
|
Given an empty IFC project
|
||||||
|
And I press "bim.load_systems"
|
||||||
|
And I press "bim.add_system"
|
||||||
|
And the variable "system" is "{ifc}.by_type('IfcSystem')[0].id()"
|
||||||
|
When I press "bim.remove_system(system={system})"
|
||||||
|
Then nothing happens
|
||||||
|
|
||||||
|
Scenario: Enable editing system
|
||||||
|
Given an empty IFC project
|
||||||
|
And I press "bim.load_systems"
|
||||||
|
And I press "bim.add_system"
|
||||||
|
And the variable "system" is "{ifc}.by_type('IfcSystem')[0].id()"
|
||||||
|
When I press "bim.enable_editing_system(system={system})"
|
||||||
|
Then nothing happens
|
||||||
|
|
||||||
|
Scenario: Disable editing system
|
||||||
|
Given an empty IFC project
|
||||||
|
And I press "bim.load_systems"
|
||||||
|
And I press "bim.add_system"
|
||||||
|
And the variable "system" is "{ifc}.by_type('IfcSystem')[0].id()"
|
||||||
|
And I press "bim.enable_editing_system(system={system})"
|
||||||
|
When I press "bim.disable_editing_system"
|
||||||
|
Then nothing happens
|
||||||
|
|
||||||
|
Scenario: Assign system
|
||||||
|
Given an empty IFC project
|
||||||
|
And I press "bim.load_systems"
|
||||||
|
And I press "bim.add_system"
|
||||||
|
And the variable "system" is "{ifc}.by_type('IfcSystem')[0].id()"
|
||||||
|
And I press "bim.enable_editing_system(system={system})"
|
||||||
|
And I add a cube
|
||||||
|
And the object "Cube" is selected
|
||||||
|
And I set "scene.BIMRootProperties.ifc_class" to "IfcPump"
|
||||||
|
And I press "bim.assign_class"
|
||||||
|
And the object "IfcPump/Cube" is selected
|
||||||
|
When I press "bim.assign_system(system={system})"
|
||||||
|
Then nothing happens
|
||||||
|
|
||||||
|
Scenario: Unassign system
|
||||||
|
Given an empty IFC project
|
||||||
|
And I press "bim.load_systems"
|
||||||
|
And I press "bim.add_system"
|
||||||
|
And the variable "system" is "{ifc}.by_type('IfcSystem')[0].id()"
|
||||||
|
And I press "bim.enable_editing_system(system={system})"
|
||||||
|
And I add a cube
|
||||||
|
And the object "Cube" is selected
|
||||||
|
And I set "scene.BIMRootProperties.ifc_class" to "IfcPump"
|
||||||
|
And I press "bim.assign_class"
|
||||||
|
And the object "IfcPump/Cube" is selected
|
||||||
|
And I press "bim.assign_system(system={system})"
|
||||||
|
When I press "bim.unassign_system(system={system})"
|
||||||
|
Then nothing happens
|
||||||
|
|
||||||
|
Scenario: Select system products
|
||||||
|
Given an empty IFC project
|
||||||
|
And I press "bim.load_systems"
|
||||||
|
And I press "bim.add_system"
|
||||||
|
And the variable "system" is "{ifc}.by_type('IfcSystem')[0].id()"
|
||||||
|
And I press "bim.enable_editing_system(system={system})"
|
||||||
|
And I add a cube
|
||||||
|
And the object "Cube" is selected
|
||||||
|
And I set "scene.BIMRootProperties.ifc_class" to "IfcPump"
|
||||||
|
And I press "bim.assign_class"
|
||||||
|
And the object "IfcPump/Cube" is selected
|
||||||
|
And I press "bim.assign_system(system={system})"
|
||||||
|
When I press "bim.select_system_products(system={system})"
|
||||||
|
Then nothing happens
|
||||||
@@ -168,6 +168,13 @@ def surveyor():
|
|||||||
prophet.verify()
|
prophet.verify()
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def system():
|
||||||
|
prophet = Prophecy(blenderbim.core.tool.System)
|
||||||
|
yield prophet
|
||||||
|
prophet.verify()
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def type():
|
def type():
|
||||||
prophet = Prophecy(blenderbim.core.tool.Type)
|
prophet = Prophecy(blenderbim.core.tool.Type)
|
||||||
|
|||||||
@@ -0,0 +1,90 @@
|
|||||||
|
# BlenderBIM Add-on - OpenBIM Blender Add-on
|
||||||
|
# Copyright (C) 2022 Dion Moult <dion@thinkmoult.com>
|
||||||
|
#
|
||||||
|
# This file is part of BlenderBIM Add-on.
|
||||||
|
#
|
||||||
|
# BlenderBIM Add-on is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# BlenderBIM Add-on 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 General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
|
||||||
|
import blenderbim.core.system as subject
|
||||||
|
from test.core.bootstrap import ifc, system
|
||||||
|
|
||||||
|
|
||||||
|
class TestLoadSystems:
|
||||||
|
def test_run(self, system):
|
||||||
|
system.import_systems().should_be_called()
|
||||||
|
system.enable_system_editing_ui().should_be_called()
|
||||||
|
system.disable_editing_system().should_be_called()
|
||||||
|
subject.load_systems(system)
|
||||||
|
|
||||||
|
|
||||||
|
class TestDisableSystemEditingUI:
|
||||||
|
def test_run(self, system):
|
||||||
|
system.disable_editing_system().should_be_called()
|
||||||
|
system.disable_system_editing_ui().should_be_called()
|
||||||
|
subject.disable_system_editing_ui(system)
|
||||||
|
|
||||||
|
|
||||||
|
class TestAddSystem:
|
||||||
|
def test_run(self, ifc, system):
|
||||||
|
ifc.run("system.add_system", ifc_class="ifc_class").should_be_called()
|
||||||
|
system.import_systems().should_be_called()
|
||||||
|
subject.add_system(ifc, system, ifc_class="ifc_class")
|
||||||
|
|
||||||
|
|
||||||
|
class TestEditSystem:
|
||||||
|
def test_run(self, ifc, system):
|
||||||
|
system.export_system_attributes().should_be_called().will_return("attributes")
|
||||||
|
ifc.run("system.edit_system", system="system", attributes="attributes").should_be_called()
|
||||||
|
system.disable_editing_system().should_be_called()
|
||||||
|
system.import_systems().should_be_called()
|
||||||
|
subject.edit_system(ifc, system, system="system")
|
||||||
|
|
||||||
|
|
||||||
|
class TestRemoveSystem:
|
||||||
|
def test_run(self, ifc, system):
|
||||||
|
ifc.run("system.remove_system", system="system").should_be_called()
|
||||||
|
system.import_systems().should_be_called()
|
||||||
|
subject.remove_system(ifc, system, system="system")
|
||||||
|
|
||||||
|
|
||||||
|
class TestEnableEditingSystem:
|
||||||
|
def test_run(self, system):
|
||||||
|
system.import_system_attributes("system").should_be_called()
|
||||||
|
system.set_active_system("system").should_be_called()
|
||||||
|
subject.enable_editing_system(system, system="system")
|
||||||
|
|
||||||
|
|
||||||
|
class TestDisableEditingSystem:
|
||||||
|
def test_run(self, system):
|
||||||
|
system.disable_editing_system().should_be_called()
|
||||||
|
subject.disable_editing_system(system)
|
||||||
|
|
||||||
|
|
||||||
|
class TestAssignSystem:
|
||||||
|
def test_run(self, ifc):
|
||||||
|
ifc.run("system.assign_system", product="product", system="system").should_be_called()
|
||||||
|
subject.assign_system(ifc, system="system", product="product")
|
||||||
|
|
||||||
|
|
||||||
|
class TestUnassignSystem:
|
||||||
|
def test_run(self, ifc):
|
||||||
|
ifc.run("system.unassign_system", product="product", system="system").should_be_called()
|
||||||
|
subject.unassign_system(ifc, system="system", product="product")
|
||||||
|
|
||||||
|
|
||||||
|
class TestSelectSystemProducts:
|
||||||
|
def test_run(self, system):
|
||||||
|
system.select_system_products("system").should_be_called()
|
||||||
|
subject.select_system_products(system, system="system")
|
||||||
@@ -0,0 +1,152 @@
|
|||||||
|
# BlenderBIM Add-on - OpenBIM Blender Add-on
|
||||||
|
# Copyright (C) 2022 Dion Moult <dion@thinkmoult.com>
|
||||||
|
#
|
||||||
|
# This file is part of BlenderBIM Add-on.
|
||||||
|
#
|
||||||
|
# BlenderBIM Add-on is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# BlenderBIM Add-on 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 General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import bpy
|
||||||
|
import ifcopenshell
|
||||||
|
import blenderbim.core.tool
|
||||||
|
import blenderbim.tool as tool
|
||||||
|
from test.bim.bootstrap import NewFile
|
||||||
|
from blenderbim.tool.system import System as subject
|
||||||
|
|
||||||
|
|
||||||
|
class TestImplementsTool(NewFile):
|
||||||
|
def test_run(self):
|
||||||
|
assert isinstance(subject(), blenderbim.core.tool.System)
|
||||||
|
|
||||||
|
|
||||||
|
class TestDisableEditingSystem(NewFile):
|
||||||
|
def test_run(self):
|
||||||
|
bpy.context.scene.BIMSystemProperties.active_system_id = 10
|
||||||
|
subject.disable_editing_system()
|
||||||
|
assert bpy.context.scene.BIMSystemProperties.active_system_id == 0
|
||||||
|
|
||||||
|
|
||||||
|
class TestDisableSystemEditingUI(NewFile):
|
||||||
|
def test_run(self):
|
||||||
|
subject.enable_system_editing_ui()
|
||||||
|
subject.disable_system_editing_ui()
|
||||||
|
assert bpy.context.scene.BIMSystemProperties.is_editing is False
|
||||||
|
|
||||||
|
|
||||||
|
class TestEnableSystemEditingUI(NewFile):
|
||||||
|
def test_run(self):
|
||||||
|
subject.enable_system_editing_ui()
|
||||||
|
assert bpy.context.scene.BIMSystemProperties.is_editing is True
|
||||||
|
|
||||||
|
|
||||||
|
class TestExportSystemAttributes(NewFile):
|
||||||
|
def test_run(self):
|
||||||
|
TestImportSystemAttributes().test_importing_a_system()
|
||||||
|
assert subject.export_system_attributes() == {
|
||||||
|
"GlobalId": "GlobalId",
|
||||||
|
"Name": "Name",
|
||||||
|
"Description": "Description",
|
||||||
|
"ObjectType": "ObjectType",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class TestImportSystemAttributes(NewFile):
|
||||||
|
def test_importing_a_system(self):
|
||||||
|
ifc = ifcopenshell.file()
|
||||||
|
tool.Ifc().set(ifc)
|
||||||
|
system = ifc.createIfcSystem()
|
||||||
|
system.GlobalId = "GlobalId"
|
||||||
|
system.Name = "Name"
|
||||||
|
system.Description = "Description"
|
||||||
|
system.ObjectType = "ObjectType"
|
||||||
|
subject().import_system_attributes(system)
|
||||||
|
props = bpy.context.scene.BIMSystemProperties
|
||||||
|
assert props.system_attributes.get("GlobalId").string_value == "GlobalId"
|
||||||
|
assert props.system_attributes.get("Name").string_value == "Name"
|
||||||
|
assert props.system_attributes.get("Description").string_value == "Description"
|
||||||
|
assert props.system_attributes.get("ObjectType").string_value == "ObjectType"
|
||||||
|
|
||||||
|
def test_importing_a_building_system(self):
|
||||||
|
ifc = ifcopenshell.file()
|
||||||
|
tool.Ifc().set(ifc)
|
||||||
|
system = ifc.createIfcBuildingSystem()
|
||||||
|
system.GlobalId = "GlobalId"
|
||||||
|
system.Name = "Name"
|
||||||
|
system.Description = "Description"
|
||||||
|
system.ObjectType = "ObjectType"
|
||||||
|
system.PredefinedType = "SHADING"
|
||||||
|
system.LongName = "LongName"
|
||||||
|
subject().import_system_attributes(system)
|
||||||
|
props = bpy.context.scene.BIMSystemProperties
|
||||||
|
assert props.system_attributes.get("GlobalId").string_value == "GlobalId"
|
||||||
|
assert props.system_attributes.get("Name").string_value == "Name"
|
||||||
|
assert props.system_attributes.get("Description").string_value == "Description"
|
||||||
|
assert props.system_attributes.get("ObjectType").string_value == "ObjectType"
|
||||||
|
assert props.system_attributes.get("PredefinedType").enum_value == "SHADING"
|
||||||
|
assert props.system_attributes.get("LongName").string_value == "LongName"
|
||||||
|
|
||||||
|
def test_importing_a_distribution_system(self):
|
||||||
|
ifc = ifcopenshell.file()
|
||||||
|
tool.Ifc().set(ifc)
|
||||||
|
system = ifc.createIfcDistributionSystem()
|
||||||
|
system.GlobalId = "GlobalId"
|
||||||
|
system.Name = "Name"
|
||||||
|
system.Description = "Description"
|
||||||
|
system.ObjectType = "ObjectType"
|
||||||
|
system.PredefinedType = "ELECTRICAL"
|
||||||
|
system.LongName = "LongName"
|
||||||
|
subject().import_system_attributes(system)
|
||||||
|
props = bpy.context.scene.BIMSystemProperties
|
||||||
|
assert props.system_attributes.get("GlobalId").string_value == "GlobalId"
|
||||||
|
assert props.system_attributes.get("Name").string_value == "Name"
|
||||||
|
assert props.system_attributes.get("Description").string_value == "Description"
|
||||||
|
assert props.system_attributes.get("ObjectType").string_value == "ObjectType"
|
||||||
|
assert props.system_attributes.get("PredefinedType").enum_value == "ELECTRICAL"
|
||||||
|
assert props.system_attributes.get("LongName").string_value == "LongName"
|
||||||
|
|
||||||
|
|
||||||
|
class TestImportSystems(NewFile):
|
||||||
|
def test_run(self):
|
||||||
|
ifc = ifcopenshell.file()
|
||||||
|
tool.Ifc().set(ifc)
|
||||||
|
system = ifc.createIfcDistributionSystem()
|
||||||
|
zone = ifc.createIfcZone()
|
||||||
|
subject.import_systems()
|
||||||
|
props = bpy.context.scene.BIMSystemProperties
|
||||||
|
assert len(props.systems) == 1
|
||||||
|
assert props.systems[0].ifc_definition_id == system.id()
|
||||||
|
assert props.systems[0].name == "Unnamed"
|
||||||
|
assert props.systems[0].ifc_class == "IfcDistributionSystem"
|
||||||
|
|
||||||
|
|
||||||
|
class TestSelectSystemProducts(NewFile):
|
||||||
|
def test_run(self):
|
||||||
|
ifc = ifcopenshell.file()
|
||||||
|
tool.Ifc().set(ifc)
|
||||||
|
element = ifcopenshell.api.run("root.create_entity", ifc, ifc_class="IfcPump")
|
||||||
|
system = ifcopenshell.api.run("system.add_system", ifc, ifc_class="IfcSystem")
|
||||||
|
ifcopenshell.api.run("system.assign_system", ifc, product=element, system=system)
|
||||||
|
obj = bpy.data.objects.new("Object", None)
|
||||||
|
bpy.context.scene.collection.objects.link(obj)
|
||||||
|
tool.Ifc.link(element, obj)
|
||||||
|
subject.select_system_products(system)
|
||||||
|
assert obj in bpy.context.selected_objects
|
||||||
|
|
||||||
|
|
||||||
|
class TestSetActiveSystem(NewFile):
|
||||||
|
def test_run(self):
|
||||||
|
ifc = ifcopenshell.file()
|
||||||
|
tool.Ifc().set(ifc)
|
||||||
|
system = ifcopenshell.api.run("system.add_system", ifc, ifc_class="IfcSystem")
|
||||||
|
subject.set_active_system(system)
|
||||||
|
assert bpy.context.scene.BIMSystemProperties.active_system_id == system.id()
|
||||||
@@ -9,8 +9,8 @@ qa:
|
|||||||
|
|
||||||
.PHONY: license
|
.PHONY: license
|
||||||
license:
|
license:
|
||||||
#copyright-header --license LGPL3 --copyright-holder "Thomas Krijnen <thomas@aecgeeks.com>" --copyright-year "2021" --copyright-software "IfcOpenShell" --copyright-software-description "IFC toolkit and geometry engine" -a ./ -o ./
|
#copyright-header --license LGPL3 --copyright-holder "Thomas Krijnen <thomas@aecgeeks.com>" --copyright-year "2022" --copyright-software "IfcOpenShell" --copyright-software-description "IFC toolkit and geometry engine" -a ./ -o ./
|
||||||
copyright-header --license LGPL3 --copyright-holder "Dion Moult <dion@thinkmoult.com>" --copyright-year "2021" --copyright-software "IfcOpenShell" --copyright-software-description "IFC toolkit and geometry engine" -a ./ -o ./
|
copyright-header --license LGPL3 --copyright-holder "Dion Moult <dion@thinkmoult.com>" --copyright-year "2022" --copyright-software "IfcOpenShell" --copyright-software-description "IFC toolkit and geometry engine" -a ./ -o ./
|
||||||
|
|
||||||
.PHONY: coverage
|
.PHONY: coverage
|
||||||
coverage:
|
coverage:
|
||||||
|
|||||||
@@ -23,13 +23,13 @@ import ifcopenshell.api
|
|||||||
class Usecase:
|
class Usecase:
|
||||||
def __init__(self, file, **settings):
|
def __init__(self, file, **settings):
|
||||||
self.file = file
|
self.file = file
|
||||||
self.settings = {}
|
self.settings = {"ifc_class": "IfcSystem"}
|
||||||
for key, value in settings.items():
|
for key, value in settings.items():
|
||||||
self.settings[key] = value
|
self.settings[key] = value
|
||||||
|
|
||||||
def execute(self):
|
def execute(self):
|
||||||
return self.file.create_entity(
|
return self.file.create_entity(
|
||||||
"IfcSystem",
|
self.settings["ifc_class"],
|
||||||
**{
|
**{
|
||||||
"GlobalId": ifcopenshell.guid.new(),
|
"GlobalId": ifcopenshell.guid.new(),
|
||||||
"OwnerHistory": ifcopenshell.api.run("owner.create_owner_history", self.file),
|
"OwnerHistory": ifcopenshell.api.run("owner.create_owner_history", self.file),
|
||||||
|
|||||||
@@ -0,0 +1,36 @@
|
|||||||
|
# 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/>.
|
||||||
|
|
||||||
|
|
||||||
|
def get_system_elements(system):
|
||||||
|
results = []
|
||||||
|
for rel in system.IsGroupedBy:
|
||||||
|
results.extend(rel.RelatedObjects)
|
||||||
|
return results
|
||||||
|
|
||||||
|
|
||||||
|
def get_element_systems(element):
|
||||||
|
results = []
|
||||||
|
for rel in element.HasAssignments:
|
||||||
|
if rel.is_a("IfcRelAssignsToGroup") and rel.RelatingGroup.is_a() in [
|
||||||
|
"IfcSystem",
|
||||||
|
"IfcDistributionSystem",
|
||||||
|
"IfcBuildingSystem",
|
||||||
|
]:
|
||||||
|
results.append(rel.RelatingGroup)
|
||||||
|
return results
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
# 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 test.bootstrap
|
||||||
|
import ifcopenshell.api
|
||||||
|
|
||||||
|
|
||||||
|
class TestAddSystem(test.bootstrap.IFC4):
|
||||||
|
def test_adding_a_system(self):
|
||||||
|
system = ifcopenshell.api.run("system.add_system", self.file, ifc_class="IfcSystem")
|
||||||
|
system2 = ifcopenshell.api.run("system.add_system", self.file, ifc_class="IfcDistributionSystem")
|
||||||
|
assert system.is_a("IfcSystem")
|
||||||
|
assert system2.is_a("IfcDistributionSystem")
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
# 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 test.bootstrap
|
||||||
|
import ifcopenshell.api
|
||||||
|
|
||||||
|
|
||||||
|
class TestRemoveSystem(test.bootstrap.IFC4):
|
||||||
|
def test_removing_a_system(self):
|
||||||
|
system = ifcopenshell.api.run("system.add_system", self.file, ifc_class="IfcSystem")
|
||||||
|
ifcopenshell.api.run("system.remove_system", self.file, system=system)
|
||||||
|
assert len(self.file.by_type("IfcSystem")) == 0
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
# 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 pytest
|
||||||
|
import test.bootstrap
|
||||||
|
import ifcopenshell.api
|
||||||
|
import ifcopenshell.util.system as subject
|
||||||
|
|
||||||
|
|
||||||
|
class TestGetSystemElements(test.bootstrap.IFC4):
|
||||||
|
def test_run(self):
|
||||||
|
element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcPump")
|
||||||
|
system = ifcopenshell.api.run("system.add_system", self.file, ifc_class="IfcSystem")
|
||||||
|
ifcopenshell.api.run("system.assign_system", self.file, product=element, system=system)
|
||||||
|
assert subject.get_system_elements(system) == [element]
|
||||||
|
|
||||||
|
|
||||||
|
class TestGetElementSystems(test.bootstrap.IFC4):
|
||||||
|
def test_run(self):
|
||||||
|
element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcPump")
|
||||||
|
system = ifcopenshell.api.run("system.add_system", self.file, ifc_class="IfcSystem")
|
||||||
|
ifcopenshell.api.run("system.assign_system", self.file, product=element, system=system)
|
||||||
|
assert subject.get_element_systems(element) == [system]
|
||||||
|
|
||||||
|
def test_do_not_get_non_services_groups(self):
|
||||||
|
element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcPump")
|
||||||
|
ifcopenshell.api.run("system.assign_system", self.file, product=element, system=self.file.createIfcGroup())
|
||||||
|
ifcopenshell.api.run("system.assign_system", self.file, product=element, system=self.file.createIfcZone())
|
||||||
|
ifcopenshell.api.run(
|
||||||
|
"system.assign_system", self.file, product=element, system=self.file.createIfcStructuralAnalysisModel()
|
||||||
|
)
|
||||||
|
assert not subject.get_element_systems(element)
|
||||||
Reference in New Issue
Block a user