mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-11 02:02:22 +00:00
New feature to show inherited element type psets.
This commit is contained in:
@@ -0,0 +1,157 @@
|
||||
# BlenderBIM Add-on - OpenBIM Blender Add-on
|
||||
# Copyright (C) 2021 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.tool as tool
|
||||
|
||||
|
||||
# TODO: Should this cache belong here? Dunno. Maybe.
|
||||
is_expanded = {}
|
||||
|
||||
|
||||
def refresh():
|
||||
ObjectPsetsData.is_loaded = False
|
||||
ObjectQtosData.is_loaded = False
|
||||
MaterialPsetsData.is_loaded = False
|
||||
TaskQtosData.is_loaded = False
|
||||
ResourceQtosData.is_loaded = False
|
||||
ResourcePsetsData.is_loaded = False
|
||||
ProfilePsetsData.is_loaded = False
|
||||
WorkSchedulePsetsData.is_loaded = False
|
||||
|
||||
|
||||
class Data:
|
||||
@classmethod
|
||||
def psetqtos(cls, element, psets_only=False, qtos_only=False):
|
||||
results = []
|
||||
psetqtos = ifcopenshell.util.element.get_psets(element, psets_only=psets_only, qtos_only=qtos_only)
|
||||
for name, data in psetqtos.items():
|
||||
results.append(
|
||||
{
|
||||
"id": data["id"],
|
||||
"Name": name,
|
||||
"is_expanded": is_expanded.get(data["id"], True),
|
||||
"Properties": [{"Name": k, "NominalValue": v} for k, v in data.items() if k != "id"],
|
||||
}
|
||||
)
|
||||
return sorted(results, key=lambda v: v["Name"])
|
||||
|
||||
|
||||
class ObjectPsetsData(Data):
|
||||
data = {}
|
||||
is_loaded = False
|
||||
|
||||
@classmethod
|
||||
def load(cls):
|
||||
cls.data = {
|
||||
"psets": cls.psetqtos(tool.Ifc.get_entity(bpy.context.active_object), psets_only=True),
|
||||
"inherited_psets": cls.inherited_psets(),
|
||||
}
|
||||
cls.is_loaded = True
|
||||
|
||||
@classmethod
|
||||
def inherited_psets(cls):
|
||||
element = tool.Ifc.get_entity(bpy.context.active_object)
|
||||
if element.is_a("IfcTypeObject"):
|
||||
return
|
||||
element_type = ifcopenshell.util.element.get_type(element)
|
||||
return cls.psetqtos(element_type)
|
||||
|
||||
|
||||
class ObjectQtosData(Data):
|
||||
data = {}
|
||||
is_loaded = False
|
||||
|
||||
@classmethod
|
||||
def load(cls):
|
||||
cls.data = {"qtos": cls.psetqtos(tool.Ifc.get_entity(bpy.context.active_object), qtos_only=True)}
|
||||
cls.is_loaded = True
|
||||
|
||||
|
||||
class MaterialPsetsData(Data):
|
||||
data = {}
|
||||
is_loaded = False
|
||||
|
||||
@classmethod
|
||||
def load(cls):
|
||||
cls.data = {"psets": cls.psetqtos(tool.Ifc.get_entity(bpy.context.active_object.active_material))}
|
||||
cls.is_loaded = True
|
||||
|
||||
|
||||
class TaskQtosData(Data):
|
||||
data = {}
|
||||
is_loaded = False
|
||||
|
||||
@classmethod
|
||||
def load(cls):
|
||||
wprops = bpy.context.scene.BIMWorkScheduleProperties
|
||||
tprops = bpy.context.scene.BIMTaskTreeProperties
|
||||
ifc_definition_id = tprops.tasks[wprops.active_task_index].ifc_definition_id
|
||||
cls.data = {"qtos": cls.psetqtos(tool.Ifc.get().by_id(ifc_definition_id), qtos_only=True)}
|
||||
cls.is_loaded = True
|
||||
|
||||
|
||||
class ResourceQtosData(Data):
|
||||
data = {}
|
||||
is_loaded = False
|
||||
|
||||
@classmethod
|
||||
def load(cls):
|
||||
rprops = bpy.context.scene.BIMResourceProperties
|
||||
rtprops = bpy.context.scene.BIMResourceTreeProperties
|
||||
ifc_definition_id = rtprops.resources[rprops.active_resource_index].ifc_definition_id
|
||||
cls.data = {"qtos": cls.psetqtos(tool.Ifc.get().by_id(ifc_definition_id), qtos_only=True)}
|
||||
cls.is_loaded = True
|
||||
|
||||
|
||||
class ResourcePsetsData(Data):
|
||||
data = {}
|
||||
is_loaded = False
|
||||
|
||||
@classmethod
|
||||
def load(cls):
|
||||
rprops = bpy.context.scene.BIMResourceProperties
|
||||
rtprops = bpy.context.scene.BIMResourceTreeProperties
|
||||
ifc_definition_id = rtprops.resources[rprops.active_resource_index].ifc_definition_id
|
||||
cls.data = {"psets": cls.psetqtos(tool.Ifc.get().by_id(ifc_definition_id), psets_only=True)}
|
||||
cls.is_loaded = True
|
||||
|
||||
|
||||
class ProfilePsetsData(Data):
|
||||
data = {}
|
||||
is_loaded = False
|
||||
|
||||
@classmethod
|
||||
def load(cls):
|
||||
pprops = bpy.context.scene.BIMProfileProperties
|
||||
ifc_definition_id = pprops.profiles[pprops.active_profile_index].ifc_definition_id
|
||||
cls.data = {"psets": cls.psetqtos(tool.Ifc.get().by_id(ifc_definition_id), psets_only=True)}
|
||||
cls.is_loaded = True
|
||||
|
||||
|
||||
class WorkSchedulePsetsData(Data):
|
||||
data = {}
|
||||
is_loaded = False
|
||||
|
||||
@classmethod
|
||||
def load(cls):
|
||||
props = bpy.context.scene.WorkSchedulePsetProperties
|
||||
ifc_definition_id = bpy.context.scene.BIMWorkScheduleProperties.active_work_schedule_id
|
||||
cls.data = {"psets": cls.psetqtos(tool.Ifc.get().by_id(ifc_definition_id), psets_only=True)}
|
||||
cls.is_loaded = True
|
||||
@@ -23,8 +23,10 @@ import ifcopenshell.util.unit
|
||||
import ifcopenshell.util.pset
|
||||
import ifcopenshell.util.attribute
|
||||
import blenderbim.bim.schema
|
||||
import blenderbim.bim.handler
|
||||
import blenderbim.tool as tool
|
||||
import blenderbim.core.pset as core
|
||||
import blenderbim.bim.module.pset.data
|
||||
from blenderbim.bim.ifc import IfcStore
|
||||
from ifcopenshell.api.pset.data import Data
|
||||
from ifcopenshell.api.cost.data import Data as CostData
|
||||
@@ -78,16 +80,15 @@ def get_pset_obj_ifc_definition_id(context, obj, obj_type):
|
||||
return context.scene.BIMWorkScheduleProperties.active_work_schedule_id
|
||||
|
||||
|
||||
class TogglePsetExpansion(bpy.types.Operator):
|
||||
class TogglePsetExpansion(bpy.types.Operator, Operator):
|
||||
bl_idname = "bim.toggle_pset_expansion"
|
||||
bl_label = "Toggle Pset Expansion"
|
||||
pset_id: bpy.props.IntProperty()
|
||||
|
||||
def execute(self, context):
|
||||
obj = context.active_object
|
||||
data = Data.psets if self.pset_id in Data.psets else Data.qtos
|
||||
data[self.pset_id]["is_expanded"] = not data[self.pset_id]["is_expanded"]
|
||||
return {"FINISHED"}
|
||||
def _execute(self, context):
|
||||
blenderbim.bim.module.pset.data.is_expanded[
|
||||
self.pset_id
|
||||
] = not blenderbim.bim.module.pset.data.is_expanded.setdefault(self.pset_id, True)
|
||||
|
||||
|
||||
class EnablePsetEditing(bpy.types.Operator):
|
||||
|
||||
@@ -17,9 +17,18 @@
|
||||
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from bpy.types import Panel
|
||||
from ifcopenshell.api.pset.data import Data
|
||||
from blenderbim.bim.ifc import IfcStore
|
||||
from blenderbim.bim.helper import draw_attribute
|
||||
from blenderbim.bim.module.pset.data import (
|
||||
ObjectPsetsData,
|
||||
ObjectQtosData,
|
||||
MaterialPsetsData,
|
||||
TaskQtosData,
|
||||
ResourceQtosData,
|
||||
ResourcePsetsData,
|
||||
ProfilePsetsData,
|
||||
WorkSchedulePsetsData,
|
||||
)
|
||||
|
||||
|
||||
def get_active_pset_obj_name(context, obj_type):
|
||||
@@ -68,8 +77,7 @@ def draw_psetqto_ui(context, pset_id, pset, props, layout, obj_type):
|
||||
draw_psetqto_editable_ui(box, props, prop)
|
||||
else:
|
||||
has_props_displayed = False
|
||||
for prop_id in pset["Properties"]:
|
||||
prop = Data.properties[prop_id]
|
||||
for prop in pset["Properties"]:
|
||||
if context.preferences.addons["blenderbim"].preferences.should_hide_empty_props and (
|
||||
prop["NominalValue"] is None or prop["NominalValue"] == ""
|
||||
):
|
||||
@@ -121,33 +129,26 @@ class BIM_PT_object_psets(Panel):
|
||||
return False
|
||||
if not IfcStore.get_element(props.ifc_definition_id):
|
||||
return False
|
||||
if props.ifc_definition_id not in Data.products:
|
||||
Data.load(IfcStore.get_file(), props.ifc_definition_id)
|
||||
if not Data.products[props.ifc_definition_id]:
|
||||
return False
|
||||
return True
|
||||
|
||||
def draw(self, context):
|
||||
oprops = context.active_object.BIMObjectProperties
|
||||
if not ObjectPsetsData.is_loaded:
|
||||
ObjectPsetsData.load()
|
||||
|
||||
props = context.active_object.PsetProperties
|
||||
if not oprops.ifc_definition_id:
|
||||
return
|
||||
if oprops.ifc_definition_id not in Data.products:
|
||||
Data.load(IfcStore.get_file(), oprops.ifc_definition_id)
|
||||
row = self.layout.row(align=True)
|
||||
row.prop(props, "pset_name", text="")
|
||||
op = row.operator("bim.add_pset", icon="ADD", text="")
|
||||
op.obj = context.active_object.name
|
||||
op.obj_type = "Object"
|
||||
|
||||
psets = [(pset_id, Data.psets[pset_id]) for pset_id in Data.products[oprops.ifc_definition_id]["psets"]]
|
||||
for pset_id, pset in sorted(psets, key=lambda v: v[1]["Name"]):
|
||||
draw_psetqto_ui(context, pset_id, pset, props, self.layout, "Object")
|
||||
for pset in ObjectPsetsData.data["psets"]:
|
||||
draw_psetqto_ui(context, pset["id"], pset, props, self.layout, "Object")
|
||||
|
||||
# TODO reimplement. See #1222.
|
||||
# if props.relating_type and props.relating_type.PsetProperties.psets:
|
||||
# self.layout.label(text="Inherited Psets:")
|
||||
# self.draw_psets_ui(props.relating_type.PsetProperties, enabled=False)
|
||||
if ObjectPsetsData.data["inherited_psets"]:
|
||||
self.layout.label(text="Inherited Psets:")
|
||||
for pset in ObjectPsetsData.data["inherited_psets"]:
|
||||
draw_psetqto_ui(context, pset["id"], pset, props, self.layout, "Object")
|
||||
|
||||
|
||||
class BIM_PT_object_qtos(Panel):
|
||||
@@ -166,28 +167,21 @@ class BIM_PT_object_qtos(Panel):
|
||||
return False
|
||||
if not IfcStore.get_element(props.ifc_definition_id):
|
||||
return False
|
||||
if props.ifc_definition_id not in Data.products:
|
||||
Data.load(IfcStore.get_file(), props.ifc_definition_id)
|
||||
if not Data.products[props.ifc_definition_id]:
|
||||
return False
|
||||
return True
|
||||
|
||||
def draw(self, context):
|
||||
oprops = context.active_object.BIMObjectProperties
|
||||
if not ObjectQtosData.is_loaded:
|
||||
ObjectQtosData.load()
|
||||
|
||||
props = context.active_object.PsetProperties
|
||||
if not oprops.ifc_definition_id:
|
||||
return
|
||||
if oprops.ifc_definition_id not in Data.products:
|
||||
Data.load(IfcStore.get_file(), oprops.ifc_definition_id)
|
||||
row = self.layout.row(align=True)
|
||||
row.prop(props, "qto_name", text="")
|
||||
op = row.operator("bim.add_qto", icon="ADD", text="")
|
||||
op.obj = context.active_object.name
|
||||
op.obj_type = "Object"
|
||||
|
||||
qtos = [(qto_id, Data.qtos[qto_id]) for qto_id in Data.products[oprops.ifc_definition_id]["qtos"]]
|
||||
for qto_id, qto in sorted(qtos, key=lambda v: v[1]["Name"]):
|
||||
draw_psetqto_ui(context, qto_id, qto, props, self.layout, "Object")
|
||||
for qto in ObjectQtosData.data["qtos"]:
|
||||
draw_psetqto_ui(context, qto["id"], qto, props, self.layout, "Object")
|
||||
|
||||
|
||||
class BIM_PT_material_psets(Panel):
|
||||
@@ -209,28 +203,21 @@ class BIM_PT_material_psets(Panel):
|
||||
file = IfcStore.get_file()
|
||||
if not file or file.schema == "IFC2X3":
|
||||
return False # We don't support material psets in IFC2X3 because they suck
|
||||
if props.ifc_definition_id not in Data.products:
|
||||
Data.load(IfcStore.get_file(), props.ifc_definition_id)
|
||||
if not Data.products[props.ifc_definition_id]:
|
||||
return False
|
||||
return True
|
||||
|
||||
def draw(self, context):
|
||||
oprops = context.active_object.active_material.BIMObjectProperties
|
||||
if not MaterialPsetsData.is_loaded:
|
||||
MaterialPsetsData.load()
|
||||
|
||||
props = context.active_object.active_material.PsetProperties
|
||||
if not oprops.ifc_definition_id:
|
||||
return
|
||||
if oprops.ifc_definition_id not in Data.products:
|
||||
Data.load(IfcStore.get_file(), oprops.ifc_definition_id)
|
||||
row = self.layout.row(align=True)
|
||||
row.prop(props, "pset_name", text="")
|
||||
op = row.operator("bim.add_pset", icon="ADD", text="")
|
||||
op.obj = context.active_object.active_material.name
|
||||
op.obj_type = "Material"
|
||||
|
||||
psets = [(pset_id, Data.psets[pset_id]) for pset_id in Data.products[oprops.ifc_definition_id]["psets"]]
|
||||
for pset_id, pset in sorted(psets, key=lambda v: v[1]["Name"]):
|
||||
draw_psetqto_ui(context, pset_id, pset, props, self.layout, "Material")
|
||||
for pset in MaterialPsetsData.data["psets"]:
|
||||
draw_psetqto_ui(context, pset["id"], pset, props, self.layout, "Material")
|
||||
|
||||
|
||||
class BIM_PT_task_qtos(Panel):
|
||||
@@ -253,20 +240,17 @@ class BIM_PT_task_qtos(Panel):
|
||||
return False
|
||||
|
||||
def draw(self, context):
|
||||
if not TaskQtosData.is_loaded:
|
||||
TaskQtosData.load()
|
||||
|
||||
props = context.scene.TaskPsetProperties
|
||||
wprops = context.scene.BIMWorkScheduleProperties
|
||||
tprops = context.scene.BIMTaskTreeProperties
|
||||
ifc_definition_id = tprops.tasks[wprops.active_task_index].ifc_definition_id
|
||||
if ifc_definition_id not in Data.products:
|
||||
Data.load(IfcStore.get_file(), ifc_definition_id)
|
||||
row = self.layout.row(align=True)
|
||||
row.prop(props, "qto_name", text="")
|
||||
op = row.operator("bim.add_qto", icon="ADD", text="")
|
||||
op.obj_type = "Task"
|
||||
|
||||
qtos = [(qto_id, Data.qtos[qto_id]) for qto_id in Data.products[ifc_definition_id]["qtos"]]
|
||||
for qto_id, qto in sorted(qtos, key=lambda v: v[1]["Name"]):
|
||||
draw_psetqto_ui(context, qto_id, qto, props, self.layout, "Task")
|
||||
for qto in TaskQtosData.data["qtos"]:
|
||||
draw_psetqto_ui(context, qto["id"], qto, props, self.layout, "Task")
|
||||
|
||||
|
||||
class BIM_PT_resource_qtos(Panel):
|
||||
@@ -287,20 +271,17 @@ class BIM_PT_resource_qtos(Panel):
|
||||
return False
|
||||
|
||||
def draw(self, context):
|
||||
if not ResourceQtosData.is_loaded:
|
||||
ResourceQtosData.load()
|
||||
|
||||
props = context.scene.ResourcePsetProperties
|
||||
rprops = context.scene.BIMResourceProperties
|
||||
rtprops = context.scene.BIMResourceTreeProperties
|
||||
ifc_definition_id = rtprops.resources[rprops.active_resource_index].ifc_definition_id
|
||||
if ifc_definition_id not in Data.products:
|
||||
Data.load(IfcStore.get_file(), ifc_definition_id)
|
||||
row = self.layout.row(align=True)
|
||||
row.prop(props, "qto_name", text="")
|
||||
op = row.operator("bim.add_qto", icon="ADD", text="")
|
||||
op.obj_type = "Resource"
|
||||
|
||||
qtos = [(qto_id, Data.qtos[qto_id]) for qto_id in Data.products[ifc_definition_id]["qtos"]]
|
||||
for qto_id, qto in sorted(qtos, key=lambda v: v[1]["Name"]):
|
||||
draw_psetqto_ui(context, qto_id, qto, props, self.layout, "Resource")
|
||||
for qto in ResourceQtosData.data["qtos"]:
|
||||
draw_psetqto_ui(context, qto["id"], qto, props, self.layout, "Resource")
|
||||
|
||||
|
||||
class BIM_PT_resource_psets(Panel):
|
||||
@@ -321,20 +302,17 @@ class BIM_PT_resource_psets(Panel):
|
||||
return False
|
||||
|
||||
def draw(self, context):
|
||||
if not ResourcePsetsData.is_loaded:
|
||||
ResourcePsetsData.load()
|
||||
|
||||
props = context.scene.ResourcePsetProperties
|
||||
rprops = context.scene.BIMResourceProperties
|
||||
rtprops = context.scene.BIMResourceTreeProperties
|
||||
ifc_definition_id = rtprops.resources[rprops.active_resource_index].ifc_definition_id
|
||||
if ifc_definition_id not in Data.products:
|
||||
Data.load(IfcStore.get_file(), ifc_definition_id)
|
||||
row = self.layout.row(align=True)
|
||||
row.prop(props, "pset_name", text="")
|
||||
op = row.operator("bim.add_pset", icon="ADD", text="")
|
||||
op.obj_type = "Resource"
|
||||
|
||||
psets = [(pset_id, Data.psets[pset_id]) for pset_id in Data.products[ifc_definition_id]["psets"]]
|
||||
for pset_id, pset in sorted(psets, key=lambda v: v[1]["Name"]):
|
||||
draw_psetqto_ui(context, pset_id, pset, props, self.layout, "Resource")
|
||||
for pset in ResourcePsetsData.data["psets"]:
|
||||
draw_psetqto_ui(context, pset["id"], pset, props, self.layout, "Resource")
|
||||
|
||||
|
||||
class BIM_PT_profile_psets(Panel):
|
||||
@@ -357,19 +335,17 @@ class BIM_PT_profile_psets(Panel):
|
||||
return False
|
||||
|
||||
def draw(self, context):
|
||||
if not ProfilePsetsData.is_loaded:
|
||||
ProfilePsetsData.load()
|
||||
|
||||
props = context.scene.ProfilePsetProperties
|
||||
pprops = context.scene.BIMProfileProperties
|
||||
ifc_definition_id = pprops.profiles[pprops.active_profile_index].ifc_definition_id
|
||||
if ifc_definition_id not in Data.products:
|
||||
Data.load(IfcStore.get_file(), ifc_definition_id)
|
||||
row = self.layout.row(align=True)
|
||||
row.prop(props, "pset_name", text="")
|
||||
op = row.operator("bim.add_pset", icon="ADD", text="")
|
||||
op.obj_type = "Profile"
|
||||
|
||||
psets = [(pset_id, Data.psets[pset_id]) for pset_id in Data.products[ifc_definition_id]["psets"]]
|
||||
for pset_id, pset in sorted(psets, key=lambda v: v[1]["Name"]):
|
||||
draw_psetqto_ui(context, pset_id, pset, props, self.layout, "Profile")
|
||||
for pset in ProfilePsetsData.data["psets"]:
|
||||
draw_psetqto_ui(context, pset["id"], pset, props, self.layout, "Profile")
|
||||
|
||||
|
||||
class BIM_PT_work_schedule_psets(Panel):
|
||||
@@ -388,15 +364,14 @@ class BIM_PT_work_schedule_psets(Panel):
|
||||
return True
|
||||
|
||||
def draw(self, context):
|
||||
if not WorkSchedulePsetsData.is_loaded:
|
||||
WorkSchedulePsetsData.load()
|
||||
|
||||
props = context.scene.WorkSchedulePsetProperties
|
||||
ifc_definition_id = context.scene.BIMWorkScheduleProperties.active_work_schedule_id
|
||||
if ifc_definition_id not in Data.products:
|
||||
Data.load(IfcStore.get_file(), ifc_definition_id)
|
||||
row = self.layout.row(align=True)
|
||||
row.prop(props, "pset_name", text="")
|
||||
op = row.operator("bim.add_pset", icon="ADD", text="")
|
||||
op.obj_type = "WorkSchedule"
|
||||
|
||||
psets = [(pset_id, Data.psets[pset_id]) for pset_id in Data.products[ifc_definition_id]["psets"]]
|
||||
for pset_id, pset in sorted(psets, key=lambda v: v[1]["Name"]):
|
||||
draw_psetqto_ui(context, pset_id, pset, props, self.layout, "WorkSchedule")
|
||||
for pset in WorkSchedulePsetsData.data["psets"]:
|
||||
draw_psetqto_ui(context, pset["id"], pset, props, self.layout, "WorkSchedule")
|
||||
|
||||
Reference in New Issue
Block a user